-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move from runtime.ts
to compiler.ts
#518
Conversation
417497b
to
3b36f29
Compare
runtime.ts
runtime.ts
to compiler.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working thru this. First pass comments below-
js/compiler.ts
Outdated
interface Window { | ||
define?: AmdDefine; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These "declare global" things confuse me. Is this meant to remain here or do you intend for this to move to globals.ts? If the latter please add a TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are intended to be global augmentations, and live in the module where the code that impacts the global scope lives, so they don't get disconnected. For example if you had something like jQuery which created a $
variable in the global scope, you would want to have that definition in the jQuery module.
Upon reflection, it is unnecessary in this case, unless we wanted to ensure we ensure that end user code does not attempt to touch it, in which case it should go into the global.d.ts
as a readonly property.
js/compiler.ts
Outdated
* A simple object structure for caching resolved modules and their contents. | ||
* | ||
* Named `FileModule` to clarify it is just a representation of meta data of | ||
* the module, not the actual module instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should call it ModuleMetaData?
js/compiler.ts
Outdated
* The required minimal API to allow formatting of TypeScript compiler | ||
* diagnostics. | ||
*/ | ||
const formatDiagnosticsHost = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an interface that this implements? If so it would be good to add a type here.
js/compiler.ts
Outdated
*/ | ||
export class DenoCompiler implements ts.LanguageServiceHost { | ||
private readonly _fileModuleMap = new Map<string, FileModule>(); | ||
private readonly _fileNamesMap = new Map<string, Map<string, string>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why the underscores?
_fileNamesMap isn't clear from the type definition what it does - maybe add a comment - or better do something like:
type ModuleSpecifier = string
type Foo = string
type Bar = string
private readonly _fileNamesMap = new Map<ModuleSpecifier, Map<Foo, Bar>>();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the underscore, convention... runtime.ts
uses the convention inconsistently:
Line 248 in 81b042c
private static _instance: Compiler; |
and
Line 241 in 81b042c
private service: ts.LanguageService; |
I have always prefaced private members with _
for as long as I can remember, back in pre-TS days. The only real argument is that it makes it abundantly clear, even at access, that you are accessing something that is private. It also ensures your public surface is less likely to run into odd conflicts. One potential other argument is that ES private members will have the #
sigil, so a future conversion to adopt this would be a "simple" find and replace.
The type aliases will make things clearer, I like that. 👍
js/compiler.ts
Outdated
private readonly _fileNamesMap = new Map<string, Map<string, string>>(); | ||
|
||
// TODO ideally this are not static and can be influenced by command line | ||
// arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to #51
js/compiler.ts
Outdated
|
||
readFile(path: string): string | undefined { | ||
log("readFile", path); | ||
throw Error("not implemented"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// TODO #534
js/compiler_tests.ts
Outdated
outputCode: string | ||
): void {}, | ||
codeFetch(moduleSpecifier: string, containingFile: string): ModuleInfo { | ||
return { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a counter to the mocked methods so we can check how many times they were called.
js/compiler_tests.ts
Outdated
|
||
test(function compiler_tests_teardown() { | ||
Object.assign(compiler, originals); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start.
tests/error_003.ts
Outdated
@@ -0,0 +1 @@ | |||
consol.log("hello world!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment like
// Note console.log is intentionally misspelled:
consol.log("hello world!");
tests/error_003.ts.out
Outdated
[30;47m1[0m consol.log("hello world!"); | ||
[30;47m [0m [91m~~~~~~[0m | ||
|
||
[96m$asset$/globals.d.ts[WILDCARD] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I like all the term escapes here... but it's fine for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, the matching will fail, because they are output with colours. So I don't know if it is make the matching strip/ignore them or put them in the .out
.
8a6d435
to
ae6671b
Compare
js/compiler_tests.ts
Outdated
assert(DenoCompiler.instance() != null); | ||
}); | ||
|
||
test(function compiler_tests_setup() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please continue to use camelCase for tests. Prefix all compiler test names with compiler
.
(I think unit_tests isn't doing this properly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't... it was 🐵👁🐵do on my part. 🤣
c823e37
to
8f1fd8d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
No need to test every method (there is a danger in being too prescriptive early on in a project). The main thing I want to see is how the compiler interacts with the rust system- via call counts to codeFetch/codeCache. I guess you're getting there still - since there's no test for the compile method yet?
js/compiler_tests.ts
Outdated
assert(compilerInstance.getScriptKind("foo.d.ts") === 3); | ||
assert(compilerInstance.getScriptKind("foo.js") === 1); | ||
assert(compilerInstance.getScriptKind("foo.json") === 6); | ||
assert(compilerInstance.getScriptKind("foo.txt") === 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use compiler.ScriptKind.JS
and friends ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there is an issue, for some reason, they don't exist at runtime. I had to create them in compiler.ts
, I guess I need to pull them from there too.
js/compiler_tests.ts
Outdated
test(function compilerRun() { | ||
const result = compilerInstance.run("foo/bar.ts", "/root/project"); | ||
assert(result != null); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to check how many times codeFetch and codeCache are called here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Yeah, this was just a basic "hack" at this point... going to introspect everything, and try to get full coverage on that, ensuring we get the behaviour we expect.
@ry, thanks for the feedback. I get the point about "too many tests" but getting full coverage on the TypeScript APIs seemed to be logical for me, as that is obviously a fixed API on the TypeScript side, and somewhat immutable (and also really important for accepting upgrades of TypeScript). |
158c9e0
to
7bb5ec6
Compare
runtime.ts
to compiler.ts
runtime.ts
to compiler.ts
@ry, no longer WIP and ready for a final (maybe?) review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I have a few comments in the tests.
It seems like this would be best done in a couple commits rather than squashing it all into one? Can you organize/squash the commits into something we can land without further modification?
// equal to `deno foo/bar.ts` | ||
const codeFetchLength = codeFetchStack.length; | ||
const codeCacheLength = codeCacheStack.length; | ||
const globalEvalLength = globalEvalStack.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work on the tests. Why not just assert that these are empty here, rather than recording the length? Since you're always popping off everything, they should be empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
]) { | ||
assert(key in result, `Expected "${key}" in compiler options.`); | ||
} | ||
assertEqual(Object.keys(result).length, 7, "Expected only 7 keys."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assert seems excessively specific to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
); | ||
const result = compilerInstance.getScriptSnapshot(moduleMetaData.fileName); | ||
assert(result != null, "Expected snapshot to be defined."); | ||
assertEqual(result.getLength(), 87, "Expected a length of 87."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using 87, use fooBarTsSource.length. No need for excessively verbose assert messages either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
"Expected .getText() to equal 'import'" | ||
); | ||
assertEqual(result.getChangeRange(result), undefined); | ||
assert(!("dispose" in result)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why "dispose" ? Maybe add a comment?
@@ -0,0 +1,12 @@ | |||
Error: Cannot resolve module "bad-module.ts" from "[WILDCARD]error_004_missing_module.ts". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good! thanks!
@@ -0,0 +1,466 @@ | |||
// Copyright 2018 the Deno authors. All rights reserved. MIT license. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename this file to js/compiler_test.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
exports.foo = "bar"; | ||
}); | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZmlsZTovLy9yb290L3Byb2plY3QvZm9vL2Jhci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7SUFDQSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ1QsUUFBQSxHQUFHLEdBQUcsS0FBSyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY29tcGlsZXIgZnJvbSBcImNvbXBpbGVyXCI7XG5jb25zb2xlLmxvZyhjb21waWxlcik7XG5leHBvcnQgY29uc3QgZm9vID0gXCJiYXJcIjtcbiJdfQ== | ||
//# sourceURL=/root/project/foo/bar.ts`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, it would be nice to not have the source map stuff in here. Maybe that needs to wait until we disable the inlineSourceMaps - if so please add TODO
// TODO Remove source map strings from fooBarTsOutput.
// https://github.com/denoland/deno/issues/23
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
/** | ||
* Abstraction of the APIs required from the `os` module so they can be | ||
* easily substituted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/substituted/mocked/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
/** | ||
* Abstraction of the APIs required from the `typescript` module so they can | ||
* be easily substituted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/substituted/mocked/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
type ContainingFile = string; | ||
type ModuleFileName = string; | ||
type ModuleSpecifier = string; | ||
type OutputCode = string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add some comments here:
// The location that a module is being loaded from. This could be a directory, like ".", or it could be a module specifier like "http://gist.github.com/somefile.ts"
type ContainingFile = string;
// The internal local filename of a compiled module. It will often be something like "/home/ry/.deno/gen/f7b4605dfbc4d3bb356e98fda6ceb1481e4a8df5.js"
type ModuleFileName = string;
// The external name of a module - could be a URL or could be a relative path. Examples "http://gist.github.com/somefile.ts" or "./somefile.ts"
type ModuleSpecifier = string;
// The compiled source code which is cached in .deno/gen/
type OutputCode = string;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return DenoCompiler._builtins[dep]; | ||
} else { | ||
const depModuleMetaData = this.run(dep, moduleMetaData.fileName); | ||
return depModuleMetaData.exports; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is duplicated just above in the try-catch? I'm having trouble following the logic here. Is this a programming error? If not, why are we mapping the deps twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not done. @kitsonk please take a look at this when you get a chance.
Continuing in #564 |
Resolves #509
Migrates from
runtime.ts
tocompiler.ts
, providing a better abstraction for compiling modules within deno. It also includes a significant amount of unit test coverage for the compiler.