Conversation
f945374 to
e1b3b78
Compare
|
@typescript-bot pack this. |
src/compiler/checker.ts
Outdated
| 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.
|
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. |
|
uP. |
|
Up. |
|
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.
src/compiler/checker.ts
Outdated
| // 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.ts
interface ImportCallOptions {
assert?: ImportAssertions;
}
interface ImportAssertions {
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:
interface ImportAssertions {
type?: ImportTypeAssertion;
[key: string]: string | undefined;
}
// see ArrayBufferTypes for reference
interface ImportTypeAssertionTypes {
json: "json";
}
type ImportTypeAssertion = Extract<ImportTypeAssertions[keyof ImportTypeAssertions], 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.:
interface ImportTypeAssertionTypes {
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:
const spreadElement = forEach(nodeArguments, isSpreadElement);
if (spreadElement) {
return grammarErrorOnNode(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.
tests/baselines/reference/importAssertion1(module=esnext).errors.txt
Outdated
Show resolved
Hide resolved
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:
| const spreadElement = forEach(nodeArguments, isSpreadElement); | |
| if (spreadElement) { | |
| return grammarErrorOnNode(nodeArguments[0], Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element); | |
| } | |
| const spreadElement = find(nodeArguments, isSpreadElement); | |
| if (spreadElement) { | |
| return grammarErrorOnNode(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.
src/compiler/types.ts
Outdated
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.
src/compiler/diagnosticMessages.json
Outdated
| "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
src/compiler/diagnosticMessages.json
Outdated
| "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'.": { |
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. |
|
@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. |
|
I found a small bug in program.ts related to |
# Conflicts: # src/compiler/diagnosticMessages.json
|
Never mind. Thanks for your changes. |
|
I fixed completions for |
9accee9 to
b07c6e9
Compare
|
Thanks for all the effort you put into this @Kingwl! |

Fixes #40694