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

Resolve the modue names with "modulename.json" to json files when doing node module resolution #22167

Merged
merged 25 commits into from May 4, 2018

Conversation

Projects
None yet
5 participants
@sheetalkamat
Copy link
Member

commented Feb 24, 2018

Fixes #7071

@sheetalkamat

This comment has been minimized.

Copy link
Member Author

commented Feb 26, 2018

@mhegazy c154b81 is the issue that was causing emptyArray to modify and my tests to fail.

@calebboyd

This comment has been minimized.

Copy link

commented Mar 8, 2018

This is great! Any chance it will make it into 2.8?

@sheetalkamat sheetalkamat force-pushed the requireJson branch from 256ef2a to 2071466 Mar 8, 2018

@sheetalkamat

This comment has been minimized.

Copy link
Member Author

commented Mar 10, 2018

@mhegazy can you please take a look so we can get this in. Thank you.

@sandersn
Copy link
Member

left a comment

The binder and checker code look good. I'll have to look at the rest later.

One big question: why doesn't the flag default to true, at least for Javascript files? In fact, why is there a flag at all?

If there is a difference between JS and TS, then there should be a JS-specific test.

@sheetalkamat

This comment has been minimized.

Copy link
Member Author

commented Apr 30, 2018

One big question: why doesn't the flag default to true, at least for Javascript files? In fact, why is there a flag at all?

Because we dont want to pull in big json files. Its almost too late most of the time when the json could result into big memory. It could be too many options or too long a string. it was discussed in design note to put this under the flag instead.
Having people to consciously opt into this would imply the user understands the cost.

@sandersn
Copy link
Member

left a comment

I think it's ready to go, although I'd still like to know whether JsonSourceFile.statements could have type NodeArray<ExpressionStatement>.

After our in-person discussion, I think it's ok to start with a flag required for both JS and TS files, and perhaps revisit this if there's enough demand for better types in config-free scenarios.

else {
const statement = createNode(SyntaxKind.ExpressionStatement) as JsonObjectExpressionStatement;
switch (token()) {
case SyntaxKind.OpenBracketToken:

This comment has been minimized.

Copy link
@sandersn

sandersn Apr 30, 2018

Member

Oh, ok. I didn't realise that this approach gives better error recovery.

@@ -1983,7 +1983,7 @@ namespace ts {
}

This comment has been minimized.

Copy link
@sandersn

sandersn Apr 30, 2018

Member

in the title for program.ts, it says that program.ts has 14 lines changed and also changed permissions from 100755 to 100644. I think that is safer since I don't think we can run program.ts from the command line, but I wasn't sure what prompted the change.

@@ -1671,7 +1675,9 @@ namespace ts {

function emitExpressionStatement(node: ExpressionStatement) {
emitExpression(node.expression);
writeSemicolon();
if (!isJsonSourceFile(currentSourceFile)) {

This comment has been minimized.

Copy link
@mhegazy

mhegazy Apr 30, 2018

why would this be called in the first place?

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 1, 2018

Author Member

https://github.com/Microsoft/TypeScript/pull/22167/files#diff-9e36f50e46928676c6142f634cb7cd1bR18 when the output is copied into outDir just like any other js file ?

This comment has been minimized.

Copy link
@mhegazy
@@ -4685,6 +4685,11 @@ namespace ts {
return links.type = anyType;
}
// Handle export default expressions
if (declaration.kind === SyntaxKind.SourceFile) {

This comment has been minimized.

Copy link
@mhegazy

mhegazy Apr 30, 2018

isSourceFile(declaration) and save the cast few lines in

@@ -505,6 +505,7 @@ namespace ts {
JSDoc = 1 << 21, // If node was parsed inside jsdoc
/* @internal */ Ambient = 1 << 22, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
/* @internal */ InWithStatement = 1 << 23, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 24, // If node was parsed in a Json

This comment has been minimized.

Copy link
@mhegazy

mhegazy Apr 30, 2018

i would just call it JSON

This comment has been minimized.

Copy link
@mhegazy

mhegazy Apr 30, 2018

or Json for consistency

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat Apr 30, 2018

Author Member

https://github.com/Microsoft/TypeScript/pull/22167/files#diff-4b8bd1eea29904f1be39cd864e1a45c0R489 has this as JavaScriptFile isnt it more consitent to use JsonFile ?

This comment has been minimized.

Copy link
@mhegazy
@mhegazy

This comment has been minimized.

Copy link

commented Apr 30, 2018

@andy-ms can you please review this change.

@mhegazy mhegazy requested a review from andy-ms Apr 30, 2018

@mhegazy

This comment has been minimized.

Copy link

commented Apr 30, 2018

@sheetalkamat, a couple of comments:

  1. I think we need a size limit as well. either in the module resolver or in the program. in .js files these can be big, and we do not want to kill the server if one (or few) were loaded.
  2. we should enable it for js projects by default, in other words set --resolveJsonModules to true in getDefaultCompilerOptions in a jsconfig.json. and also in the server. we can do that in a separate PR if you want.
@sheetalkamat

This comment has been minimized.

Copy link
Member Author

commented May 3, 2018

chatted with @mhegazy offline and the making --resolveJsonModules default to true for javascript files and limiting the size of files need to be handled separately since its going to involve effort thats generic even for javascript projects in general.

@sheetalkamat

This comment has been minimized.

Copy link
Member Author

commented May 3, 2018

Ping @andy-ms @mhegazy for final review before merge

@@ -4718,6 +4718,11 @@ namespace ts {
return links.type = anyType;
}
// Handle export default expressions
if (isSourceFile(declaration)) {
Debug.assert(isJsonSourceFile(declaration));
const jsonSourceFile = <JsonSourceFile>declaration;

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

cast(declaration, isJsonSourceFile) helps avoid the type assertion

@@ -3543,6 +3547,11 @@
"code": 6196,
"reportsUnnecessary": true
},
"Resolve module name imported with '.json' extension to the json source file.": {

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

I think this message could be improved -- not obvious what the alternative is. "Type-check imported '.json' files" might be a better explanation. The same for the error message -- it's not the module resolution that users will care about, but the fact that we typecheck the contents of the file.

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 4, 2018

Author Member

But that's not what it means though.. We wont even look for .json files if the flag is on. So its not just typechecking but picking up the modules?

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

How about "Include '.json' files in the program"?
The reason is that module resolution seems like more of an internal issue that most users won't care about. But they will care if their '.json' files are getting compiled or not.

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 4, 2018

Author Member

somehow module needs to be part of the msg since aren't just including any json file?
Include modules imported with '.json' extension ?

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Assuming that .json imports would have failed before, that's a better description.


function convertObjectLiteralExpressionToJson(
node: ObjectLiteralExpression,
knownOptions: Map<CommandLineOption> | undefined,
extraKeyDiagnosticMessage: DiagnosticMessage | undefined,
parentOption: string | undefined
): any {
const result: any = {};
const result: any = returnValue ? {} : undefined;

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Could you add a comment on the function header?

@@ -898,6 +903,11 @@ namespace ts {
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
*/
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
if (extensions === Extensions.Json) {

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Seems like this could be handled along with the bottom case if (hasJavaScriptFileExtension)?

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 4, 2018

Author Member

That just makes too many checks of extension !== Extensions.Json since we dont want to resolve "module" to module.json but only "module.json"

@@ -2426,6 +2433,7 @@ namespace ts {
switch (extension) {
case Extension.Ts:
case Extension.Dts:
case Extension.Json:
// These are always allowed.

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Assuming we would only ever get a .json module if the option was set? Maybe could put that in the comment.

}
}

export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile, propKey: string, elementValue: string): StringLiteral {

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Nit: StringLiteral | undefined


export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile, propKey: string, elementValue: string): StringLiteral {
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(tsConfigSourceFile);
if (jsonObjectLiteral) {

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member
return jsonObjectLiteral && firstDefined(getPropertyAssignment(jsonObjectLiteral, propKey), property =>
    isArrayLiteralExpression(property.initializer)
        ? find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue)
        : undefined);
@@ -1217,7 +1217,7 @@ namespace Harness {
}

const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : true;
const programFileNames = inputFiles.map(file => file.unitName);
const programFileNames = inputFiles.map(file => file.unitName).filter(fileName => !ts.fileExtensionIs(fileName, ts.Extension.Json));

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Why filter these?

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 4, 2018

Author Member

Because json files arent provided as fileNames but only picked during module resolution

if (!cfg) return;
const oldFile = cfg.jsonObject && getFilesEntry(cfg.jsonObject, oldFilePath);
const configFile = program.getCompilerOptions().configFile;
const oldFile = getTsConfigPropArrayElementValue(configFile, "files", oldFilePath);

This comment has been minimized.

Copy link
@andy-ms

andy-ms May 4, 2018

Member

Nit: That function isn't declared to accept undefined inputs

@andy-ms

andy-ms approved these changes May 4, 2018

@@ -2200,6 +2200,12 @@ namespace ts {
}
}

if (options.resolveJsonModule) {
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {

This comment has been minimized.

Copy link
@mhegazy

mhegazy May 4, 2018

what about --module? do not think we should allow this for --module ES2015 for example..

This comment has been minimized.

Copy link
@sheetalkamat

sheetalkamat May 4, 2018

Author Member

Clarified offline. At present --moduleResolution specified takes preferences for resolution irrespective of --module and since there is no change in there, no error needs to be reported specially.

@mhegazy

mhegazy approved these changes May 4, 2018

Copy link

left a comment

One comment about --module and --resolveJsonModule relationship.

@mhegazy mhegazy referenced this pull request May 4, 2018

Closed

Support new flags (2.9) #23627

4 of 4 tasks complete

@sheetalkamat sheetalkamat merged commit 5133c70 into master May 4, 2018

5 checks passed

VSTS: TS-PR-node10 512 succeeded
Details
VSTS: TS-PR-node6 510 succeeded
Details
VSTS: TS-PR-node8 511 succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
license/cla All CLA requirements met.
Details

@sheetalkamat sheetalkamat deleted the requireJson branch May 4, 2018

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.