Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
deno
提交
2422e526
D
deno
项目概览
张重言
/
deno
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
deno
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2422e526
编写于
10月 31, 2018
作者:
K
Kitson Kelly
提交者:
Ryan Dahl
10月 30, 2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add ability to load JSON as modules (#1065)
上级
0fbee30f
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
161 addition
and
44 deletion
+161
-44
js/compiler.ts
js/compiler.ts
+82
-40
js/compiler_test.ts
js/compiler_test.ts
+68
-4
tests/020_json_modules.ts
tests/020_json_modules.ts
+3
-0
tests/020_json_modules.ts.out
tests/020_json_modules.ts.out
+1
-0
tests/subdir/config.json
tests/subdir/config.json
+6
-0
tsconfig.json
tsconfig.json
+1
-0
未找到文件。
js/compiler.ts
浏览文件 @
2422e526
...
...
@@ -79,7 +79,7 @@ export interface Ts {
*/
export
class
ModuleMetaData
implements
ts
.
IScriptSnapshot
{
public
deps
?:
ModuleFileName
[];
public
readonly
exports
=
{};
public
exports
=
{};
public
factory
?:
AmdFactory
;
public
gatheringDeps
=
false
;
public
hasRun
=
false
;
...
...
@@ -129,6 +129,15 @@ function getExtension(
}
}
/** Generate output code for a provided JSON string along with its source. */
export
function
jsonAmdTemplate
(
jsonString
:
string
,
sourceFileName
:
string
):
OutputCode
{
// tslint:disable-next-line:max-line-length
return
`define([], function() { return JSON.parse(
\`
${
jsonString
}
\`
); });\n//# sourceURL=
${
sourceFileName
}
`
;
}
/** A singleton class that combines the TypeScript Language Service host API
* with Deno specific APIs to provide an interface for compiling and running
* TypeScript and JavaScript modules.
...
...
@@ -153,11 +162,12 @@ export class DenoCompiler
>
();
// TODO ideally this are not static and can be influenced by command line
// arguments
private
readonly
_options
:
Readonly
<
ts
.
CompilerOptions
>
=
{
private
readonly
_options
:
ts
.
CompilerOptions
=
{
allowJs
:
true
,
checkJs
:
true
,
module
:
ts
.
ModuleKind
.
AMD
,
outDir
:
"
$deno$
"
,
resolveJsonModule
:
true
,
sourceMap
:
true
,
stripComments
:
true
,
target
:
ts
.
ScriptTarget
.
ESNext
...
...
@@ -198,7 +208,15 @@ export class DenoCompiler
);
assert
(
moduleMetaData
.
hasRun
===
false
,
"
Module has already been run.
"
);
// asserts not tracked by TypeScripts, so using not null operator
moduleMetaData
.
factory
!
(...
this
.
_getFactoryArguments
(
moduleMetaData
));
const
exports
=
moduleMetaData
.
factory
!
(
...
this
.
_getFactoryArguments
(
moduleMetaData
)
);
// For JSON module support and potential future features.
// TypeScript always imports `exports` and mutates it directly, but the
// AMD specification allows values to be returned from the factory.
if
(
exports
!=
null
)
{
moduleMetaData
.
exports
=
exports
;
}
moduleMetaData
.
hasRun
=
true
;
}
}
...
...
@@ -421,50 +439,74 @@ export class DenoCompiler
if
(
!
recompile
&&
moduleMetaData
.
outputCode
)
{
return
moduleMetaData
.
outputCode
;
}
const
{
fileName
,
sourceCode
,
moduleId
}
=
moduleMetaData
;
const
{
fileName
,
sourceCode
,
m
ediaType
,
m
oduleId
}
=
moduleMetaData
;
console
.
warn
(
"
Compiling
"
,
moduleId
);
const
service
=
this
.
_service
;
const
output
=
service
.
getEmitOutput
(
fileName
);
// Get the relevant diagnostics - this is 3x faster than
// `getPreEmitDiagnostics`.
const
diagnostics
=
[
...
service
.
getCompilerOptionsDiagnostics
(),
...
service
.
getSyntacticDiagnostics
(
fileName
),
...
service
.
getSemanticDiagnostics
(
fileName
)
];
if
(
diagnostics
.
length
>
0
)
{
const
errMsg
=
this
.
_ts
.
formatDiagnosticsWithColorAndContext
(
diagnostics
,
this
// Instead of using TypeScript to transpile JSON modules, we will just do
// it directly.
if
(
mediaType
===
MediaType
.
Json
)
{
moduleMetaData
.
outputCode
=
jsonAmdTemplate
(
sourceCode
,
fileName
);
}
else
{
assert
(
mediaType
===
MediaType
.
TypeScript
||
mediaType
===
MediaType
.
JavaScript
);
console
.
log
(
errMsg
);
// All TypeScript errors are terminal for deno
this
.
_os
.
exit
(
1
);
}
// TypeScript is overly opinionated that only CommonJS modules kinds can
// support JSON imports. Allegedly this was fixed in
// Microsoft/TypeScript#26825 but that doesn't seem to be working here,
// so we will trick the TypeScript compiler.
this
.
_options
.
module
=
ts
.
ModuleKind
.
AMD
;
const
output
=
service
.
getEmitOutput
(
fileName
);
this
.
_options
.
module
=
ts
.
ModuleKind
.
CommonJS
;
// Get the relevant diagnostics - this is 3x faster than
// `getPreEmitDiagnostics`.
const
diagnostics
=
[
...
service
.
getCompilerOptionsDiagnostics
(),
...
service
.
getSyntacticDiagnostics
(
fileName
),
...
service
.
getSemanticDiagnostics
(
fileName
)
];
if
(
diagnostics
.
length
>
0
)
{
const
errMsg
=
this
.
_ts
.
formatDiagnosticsWithColorAndContext
(
diagnostics
,
this
);
console
.
log
(
errMsg
);
// All TypeScript errors are terminal for deno
this
.
_os
.
exit
(
1
);
}
assert
(
!
output
.
emitSkipped
,
"
The emit was skipped for an unknown reason.
"
);
assert
(
!
output
.
emitSkipped
,
"
The emit was skipped for an unknown reason.
"
);
assert
(
output
.
outputFiles
.
length
===
2
,
`Expected 2 files to be emitted, got
${
output
.
outputFiles
.
length
}
.`
);
assert
(
output
.
outputFiles
.
length
===
2
,
`Expected 2 files to be emitted, got
${
output
.
outputFiles
.
length
}
.`
);
const
[
sourceMapFile
,
outputFile
]
=
output
.
outputFiles
;
assert
(
sourceMapFile
.
name
.
endsWith
(
"
.map
"
),
"
Expected first emitted file to be a source map
"
);
assert
(
outputFile
.
name
.
endsWith
(
"
.js
"
),
"
Expected second emitted file to be JavaScript
"
);
moduleMetaData
.
outputCode
=
`
${
outputFile
.
text
}
\n//# sourceURL=
${
fileName
}
`
;
moduleMetaData
.
sourceMap
=
sourceMapFile
.
text
;
}
const
[
sourceMapFile
,
outputFile
]
=
output
.
outputFiles
;
assert
(
sourceMapFile
.
name
.
endsWith
(
"
.map
"
),
"
Expected first emitted file to be a source map
"
);
assert
(
outputFile
.
name
.
endsWith
(
"
.js
"
),
"
Expected second emitted file to be JavaScript
"
);
const
outputCode
=
(
moduleMetaData
.
outputCode
=
`
${
outputFile
.
text
}
\n//# sourceURL=
${
fileName
}
`
);
const
sourceMap
=
(
moduleMetaData
.
sourceMap
=
sourceMapFile
.
text
);
moduleMetaData
.
scriptVersion
=
"
1
"
;
this
.
_os
.
codeCache
(
fileName
,
sourceCode
,
outputCode
,
sourceMap
);
this
.
_os
.
codeCache
(
fileName
,
sourceCode
,
moduleMetaData
.
outputCode
,
moduleMetaData
.
sourceMap
);
return
moduleMetaData
.
outputCode
;
}
...
...
js/compiler_test.ts
浏览文件 @
2422e526
...
...
@@ -6,7 +6,7 @@ import * as ts from "typescript";
// We use a silly amount of `any` in these tests...
// tslint:disable:no-any
const
{
DenoCompiler
}
=
(
deno
as
any
).
_compiler
;
const
{
DenoCompiler
,
jsonAmdTemplate
}
=
(
deno
as
any
).
_compiler
;
interface
ModuleInfo
{
moduleName
:
string
|
undefined
;
...
...
@@ -118,6 +118,11 @@ const fooBazTsOutput = `define(["require", "exports", "./bar.ts"], function (req
// This is not a valid map, just mock data
const
fooBazTsSourcemap
=
`{"version":3,"file":"baz.js","sourceRoot":"","sources":["file:///root/project/foo/baz.ts"],"names":[],"mappings":""}`
;
const
loadConfigSource
=
`import * as config from "./config.json";
console.log(config.foo.baz);
`
;
const
configJsonSource
=
`{"foo":{"bar": true,"baz": ["qat", 1]}}`
;
// tslint:enable:max-line-length
const
moduleMap
:
{
...
...
@@ -148,6 +153,14 @@ const moduleMap: {
"
console.log();
"
,
null
,
null
),
"
loadConfig.ts
"
:
mockModuleInfo
(
"
/root/project/loadConfig.ts
"
,
"
/root/project/loadConfig.ts
"
,
MediaType
.
TypeScript
,
loadConfigSource
,
null
,
null
)
},
"
/root/project/foo/baz.ts
"
:
{
...
...
@@ -166,6 +179,16 @@ const moduleMap: {
"
/root/project/modB.ts
"
:
{
"
./modA.ts
"
:
modAModuleInfo
},
"
/root/project/loadConfig.ts
"
:
{
"
./config.json
"
:
mockModuleInfo
(
"
/root/project/config.json
"
,
"
/root/project/config.json
"
,
MediaType
.
Json
,
configJsonSource
,
null
,
null
)
},
"
/moduleKinds
"
:
{
"
foo.ts
"
:
mockModuleInfo
(
"
foo
"
,
...
...
@@ -280,7 +303,7 @@ const osMock = {
return
mockModuleInfo
(
null
,
null
,
null
,
null
,
null
,
null
);
},
exit
(
code
:
number
):
never
{
throw
new
Error
(
`os.exit(
${
code
}
)`
);
throw
new
Error
(
`
Unexpected call to
os.exit(
${
code
}
)`
);
}
};
const
tsMock
=
{
...
...
@@ -289,9 +312,9 @@ const tsMock = {
},
formatDiagnosticsWithColorAndContext
(
diagnostics
:
ReadonlyArray
<
ts
.
Diagnostic
>
,
host
:
ts
.
FormatDiagnosticsHost
_
host
:
ts
.
FormatDiagnosticsHost
):
string
{
return
""
;
return
JSON
.
stringify
(
diagnostics
.
map
(({
messageText
})
=>
messageText
))
;
}
};
...
...
@@ -374,6 +397,23 @@ function teardown() {
Object
.
assign
(
compilerInstance
,
originals
);
}
test
(
function
testJsonAmdTemplate
()
{
let
deps
:
string
[];
let
factory
:
Function
;
function
define
(
d
:
string
[],
f
:
Function
)
{
deps
=
d
;
factory
=
f
;
}
const
code
=
jsonAmdTemplate
(
`{ "hello": "world", "foo": "bar" }`
);
const
result
=
eval
(
code
);
assert
(
result
==
null
);
assertEqual
(
deps
&&
deps
.
length
,
0
);
assert
(
factory
!=
null
);
const
factoryResult
=
factory
();
assertEqual
(
factoryResult
,
{
hello
:
"
world
"
,
foo
:
"
bar
"
});
});
test
(
function
compilerInstance
()
{
assert
(
DenoCompiler
!=
null
);
assert
(
DenoCompiler
.
instance
()
!=
null
);
...
...
@@ -479,6 +519,29 @@ test(function compilerRunCircularDependency() {
teardown
();
});
test
(
function
compilerLoadJsonModule
()
{
setup
();
const
factoryStack
:
string
[]
=
[];
const
configJsonDeps
:
string
[]
=
[];
const
configJsonFactory
=
()
=>
{
factoryStack
.
push
(
"
configJson
"
);
return
JSON
.
parse
(
configJsonSource
);
};
const
loadConfigDeps
=
[
"
require
"
,
"
exports
"
,
"
./config.json
"
];
const
loadConfigFactory
=
(
_require
,
_exports
,
_config
)
=>
{
factoryStack
.
push
(
"
loadConfig
"
);
assertEqual
(
_config
,
JSON
.
parse
(
configJsonSource
));
};
mockDepsStack
.
push
(
configJsonDeps
);
mockFactoryStack
.
push
(
configJsonFactory
);
mockDepsStack
.
push
(
loadConfigDeps
);
mockFactoryStack
.
push
(
loadConfigFactory
);
compilerInstance
.
run
(
"
loadConfig.ts
"
,
"
/root/project
"
);
assertEqual
(
factoryStack
,
[
"
configJson
"
,
"
loadConfig
"
]);
teardown
();
});
test
(
function
compilerResolveModule
()
{
setup
();
const
moduleMetaData
=
compilerInstance
.
resolveModule
(
...
...
@@ -544,6 +607,7 @@ test(function compilerGetCompilationSettings() {
"
checkJs
"
,
"
module
"
,
"
outDir
"
,
"
resolveJsonModule
"
,
"
sourceMap
"
,
"
stripComments
"
,
"
target
"
...
...
tests/020_json_modules.ts
0 → 100644
浏览文件 @
2422e526
import
*
as
config
from
"
./subdir/config.json
"
;
console
.
log
(
JSON
.
stringify
(
config
));
tests/020_json_modules.ts.out
0 → 100644
浏览文件 @
2422e526
{"foo":{"bar":true,"baz":["qat",1]}}
tests/subdir/config.json
0 → 100644
浏览文件 @
2422e526
{
"foo"
:
{
"bar"
:
true
,
"baz"
:
[
"qat"
,
1
]
}
}
tsconfig.json
浏览文件 @
2422e526
...
...
@@ -16,6 +16,7 @@
"preserveConstEnums"
:
true
,
"pretty"
:
true
,
"removeComments"
:
true
,
"resolveJsonModule"
:
true
,
"sourceMap"
:
true
,
"strict"
:
true
,
"target"
:
"esnext"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录