Skip to content
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

Closed
wants to merge 2 commits into from

Conversation

kitsonk
Copy link
Contributor

@kitsonk kitsonk commented Aug 14, 2018

Resolves #509

Migrates from runtime.ts to compiler.ts, providing a better abstraction for compiling modules within deno. It also includes a significant amount of unit test coverage for the compiler.

@kitsonk kitsonk force-pushed the ts_runtime_improve branch from 417497b to 3b36f29 Compare August 16, 2018 18:04
@kitsonk kitsonk changed the title [WIP] Improve runtime.ts [WIP] Move from runtime.ts to compiler.ts Aug 16, 2018
Copy link
Member

@ry ry left a 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;
}
}
Copy link
Member

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.

Copy link
Contributor Author

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.
Copy link
Member

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 = {
Copy link
Member

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>>();
Copy link
Member

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>>();

Copy link
Contributor Author

@kitsonk kitsonk Aug 18, 2018

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:

private static _instance: Compiler;

and

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
Copy link
Member

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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// TODO #534

outputCode: string
): void {},
codeFetch(moduleSpecifier: string, containingFile: string): ModuleInfo {
return {
Copy link
Member

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.


test(function compiler_tests_teardown() {
Object.assign(compiler, originals);
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start.

@@ -0,0 +1 @@
consol.log("hello world!");
Copy link
Member

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!");

1 consol.log("hello world!");
  ~~~~~~

$asset$/globals.d.tsILDCARD]
Copy link
Member

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.

Copy link
Contributor Author

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.

@kitsonk kitsonk force-pushed the ts_runtime_improve branch from 8a6d435 to ae6671b Compare August 17, 2018 16:50
assert(DenoCompiler.instance() != null);
});

test(function compiler_tests_setup() {
Copy link
Member

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)

Copy link
Contributor Author

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. 🤣

@kitsonk kitsonk force-pushed the ts_runtime_improve branch 2 times, most recently from c823e37 to 8f1fd8d Compare August 19, 2018 21:16
Copy link
Member

@ry ry left a 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?

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);
Copy link
Member

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 ?

Copy link
Contributor Author

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.

test(function compilerRun() {
const result = compilerInstance.run("foo/bar.ts", "/root/project");
assert(result != null);
});
Copy link
Member

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.

Copy link
Contributor Author

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.

@kitsonk
Copy link
Contributor Author

kitsonk commented Aug 20, 2018

@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).

@kitsonk kitsonk force-pushed the ts_runtime_improve branch from 158c9e0 to 7bb5ec6 Compare August 21, 2018 18:08
@kitsonk kitsonk changed the title [WIP] Move from runtime.ts to compiler.ts Move from runtime.ts to compiler.ts Aug 21, 2018
@kitsonk
Copy link
Contributor Author

kitsonk commented Aug 21, 2018

@ry, no longer WIP and ready for a final (maybe?) review

Copy link
Member

@ry ry left a 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;
Copy link
Member

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.

Copy link
Member

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.");
Copy link
Member

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.

Copy link
Member

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.");
Copy link
Member

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.

Copy link
Member

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));
Copy link
Member

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".
Copy link
Member

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.
Copy link
Member

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

Copy link
Member

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`;
Copy link
Member

@ry ry Aug 22, 2018

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

Copy link
Member

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/substituted/mocked/

Copy link
Member

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/substituted/mocked/

Copy link
Member

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;
Copy link
Member

@ry ry Aug 22, 2018

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;

Copy link
Member

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;
Copy link
Member

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?

Copy link
Member

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.

This was referenced Aug 22, 2018
@ry
Copy link
Member

ry commented Aug 22, 2018

Continuing in #564

@ry ry closed this Aug 22, 2018
@kitsonk kitsonk deleted the ts_runtime_improve branch August 2, 2022 04:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants