Uh oh!
There was an error while loading. Please reload this page.
Import assertion - #40698
Conversation
f945374 to
e1b3b78CompareKingwl
commented
Sep 22, 2020
@typescript-bot pack this. |
| function checkGrammarImportAssertion(declaration: ImportDeclaration | ExportDeclaration) { | ||
| const target = getEmitScriptTarget(compilerOptions); | ||
| if (target < ScriptTarget.ESNext && declaration.assertClause) { | ||
| grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_are_not_available_when_targeting_lower_than_esnext); |
There was a problem hiding this comment.
According to the current specification of Import Assertion, the import clause cannot affect the representation of the source text. Does it mean it can be safely ignored (when downlevel, drop the whole assert clause instead of emitting an error)?
There was a problem hiding this comment.
Well. IMO, downlevel means something could map to another. Ignore is not a good idea.
But maybe we could control the error by module options rather than target.
There was a problem hiding this comment.
Import Assertions are an enrichment to the import statement, provides the runtime with extra information of which it can make a decision about. I could see the need to allow an error by default, but allow the error to be ignored and the node to be dropped from the emit.
The biggest use case is supporting JSON modules, and there are several runtimes that already support JSON modules without the assertion, but I can see people wanting to start writing the assertions in the code for the runtimes that will only support it with the assertion clause.
typescript-bot
commented
Nov 12, 2020
The TypeScript team hasn't accepted the linked issue #40694. If you can get it accepted, this PR will have a better chance of being reviewed. |
Kingwl
commented
Dec 31, 2020
uP. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Kingwl
commented
Sep 8, 2021
Up. |
rbuckton
commented
Sep 9, 2021
Sorry for the delay @Kingwl. I'm looking at this again today. |
rbuckton
left a comment
There was a problem hiding this comment.
FYI, I will be OOF through Tuesday and may not be able to respond to feedback until Wednesday.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. | ||
| // parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import. | ||
| if (isSpreadElement(nodeArguments[0])) { | ||
| if (nodeArguments.length && isSpreadElement(nodeArguments[0])) { |
There was a problem hiding this comment.
Do we need to check that all elements of the assert property of the second argument have type string? Per https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call, Step 10.d.v.3:
No coercion to string is performed here, the algorithm explicitly checks for strings.
We might want to consider something like the ImportMeta interface for the import argument, something like:
// es5.d.tsinterfaceImportCallOptions{assert?: ImportAssertions;}interfaceImportAssertions{type?: string;[key: string]: string|undefined;// not ideal, but necessary so that `type` is optional.}Then we can check against the global ImportCallOptions type, and if other assertions or options are added later, they can be introduced using global augmentation similar to ImportMeta.
We could consider this as a follow-on PR if necessary, but it would be nice to have.
There was a problem hiding this comment.
NOTE: if we wanted to be more specific with type we'd need to create an open-ended union via an interface as well:
interfaceImportAssertions{type?: ImportTypeAssertion;[key: string]: string|undefined;}// see ArrayBufferTypes for referenceinterfaceImportTypeAssertionTypes{json: "json";}typeImportTypeAssertion=Extract<ImportTypeAssertions[keyofImportTypeAssertions],string>;That way, we have better completions for type and if a host environment supported other values for type, they could also be added via augmentation, i.e.:
interfaceImportTypeAssertionTypes{css: "css";}There was a problem hiding this comment.
Also, the nodeArguments.length check shouldn't be necessary if checkGrammarImportCallArguments already asserts that nodeArguments.length can't be zero.
There was a problem hiding this comment.
We also need to ensure that nodeArguments[1] (if present) is not a spread element.
I would suggest this approach:
constspreadElement=forEach(nodeArguments,isSpreadElement);if(spreadElement){returngrammarErrorOnNode(spreadElement,Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element);}That way it checks all arguments, but only reports on the first error (which is almost always the case for grammar errors).
There was a problem hiding this comment.
Should we check the assert clause too?Or just the second parameter of dynamic import.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
rbuckton
left a comment
There was a problem hiding this comment.
A few more minor changes. @DanielRosenwasser, @andrewbranch do we want to add something like #40698 (comment) in this PR or in a follow up?
There was a problem hiding this comment.
Nit: remove extra space
| if(nodeArguments.length===0||nodeArguments.length>2){ | |
| if(nodeArguments.length===0||nodeArguments.length>2){ |
There was a problem hiding this comment.
Hmm. This doesn't quite do what we want. We want to report the error on the spread element, not the first argument (which might not be the spread element). I think we want this instead:
| constspreadElement=forEach(nodeArguments,isSpreadElement); | |
| if(spreadElement){ | |
| returngrammarErrorOnNode(nodeArguments[0],Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element); | |
| } | |
| constspreadElement=find(nodeArguments,isSpreadElement); | |
| if(spreadElement){ | |
| returngrammarErrorOnNode(spreadElement,Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element); | |
| } | |
There was a problem hiding this comment.
I would leave | undefined here instead of adding ?. My previous comment was specific to the create. For a create, there's no sense breaking existing code because they weren't previously passing an argument. For an update, we do want to break existing code because there's now a new node they may not be appropriately handling.
There was a problem hiding this comment.
I also would leave | undefined here. We want to break callers here since they could be forgetting to handle a node they weren't previously handling.
| "category": "Message", | ||
| "code": 1449 | ||
| }, | ||
| "Dynamic import must only have a specifier and an optional assertion as arguments": { |
There was a problem hiding this comment.
| "Dynamic import must only have a specifier and an optional assertion as arguments": { | |
| "Dynamic imports can only accept a path and an optional assertion as arguments": { |
There was a problem hiding this comment.
Agree, but I think module specifier is a more correct term than path
| "code": 1323 | ||
| }, | ||
| "Dynamic import must have one specifier as an argument.": { | ||
| "Dynamic import only supports a second argument when the '--module' option is set to 'esnext'.": { |
There was a problem hiding this comment.
| "Dynamic import only supports a second argument when the '--module' option is set to 'esnext'.": { | |
| "Dynamic imports only support a second argument when the '--module' option is set to 'esnext'.": { |
andrewbranch
commented
Sep 16, 2021
Let’s try to get this in this PR if possible. Preventing runtime errors seems high priority to me. I personally like the idea of an open-ended interface, but I think that warrants some design discussion to make sure we’re all on the same page. Let’s discuss at Friday’s meeting. |
rbuckton
commented
Sep 17, 2021
@Kingwl, if you don't mind I'm going to make some of these minor changes and add a basic implementation of #40698 (comment) that we can expand on later. |
rbuckton
commented
Sep 17, 2021
I found a small bug in program.ts related to |
# Conflicts: # src/compiler/diagnosticMessages.json
Kingwl
commented
Sep 18, 2021
Never mind. Thanks for your changes. |
rbuckton
commented
Sep 20, 2021
I fixed completions for |
9accee9 to
b07c6e9Comparerbuckton
commented
Sep 20, 2021
Thanks for all the effort you put into this @Kingwl! |

Fixes#40694