Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
2a01db15
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2a01db15
编写于
10月 02, 2018
作者:
R
Rob Lourens
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix #59801 - use shared extension tsconfig for search-rg
上级
92a9a072
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
97 addition
and
101 deletion
+97
-101
extensions/search-rg/src/extension.ts
extensions/search-rg/src/extension.ts
+19
-14
extensions/search-rg/src/ripgrepFileSearch.ts
extensions/search-rg/src/ripgrepFileSearch.ts
+24
-25
extensions/search-rg/src/ripgrepTextSearch.ts
extensions/search-rg/src/ripgrepTextSearch.ts
+41
-47
extensions/search-rg/src/test/searchrg.test.ts
extensions/search-rg/src/test/searchrg.test.ts
+9
-8
extensions/search-rg/src/utils.ts
extensions/search-rg/src/utils.ts
+2
-0
extensions/search-rg/tsconfig.json
extensions/search-rg/tsconfig.json
+2
-7
未找到文件。
extensions/search-rg/src/extension.ts
浏览文件 @
2a01db15
...
...
@@ -17,42 +17,47 @@ export function activate(): void {
}
}
type
SearchEngine
=
RipgrepFileSearchEngine
|
RipgrepTextSearchEngine
;
class
RipgrepSearchProvider
implements
vscode
.
FileIndexProvider
,
vscode
.
TextSearchProvider
{
private
inProgress
:
Set
<
SearchEngin
e
>
=
new
Set
();
private
inProgress
:
Set
<
vscode
.
CancellationTokenSourc
e
>
=
new
Set
();
constructor
(
private
outputChannel
:
vscode
.
OutputChannel
)
{
process
.
once
(
'
exit
'
,
()
=>
this
.
dispose
());
}
provideTextSearchResults
(
query
:
vscode
.
TextSearchQuery
,
options
:
vscode
.
TextSearchOptions
,
progress
:
vscode
.
Progress
<
vscode
.
TextSearchResult
>
,
token
:
vscode
.
CancellationToken
):
Thenabl
e
<
vscode
.
TextSearchComplete
>
{
provideTextSearchResults
(
query
:
vscode
.
TextSearchQuery
,
options
:
vscode
.
TextSearchOptions
,
progress
:
vscode
.
Progress
<
vscode
.
TextSearchResult
>
,
token
:
vscode
.
CancellationToken
):
Promis
e
<
vscode
.
TextSearchComplete
>
{
const
engine
=
new
RipgrepTextSearchEngine
(
this
.
outputChannel
);
return
this
.
with
Engine
(
engine
,
()
=>
engine
.
provideTextSearchResults
(
query
,
options
,
progress
,
token
));
return
this
.
with
Token
(
token
,
token
=>
engine
.
provideTextSearchResults
(
query
,
options
,
progress
,
token
));
}
provideFileIndex
(
options
:
vscode
.
FileSearchOptions
,
token
:
vscode
.
CancellationToken
):
Thenable
<
vscode
.
Uri
[]
>
{
const
engine
=
new
RipgrepFileSearchEngine
(
this
.
outputChannel
);
const
results
:
vscode
.
Uri
[]
=
[];
const
onResult
=
relativePathMatch
=>
{
const
onResult
=
(
relativePathMatch
:
string
)
=>
{
results
.
push
(
vscode
.
Uri
.
file
(
options
.
folder
.
fsPath
+
'
/
'
+
relativePathMatch
));
};
return
this
.
with
Engine
(
engine
,
()
=>
engine
.
provideFileSearchResults
(
options
,
{
report
:
onResult
},
token
))
return
this
.
with
Token
(
token
,
token
=>
engine
.
provideFileSearchResults
(
options
,
{
report
:
onResult
},
token
))
.
then
(()
=>
results
);
}
private
withEngine
<
T
>
(
engine
:
SearchEngine
,
fn
:
()
=>
Thenable
<
T
>
):
Thenable
<
T
>
{
this
.
inProgress
.
add
(
engine
);
return
fn
().
then
(
result
=>
{
this
.
inProgress
.
delete
(
engine
);
private
async
withToken
<
T
>
(
token
:
vscode
.
CancellationToken
,
fn
:
(
token
:
vscode
.
CancellationToken
)
=>
Thenable
<
T
>
):
Promise
<
T
>
{
const
merged
=
mergedTokenSource
(
token
);
this
.
inProgress
.
add
(
merged
);
const
result
=
await
fn
(
merged
.
token
);
this
.
inProgress
.
delete
(
merged
);
return
result
;
});
return
result
;
}
private
dispose
()
{
this
.
inProgress
.
forEach
(
engine
=>
engine
.
cancel
());
}
}
\ No newline at end of file
}
function
mergedTokenSource
(
token
:
vscode
.
CancellationToken
):
vscode
.
CancellationTokenSource
{
const
tokenSource
=
new
vscode
.
CancellationTokenSource
();
token
.
onCancellationRequested
(()
=>
tokenSource
.
cancel
());
return
tokenSource
;
}
extensions/search-rg/src/ripgrepFileSearch.ts
浏览文件 @
2a01db15
...
...
@@ -10,7 +10,7 @@ import * as vscode from 'vscode';
import
{
normalizeNFC
,
normalizeNFD
}
from
'
./normalization
'
;
import
{
rgPath
}
from
'
./ripgrep
'
;
import
{
rgErrorMsgForDisplay
}
from
'
./ripgrepTextSearch
'
;
import
{
anchorGlob
}
from
'
./utils
'
;
import
{
anchorGlob
,
Maybe
}
from
'
./utils
'
;
const
isMac
=
process
.
platform
===
'
darwin
'
;
...
...
@@ -18,18 +18,8 @@ const isMac = process.platform === 'darwin';
const
rgDiskPath
=
rgPath
.
replace
(
/
\b
node_modules
\.
asar
\b
/
,
'
node_modules.asar.unpacked
'
);
export
class
RipgrepFileSearchEngine
{
private
rgProc
:
cp
.
ChildProcess
;
private
isDone
:
boolean
;
constructor
(
private
outputChannel
:
vscode
.
OutputChannel
)
{
}
cancel
()
{
this
.
isDone
=
true
;
if
(
this
.
rgProc
)
{
this
.
rgProc
.
kill
();
}
}
provideFileSearchResults
(
options
:
vscode
.
FileSearchOptions
,
progress
:
vscode
.
Progress
<
string
>
,
token
:
vscode
.
CancellationToken
):
Thenable
<
void
>
{
this
.
outputChannel
.
appendLine
(
`provideFileSearchResults
${
JSON
.
stringify
({
...
options
,
...
...
@@ -39,7 +29,16 @@ export class RipgrepFileSearchEngine {
})}
`
);
return
new
Promise
((
resolve
,
reject
)
=>
{
token
.
onCancellationRequested
(()
=>
this
.
cancel
());
let
isDone
=
false
;
const
cancel
=
()
=>
{
isDone
=
true
;
if
(
rgProc
)
{
rgProc
.
kill
();
}
};
token
.
onCancellationRequested
(()
=>
cancel
());
const
rgArgs
=
getRgArgs
(
options
);
...
...
@@ -50,22 +49,22 @@ export class RipgrepFileSearchEngine {
.
join
(
'
'
);
this
.
outputChannel
.
appendLine
(
`rg
${
escapedArgs
}
\n - cwd:
${
cwd
}
\n`
);
this
.
rgProc
=
cp
.
spawn
(
rgDiskPath
,
rgArgs
,
{
cwd
});
let
rgProc
:
Maybe
<
cp
.
ChildProcess
>
=
cp
.
spawn
(
rgDiskPath
,
rgArgs
,
{
cwd
});
this
.
rgProc
.
on
(
'
error
'
,
e
=>
{
rgProc
.
on
(
'
error
'
,
e
=>
{
console
.
log
(
e
);
reject
(
e
);
});
let
leftover
=
''
;
this
.
collectStdout
(
this
.
rgProc
,
(
err
,
stdout
,
last
)
=>
{
this
.
collectStdout
(
rgProc
,
(
err
,
stdout
,
last
)
=>
{
if
(
err
)
{
reject
(
err
);
return
;
}
// Mac: uses NFD unicode form on disk, but we want NFC
const
normalized
=
leftover
+
(
isMac
?
normalizeNFC
(
stdout
)
:
stdout
);
const
normalized
=
leftover
+
(
isMac
?
normalizeNFC
(
stdout
||
''
)
:
stdout
);
const
relativeFiles
=
normalized
.
split
(
'
\n
'
);
if
(
last
)
{
...
...
@@ -75,7 +74,7 @@ export class RipgrepFileSearchEngine {
relativeFiles
.
pop
();
}
}
else
{
leftover
=
relativeFiles
.
pop
();
leftover
=
<
string
>
relativeFiles
.
pop
();
}
if
(
relativeFiles
.
length
&&
relativeFiles
[
0
].
indexOf
(
'
\n
'
)
!==
-
1
)
{
...
...
@@ -88,11 +87,11 @@ export class RipgrepFileSearchEngine {
});
if
(
last
)
{
if
(
this
.
isDone
)
{
if
(
isDone
)
{
resolve
();
}
else
{
// Trigger last result
this
.
rgProc
=
null
;
rgProc
=
null
;
if
(
err
)
{
reject
(
err
);
}
else
{
...
...
@@ -104,8 +103,8 @@ export class RipgrepFileSearchEngine {
});
}
private
collectStdout
(
cmd
:
cp
.
ChildProcess
,
cb
:
(
err
:
Error
,
stdout
?:
string
,
last
?:
boolean
)
=>
void
):
void
{
let
onData
=
(
err
:
Error
,
stdout
?:
string
,
last
?:
boolean
)
=>
{
private
collectStdout
(
cmd
:
cp
.
ChildProcess
,
cb
:
(
err
?
:
Error
,
stdout
?:
string
,
last
?:
boolean
)
=>
void
):
void
{
let
onData
=
(
err
?
:
Error
,
stdout
?:
string
,
last
?:
boolean
)
=>
{
if
(
err
||
last
)
{
onData
=
()
=>
{
};
}
...
...
@@ -136,19 +135,19 @@ export class RipgrepFileSearchEngine {
cmd
.
on
(
'
close
'
,
(
code
:
number
)
=>
{
// ripgrep returns code=1 when no results are found
let
stderrText
,
displayMsg
:
string
;
let
stderrText
,
displayMsg
:
Maybe
<
string
>
;
if
(
!
gotData
&&
(
stderrText
=
this
.
decodeData
(
stderr
))
&&
(
displayMsg
=
rgErrorMsgForDisplay
(
stderrText
)))
{
onData
(
new
Error
(
`command failed with error code
${
code
}
:
${
displayMsg
}
`
));
}
else
{
onData
(
null
,
''
,
true
);
onData
(
undefined
,
''
,
true
);
}
});
}
private
forwardData
(
stream
:
Readable
,
cb
:
(
err
:
Error
,
stdout
?:
string
)
=>
void
):
NodeStringDecoder
{
private
forwardData
(
stream
:
Readable
,
cb
:
(
err
?
:
Error
,
stdout
?:
string
)
=>
void
):
NodeStringDecoder
{
const
decoder
=
new
StringDecoder
();
stream
.
on
(
'
data
'
,
(
data
:
Buffer
)
=>
{
cb
(
null
,
decoder
.
write
(
data
));
cb
(
undefined
,
decoder
.
write
(
data
));
});
return
decoder
;
}
...
...
extensions/search-rg/src/ripgrepTextSearch.ts
浏览文件 @
2a01db15
...
...
@@ -9,31 +9,14 @@ import * as path from 'path';
import
{
NodeStringDecoder
,
StringDecoder
}
from
'
string_decoder
'
;
import
*
as
vscode
from
'
vscode
'
;
import
{
rgPath
}
from
'
./ripgrep
'
;
import
{
anchorGlob
,
createTextSearchResult
}
from
'
./utils
'
;
import
{
anchorGlob
,
createTextSearchResult
,
Maybe
}
from
'
./utils
'
;
// If vscode-ripgrep is in an .asar file, then the binary is unpacked.
const
rgDiskPath
=
rgPath
.
replace
(
/
\b
node_modules
\.
asar
\b
/
,
'
node_modules.asar.unpacked
'
);
export
class
RipgrepTextSearchEngine
{
private
isDone
=
false
;
private
rgProc
:
cp
.
ChildProcess
;
private
ripgrepParser
:
RipgrepParser
;
constructor
(
private
outputChannel
:
vscode
.
OutputChannel
)
{
}
cancel
()
{
this
.
isDone
=
true
;
if
(
this
.
rgProc
)
{
this
.
rgProc
.
kill
();
}
if
(
this
.
ripgrepParser
)
{
this
.
ripgrepParser
.
cancel
();
}
}
provideTextSearchResults
(
query
:
vscode
.
TextSearchQuery
,
options
:
vscode
.
TextSearchOptions
,
progress
:
vscode
.
Progress
<
vscode
.
TextSearchResult
>
,
token
:
vscode
.
CancellationToken
):
Thenable
<
vscode
.
TextSearchComplete
>
{
this
.
outputChannel
.
appendLine
(
`provideTextSearchResults
${
query
.
pattern
}
,
${
JSON
.
stringify
({
...
options
,
...
...
@@ -43,7 +26,7 @@ export class RipgrepTextSearchEngine {
})}
`
);
return
new
Promise
((
resolve
,
reject
)
=>
{
token
.
onCancellationRequested
(()
=>
this
.
cancel
());
token
.
onCancellationRequested
(()
=>
cancel
());
const
rgArgs
=
getRgArgs
(
query
,
options
);
...
...
@@ -54,51 +37,64 @@ export class RipgrepTextSearchEngine {
.
join
(
'
'
);
this
.
outputChannel
.
appendLine
(
`rg
${
escapedArgs
}
\n - cwd:
${
cwd
}
`
);
this
.
rgProc
=
cp
.
spawn
(
rgDiskPath
,
rgArgs
,
{
cwd
});
this
.
rgProc
.
on
(
'
error
'
,
e
=>
{
let
rgProc
:
Maybe
<
cp
.
ChildProcess
>
=
cp
.
spawn
(
rgDiskPath
,
rgArgs
,
{
cwd
});
rgProc
.
on
(
'
error
'
,
e
=>
{
console
.
error
(
e
);
this
.
outputChannel
.
append
(
'
Error:
'
+
(
e
&&
e
.
message
));
reject
(
e
);
});
let
gotResult
=
false
;
this
.
ripgrepParser
=
new
RipgrepParser
(
options
.
maxResults
,
cwd
,
options
.
previewOptions
);
this
.
ripgrepParser
.
on
(
'
result
'
,
(
match
:
vscode
.
TextSearchResult
)
=>
{
const
ripgrepParser
=
new
RipgrepParser
(
options
.
maxResults
,
cwd
,
options
.
previewOptions
);
ripgrepParser
.
on
(
'
result
'
,
(
match
:
vscode
.
TextSearchResult
)
=>
{
gotResult
=
true
;
progress
.
report
(
match
);
});
let
isDone
=
false
;
const
cancel
=
()
=>
{
isDone
=
true
;
if
(
rgProc
)
{
rgProc
.
kill
();
}
if
(
ripgrepParser
)
{
ripgrepParser
.
cancel
();
}
};
let
limitHit
=
false
;
this
.
ripgrepParser
.
on
(
'
hitLimit
'
,
()
=>
{
ripgrepParser
.
on
(
'
hitLimit
'
,
()
=>
{
limitHit
=
true
;
this
.
cancel
();
cancel
();
});
this
.
rgProc
.
stdout
.
on
(
'
data
'
,
data
=>
{
this
.
ripgrepParser
.
handleData
(
data
);
rgProc
.
stdout
.
on
(
'
data
'
,
data
=>
{
ripgrepParser
.
handleData
(
data
);
});
let
gotData
=
false
;
this
.
rgProc
.
stdout
.
once
(
'
data
'
,
()
=>
gotData
=
true
);
rgProc
.
stdout
.
once
(
'
data
'
,
()
=>
gotData
=
true
);
let
stderr
=
''
;
this
.
rgProc
.
stderr
.
on
(
'
data
'
,
data
=>
{
rgProc
.
stderr
.
on
(
'
data
'
,
data
=>
{
const
message
=
data
.
toString
();
this
.
outputChannel
.
append
(
message
);
stderr
+=
message
;
});
this
.
rgProc
.
on
(
'
close
'
,
code
=>
{
rgProc
.
on
(
'
close
'
,
()
=>
{
this
.
outputChannel
.
appendLine
(
gotData
?
'
Got data from stdout
'
:
'
No data from stdout
'
);
this
.
outputChannel
.
appendLine
(
gotResult
?
'
Got result from parser
'
:
'
No result from parser
'
);
this
.
outputChannel
.
appendLine
(
''
);
if
(
this
.
isDone
)
{
if
(
isDone
)
{
resolve
({
limitHit
});
}
else
{
// Trigger last result
this
.
ripgrepParser
.
flush
();
this
.
rgProc
=
null
;
let
displayMsg
:
string
;
ripgrepParser
.
flush
();
rgProc
=
null
;
let
displayMsg
:
Maybe
<
string
>
;
if
(
stderr
&&
!
gotData
&&
(
displayMsg
=
rgErrorMsgForDisplay
(
stderr
)))
{
reject
(
new
Error
(
displayMsg
));
}
else
{
...
...
@@ -115,7 +111,7 @@ export class RipgrepTextSearchEngine {
* Ripgrep produces stderr output which is not from a fatal error, and we only want the search to be
* "failed" when a fatal error was produced.
*/
export
function
rgErrorMsgForDisplay
(
msg
:
string
):
string
|
undefined
{
export
function
rgErrorMsgForDisplay
(
msg
:
string
):
Maybe
<
string
>
{
const
firstLine
=
msg
.
split
(
'
\n
'
)[
0
].
trim
();
if
(
firstLine
.
startsWith
(
'
Error parsing regex
'
))
{
...
...
@@ -150,9 +146,9 @@ export class RipgrepParser extends EventEmitter {
public
static
readonly
MATCH_START_MARKER
=
'
\
u001b[0m
\
u001b[31m
'
;
public
static
readonly
MATCH_END_MARKER
=
'
\
u001b[0m
'
;
private
currentFile
:
string
;
private
remainder
:
string
;
private
isDone
:
boolean
;
private
currentFile
=
''
;
private
remainder
=
''
;
private
isDone
=
false
;
private
stringDecoder
:
NodeStringDecoder
;
private
numResults
=
0
;
...
...
@@ -182,7 +178,7 @@ export class RipgrepParser extends EventEmitter {
decodedData
;
const
dataLines
:
string
[]
=
dataStr
.
split
(
/
\r\n
|
\n
/
);
this
.
remainder
=
dataLines
[
dataLines
.
length
-
1
]
?
dataLines
.
pop
()
:
null
;
this
.
remainder
=
dataLines
[
dataLines
.
length
-
1
]
?
<
string
>
dataLines
.
pop
()
:
''
;
for
(
let
l
=
0
;
l
<
dataLines
.
length
;
l
++
)
{
const
outputLine
=
dataLines
[
l
].
trim
();
...
...
@@ -190,7 +186,7 @@ export class RipgrepParser extends EventEmitter {
break
;
}
let
r
:
RegExpMatchArray
;
let
r
:
Maybe
<
RegExpMatchArray
>
;
if
(
r
=
outputLine
.
match
(
RipgrepParser
.
RESULT_REGEX
))
{
const
lineNum
=
parseInt
(
r
[
1
])
-
1
;
let
matchText
=
r
[
2
];
...
...
@@ -202,7 +198,7 @@ export class RipgrepParser extends EventEmitter {
}
// Line is a result - add to collected results for the current file path
this
.
handleMatchLine
(
outputLine
,
lineNum
,
matchText
);
this
.
handleMatchLine
(
lineNum
,
matchText
);
}
else
if
(
r
=
outputLine
.
match
(
RipgrepParser
.
FILE_REGEX
))
{
this
.
currentFile
=
r
[
1
];
}
else
{
...
...
@@ -211,7 +207,7 @@ export class RipgrepParser extends EventEmitter {
}
}
private
handleMatchLine
(
outputLine
:
string
,
lineNum
:
number
,
lineText
:
string
):
void
{
private
handleMatchLine
(
lineNum
:
number
,
lineText
:
string
):
void
{
if
(
lineNum
===
0
)
{
lineText
=
stripUTF8BOM
(
lineText
);
}
...
...
@@ -332,9 +328,9 @@ function getRgArgs(query: vscode.TextSearchQuery, options: vscode.TextSearchOpti
query
.
pattern
=
'
\\
-
\\
-
'
;
}
let
searchPatternAfterDoubleDashes
:
string
;
let
searchPatternAfterDoubleDashes
:
Maybe
<
string
>
;
if
(
query
.
isWordMatch
)
{
const
regexp
=
createRegExp
(
query
.
pattern
,
query
.
isRegExp
,
{
wholeWord
:
query
.
isWordMatch
});
const
regexp
=
createRegExp
(
query
.
pattern
,
!!
query
.
isRegExp
,
{
wholeWord
:
query
.
isWordMatch
});
const
regexpStr
=
regexp
.
source
.
replace
(
/
\\\/
/g
,
'
/
'
);
// RegExp.source arbitrarily returns escaped slashes. Search and destroy.
args
.
push
(
'
--regexp
'
,
regexpStr
);
}
else
if
(
query
.
isRegExp
)
{
...
...
@@ -407,10 +403,8 @@ function escapeRegExpCharacters(value: string): string {
const
UTF8_BOM
=
65279
;
const
UTF8_BOM_CHARACTER
=
String
.
fromCharCode
(
UTF8_BOM
);
function
startsWithUTF8BOM
(
str
:
string
):
boolean
{
return
(
str
&&
str
.
length
>
0
&&
str
.
charCodeAt
(
0
)
===
UTF8_BOM
);
return
!!
(
str
&&
str
.
length
>
0
&&
str
.
charCodeAt
(
0
)
===
UTF8_BOM
);
}
function
stripUTF8BOM
(
str
:
string
):
string
{
...
...
extensions/search-rg/src/test/searchrg.test.ts
浏览文件 @
2a01db15
...
...
@@ -4,16 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import
'
mocha
'
;
import
*
as
assert
from
'
assert
'
;
import
*
as
vscode
from
'
vscode
'
;
import
*
as
path
from
'
path
'
;
import
{
createTextSearchResult
}
from
'
../utils
'
;
// TODO./
// import * as assert from 'assert';
// import * as vscode from 'vscode';
// import * as path from 'path';
// import { createTextSearchResult } from '../utils';
function
createOneLineRange
(
lineNumber
:
number
,
startCol
:
number
,
endCol
:
number
):
vscode
.
Range
{
return
new
vscode
.
Range
(
lineNumber
,
startCol
,
lineNumber
,
endCol
);
}
//
function createOneLineRange(lineNumber: number, startCol: number, endCol: number): vscode.Range {
//
return new vscode.Range(lineNumber, startCol, lineNumber, endCol);
//
}
const
uri
=
vscode
.
Uri
.
file
(
'
/foo/bar
'
);
//
const uri = vscode.Uri.file('/foo/bar');
suite
(
'
search-rg
'
,
()
=>
{
...
...
extensions/search-rg/src/utils.ts
浏览文件 @
2a01db15
...
...
@@ -6,6 +6,8 @@
import
*
as
path
from
'
path
'
;
import
*
as
vscode
from
'
vscode
'
;
export
type
Maybe
<
T
>
=
T
|
null
|
undefined
;
export
function
fixDriveC
(
_path
:
string
):
string
{
const
root
=
path
.
parse
(
_path
).
root
;
return
root
.
toLowerCase
()
===
'
c:/
'
?
...
...
extensions/search-rg/tsconfig.json
浏览文件 @
2a01db15
{
"extends"
:
"../shared.tsconfig.json"
,
"compilerOptions"
:
{
"target"
:
"es5"
,
"module"
:
"commonjs"
,
"lib"
:
[
"es6"
,
"es2015.promise"
],
"outDir"
:
"./out"
,
"experimentalDecorators"
:
true
"experimentalDecorators"
:
true
,
},
"include"
:
[
"src/**/*"
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录