1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Import assertions (#5391)

This commit is contained in:
Geoffrey Booth 2022-01-20 11:40:13 -08:00 committed by GitHub
parent 20b8362887
commit f557c0579b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 735 additions and 210 deletions

View file

@ -476,6 +476,7 @@ runTests = (CoffeeScript) ->
skipUnless '/foo.bar/s.test("foo\tbar")', ['regex_dotall.coffee']
skipUnless '1_2_3', ['numeric_literal_separators.coffee']
skipUnless '1n', ['numbers_bigint.coffee']
skipUnless 'async () => { await import(\'data:application/json,{"foo":"bar"}\', { assert: { type: "json" } }) }', ['import_assertions.coffee']
files = fs.readdirSync('test').filter (filename) ->
filename not in testFilesToSkip

View file

@ -277,7 +277,7 @@ defined above. The <code>LOC</code> function, when used below in the grammar rul
is used to make sure that newly created node class objects get correct
location data assigned to them. By default, the grammar will assign the
location data spanned by <em>all</em> of the tokens on the left (e.g. a string
such as <code>&#39;Body TERMINATOR Line&#39;</code>) to the “top-level” node returned by
such as <code>&#39;Body TERMINATOR Line&#39;</code>) to the “top-level” node returned by
the grammar rule (the function on the right). But for “inner” node class
objects created by grammar rules, they wont get correct location data
assigned to them without adding <code>LOC</code>.</p>
@ -1146,13 +1146,20 @@ and optional references to the superclass.</p>
]
Import: [
o <span class="hljs-string">&#x27;IMPORT String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-literal">null</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;IMPORT ImportNamespaceSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;IMPORT { } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList []), $<span class="hljs-number">5</span>
o <span class="hljs-string">&#x27;IMPORT { ImportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>), $<span class="hljs-number">6</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">5</span>), $<span class="hljs-number">9</span>
o <span class="hljs-string">&#x27;IMPORT String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">&#x27;IMPORT String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-literal">null</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-literal">null</span>), $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
o <span class="hljs-string">&#x27;IMPORT ImportNamespaceSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;IMPORT ImportNamespaceSpecifier FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
o <span class="hljs-string">&#x27;IMPORT { } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList []), $<span class="hljs-number">5</span>
o <span class="hljs-string">&#x27;IMPORT { } FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList []), $<span class="hljs-number">5</span>, $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;IMPORT { ImportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause(<span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>, $<span class="hljs-number">9</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>), $<span class="hljs-number">6</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>), $<span class="hljs-number">6</span>, $<span class="hljs-number">8</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">5</span>), $<span class="hljs-number">9</span>
o <span class="hljs-string">&#x27;IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ImportDeclaration <span class="hljs-keyword">new</span> ImportClause($<span class="hljs-number">2</span>, <span class="hljs-keyword">new</span> ImportSpecifierList $<span class="hljs-number">5</span>), $<span class="hljs-number">9</span>, $<span class="hljs-number">11</span>
]
ImportSpecifierList: [
@ -1179,20 +1186,23 @@ and optional references to the superclass.</p>
]
Export: [
o <span class="hljs-string">&#x27;EXPORT { }&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList []
o <span class="hljs-string">&#x27;EXPORT { ExportSpecifierList OptComma }&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList $<span class="hljs-number">3</span>
o <span class="hljs-string">&#x27;EXPORT Class&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration $<span class="hljs-number">2</span>
o <span class="hljs-string">&#x27;EXPORT Identifier = Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">4</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, <span class="hljs-literal">null</span>,
o <span class="hljs-string">&#x27;EXPORT { }&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList []
o <span class="hljs-string">&#x27;EXPORT { ExportSpecifierList OptComma }&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList $<span class="hljs-number">3</span>
o <span class="hljs-string">&#x27;EXPORT Class&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration $<span class="hljs-number">2</span>
o <span class="hljs-string">&#x27;EXPORT Identifier = Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">4</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, <span class="hljs-literal">null</span>,
moduleDeclaration: <span class="hljs-string">&#x27;export&#x27;</span>)
o <span class="hljs-string">&#x27;EXPORT Identifier = TERMINATOR Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">5</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, <span class="hljs-literal">null</span>,
o <span class="hljs-string">&#x27;EXPORT Identifier = TERMINATOR Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">5</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, <span class="hljs-literal">null</span>,
moduleDeclaration: <span class="hljs-string">&#x27;export&#x27;</span>)
o <span class="hljs-string">&#x27;EXPORT Identifier = INDENT Expression OUTDENT&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">6</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, <span class="hljs-literal">null</span>,
o <span class="hljs-string">&#x27;EXPORT Identifier = INDENT Expression OUTDENT&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration LOC(<span class="hljs-number">2</span>,<span class="hljs-number">6</span>)(<span class="hljs-keyword">new</span> Assign $<span class="hljs-number">2</span>, $<span class="hljs-number">5</span>, <span class="hljs-literal">null</span>,
moduleDeclaration: <span class="hljs-string">&#x27;export&#x27;</span>)
o <span class="hljs-string">&#x27;EXPORT DEFAULT Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration $<span class="hljs-number">3</span>
o <span class="hljs-string">&#x27;EXPORT DEFAULT INDENT Object OUTDENT&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration <span class="hljs-keyword">new</span> Value $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;EXPORT EXPORT_ALL FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportAllDeclaration <span class="hljs-keyword">new</span> Literal($<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;EXPORT { } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList([]), $<span class="hljs-number">5</span>
o <span class="hljs-string">&#x27;EXPORT { ExportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList($<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;EXPORT DEFAULT Expression&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration $<span class="hljs-number">3</span>
o <span class="hljs-string">&#x27;EXPORT DEFAULT INDENT Object OUTDENT&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportDefaultDeclaration <span class="hljs-keyword">new</span> Value $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;EXPORT EXPORT_ALL FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportAllDeclaration <span class="hljs-keyword">new</span> Literal($<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>
o <span class="hljs-string">&#x27;EXPORT EXPORT_ALL FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportAllDeclaration <span class="hljs-keyword">new</span> Literal($<span class="hljs-number">2</span>), $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
o <span class="hljs-string">&#x27;EXPORT { } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList([]), $<span class="hljs-number">5</span>
o <span class="hljs-string">&#x27;EXPORT { } FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList([]), $<span class="hljs-number">5</span>, $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;EXPORT { ExportSpecifierList OptComma } FROM String&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList($<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>
o <span class="hljs-string">&#x27;EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object&#x27;</span>, <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> ExportNamedDeclaration <span class="hljs-keyword">new</span> ExportSpecifierList($<span class="hljs-number">3</span>), $<span class="hljs-number">7</span>, $<span class="hljs-number">9</span>
]
ExportSpecifierList: [

View file

@ -414,6 +414,9 @@ though <code>is</code> means <code>===</code> otherwise.</p>
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;default&#x27;</span> <span class="hljs-keyword">and</span> @seenExport <span class="hljs-keyword">and</span> @tag() <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;EXPORT&#x27;</span>, <span class="hljs-string">&#x27;AS&#x27;</span>]
@token <span class="hljs-string">&#x27;DEFAULT&#x27;</span>, id
<span class="hljs-keyword">return</span> id.length
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;assert&#x27;</span> <span class="hljs-keyword">and</span> (@seenImport <span class="hljs-keyword">or</span> @seenExport) <span class="hljs-keyword">and</span> @tag() <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;STRING&#x27;</span>
@token <span class="hljs-string">&#x27;ASSERT&#x27;</span>, id
<span class="hljs-keyword">return</span> id.length
<span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;do&#x27;</span> <span class="hljs-keyword">and</span> regExSuper = <span class="hljs-regexp">/^(\s*super)(?!\(\))/</span>.exec @chunk[<span class="hljs-number">3.</span>..]
@token <span class="hljs-string">&#x27;SUPER&#x27;</span>, <span class="hljs-string">&#x27;super&#x27;</span>
@token <span class="hljs-string">&#x27;CALL_START&#x27;</span>, <span class="hljs-string">&#x27;(&#x27;</span>

View file

@ -5845,11 +5845,11 @@ opposed to the <code>Object.defineProperty</code> method).</p>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.ModuleDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@clause, @source)</span> -&gt;</span>
constructor: <span class="hljs-function"><span class="hljs-params">(@clause, @source, @assertions)</span> -&gt;</span>
super()
@checkSource()
children: [<span class="hljs-string">&#x27;clause&#x27;</span>, <span class="hljs-string">&#x27;source&#x27;</span>]
children: [<span class="hljs-string">&#x27;clause&#x27;</span>, <span class="hljs-string">&#x27;source&#x27;</span>, <span class="hljs-string">&#x27;assertions&#x27;</span>]
isStatement: YES
jumps: THIS
@ -5880,6 +5880,14 @@ whether were at the “program top-level”.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> o.indent.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
@error <span class="hljs-string">&quot;<span class="hljs-subst">#{moduleDeclarationType}</span> statements must be at top-level scope&quot;</span>
astAssertions: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @assertions?.properties?
@assertions.properties.map (assertion) =&gt;
{ start, end, loc, left, right } = assertion.ast(o)
{ type: <span class="hljs-string">&#x27;ImportAttribute&#x27;</span>, start, end, loc, key: left, value: right }
<span class="hljs-keyword">else</span>
[]
<span class="hljs-built_in">exports</span>.ImportDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleDeclaration</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o, <span class="hljs-string">&#x27;import&#x27;</span>
@ -5892,6 +5900,9 @@ whether were at the “program top-level”.</p>
<span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">&#x27; from &#x27;</span> <span class="hljs-keyword">unless</span> @clause <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>
code.push @makeCode @source.value
<span class="hljs-keyword">if</span> @assertions?
code.push @makeCode <span class="hljs-string">&#x27; assert &#x27;</span>
code.push @assertions.compileToFragments(o)...
code.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
code
@ -5904,6 +5915,7 @@ whether were at the “program top-level”.</p>
ret =
specifiers: @clause?.ast(o) ? []
source: @source.ast o
assertions: @astAssertions(o)
ret.importKind = <span class="hljs-string">&#x27;value&#x27;</span> <span class="hljs-keyword">if</span> @clause
ret
@ -5965,7 +5977,12 @@ that will be the <code>specifiers</code> property of an <code>ImportDeclaration<
<span class="hljs-keyword">else</span>
code = code.concat @clause.compileNode o
code.push @makeCode <span class="hljs-string">&quot; from <span class="hljs-subst">#{@source.value}</span>&quot;</span> <span class="hljs-keyword">if</span> @source?.value?
<span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">&quot; from <span class="hljs-subst">#{@source.value}</span>&quot;</span>
<span class="hljs-keyword">if</span> @assertions?
code.push @makeCode <span class="hljs-string">&#x27; assert &#x27;</span>
code.push @assertions.compileToFragments(o)...
code.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
code</pre></div></div>
@ -5994,6 +6011,7 @@ that will be the <code>specifiers</code> property of an <code>ImportDeclaration<
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
ret =
source: @source?.ast(o) ? <span class="hljs-literal">null</span>
assertions: @astAssertions(o)
exportKind: <span class="hljs-string">&#x27;value&#x27;</span>
clauseAst = @clause.ast o
<span class="hljs-keyword">if</span> @clause <span class="hljs-keyword">instanceof</span> ExportSpecifierList
@ -6008,11 +6026,13 @@ that will be the <code>specifiers</code> property of an <code>ImportDeclaration<
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
declaration: @clause.ast o
assertions: @astAssertions(o)
<span class="hljs-built_in">exports</span>.ExportAllDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportAllDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
source: @source.ast o
assertions: @astAssertions(o)
exportKind: <span class="hljs-string">&#x27;value&#x27;</span>
<span class="hljs-built_in">exports</span>.ModuleSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
@ -6148,8 +6168,8 @@ that will be the <code>specifiers</code> property of an <code>ImportDeclaration<
super o
checkArguments: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">unless</span> @args.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
@error <span class="hljs-string">&#x27;import() requires exactly one argument&#x27;</span>
<span class="hljs-keyword">unless</span> <span class="hljs-number">1</span> &lt;= @args.length &lt;= <span class="hljs-number">2</span>
@error <span class="hljs-string">&#x27;import() accepts either one or two arguments&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkArguments()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4268,6 +4268,8 @@ import { now as currentTimestamp } from 'underscore'
import { first, last } from 'underscore'
import utilityBelt, { each } from 'underscore'
import dates from './calendar.json' assert { type: 'json' }
export default Math
export square = (x) -> x * x
export class Mathematics
@ -4279,6 +4281,7 @@ export { Mathematics as default, sqrt as squareRoot }
export * from 'underscore'
export { max, min } from 'underscore'
export { version } from './package.json' assert { type: 'json' }
</textarea>
<pre class="placeholder-code"><span class="cm-variable">import</span> <span class="cm-string">'./local-file.js'</span> <span class="cm-comment"># Must be the filename of the generated file</span>
<span class="cm-variable">import</span> <span class="cm-string">'package'</span>
@ -4291,6 +4294,8 @@ export { max, min } from 'underscore'
<span class="cm-variable">import</span> <span class="cm-punctuation">{</span> <span class="cm-variable">first</span><span class="cm-punctuation">,</span> <span class="cm-variable">last</span> <span class="cm-punctuation">}</span> <span class="cm-variable">from</span> <span class="cm-string">'underscore'</span>
<span class="cm-variable">import</span> <span class="cm-variable">utilityBelt</span><span class="cm-punctuation">,</span> <span class="cm-punctuation">{</span> <span class="cm-variable">each</span> <span class="cm-punctuation">}</span> <span class="cm-variable">from</span> <span class="cm-string">'underscore'</span>
<span class="cm-variable">import</span> <span class="cm-variable">dates</span> <span class="cm-variable">from</span> <span class="cm-string">'./calendar.json'</span> <span class="cm-variable">assert</span> <span class="cm-punctuation">{</span> <span class="cm-variable">type</span><span class="cm-punctuation">:</span> <span class="cm-string">'json'</span> <span class="cm-punctuation">}</span>
<span class="cm-variable">export</span> <span class="cm-variable">default</span> <span class="cm-variable">Math</span>
<span class="cm-variable">export</span> <span class="cm-variable">square</span> <span class="cm-punctuation">=</span> <span class="cm-punctuation">(</span><span class="cm-variable">x</span><span class="cm-punctuation">)</span> <span class="cm-operator">-></span> <span class="cm-variable">x</span> <span class="cm-operator">*</span> <span class="cm-variable">x</span>
<span class="cm-variable">export</span> <span class="cm-keyword">class</span> <span class="cm-variable">Mathematics</span>
@ -4302,6 +4307,7 @@ export { max, min } from 'underscore'
<span class="cm-variable">export</span> <span class="cm-operator">*</span> <span class="cm-variable">from</span> <span class="cm-string">'underscore'</span>
<span class="cm-variable">export</span> <span class="cm-punctuation">{</span> <span class="cm-variable">max</span><span class="cm-punctuation">,</span> <span class="cm-variable">min</span> <span class="cm-punctuation">}</span> <span class="cm-variable">from</span> <span class="cm-string">'underscore'</span>
<span class="cm-variable">export</span> <span class="cm-punctuation">{</span> <span class="cm-variable">version</span> <span class="cm-punctuation">}</span> <span class="cm-variable">from</span> <span class="cm-string">'./package.json'</span> <span class="cm-variable">assert</span> <span class="cm-punctuation">{</span> <span class="cm-variable">type</span><span class="cm-punctuation">:</span> <span class="cm-string">'json'</span> <span class="cm-punctuation">}</span>
</pre>
</div>
<div class="col-md-6 javascript-output-column">
@ -4330,6 +4336,10 @@ import utilityBelt, {
each
} from 'underscore';
import dates from './calendar.json' assert {
type: 'json'
};
export default Math;
export var square = function(x) {
@ -4366,6 +4376,12 @@ export {
max,
min
} from 'underscore';
export {
version
} from './package.json' assert {
type: 'json'
};
</textarea>
<pre class="placeholder-code"><span class="cm-keyword">import</span> <span class="cm-string">'./local-file.js'</span>;
@ -4392,6 +4408,10 @@ export {
<span class="cm-def">each</span>
} <span class="cm-keyword">from</span> <span class="cm-string">'underscore'</span>;
<span class="cm-keyword">import</span> <span class="cm-def">dates</span> <span class="cm-keyword">from</span> <span class="cm-string">'./calendar.json'</span> <span class="cm-variable">assert</span> {
<span class="cm-variable">type</span>: <span class="cm-string">'json'</span>
};
<span class="cm-keyword">export</span> <span class="cm-keyword">default</span> <span class="cm-variable">Math</span>;
<span class="cm-keyword">export</span> <span class="cm-keyword">var</span> <span class="cm-def">square</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>(<span class="cm-def">x</span>) {
@ -4428,6 +4448,12 @@ export {
<span class="cm-variable">max</span>,
<span class="cm-variable">min</span>
} <span class="cm-keyword">from</span> <span class="cm-string">'underscore'</span>;
<span class="cm-keyword">export</span> {
<span class="cm-variable">version</span>
} <span class="cm-keyword">from</span> <span class="cm-string">'./package.json'</span> <span class="cm-variable">assert</span> {
<span class="cm-variable">type</span>: <span class="cm-string">'json'</span>
};
</pre>
</div>
</div>

View file

@ -2218,6 +2218,31 @@ test "AST as expected for ModuleDeclaration node", ->
type: 'StringLiteral'
value: '.'
testStatement 'import X from "." assert { type: "json" }',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'X'
declaration: no
]
importKind: 'value'
source:
type: 'StringLiteral'
value: '.'
assertions: [
type: 'ImportAttribute'
key:
type: 'Identifier'
name: 'type'
value:
type: 'StringLiteral'
value: 'json'
extra:
raw: '"json"'
]
test "AST as expected for ImportDeclaration node", ->
testStatement 'import React, {Component} from "react"',
type: 'ImportDeclaration'
@ -2369,6 +2394,26 @@ test "AST as expected for ExportAllDeclaration node", ->
raw: '"module-name"'
exportKind: 'value'
testStatement 'export * from "module-name" assert { type: "json" }',
type: 'ExportAllDeclaration'
source:
type: 'StringLiteral'
value: 'module-name'
extra:
raw: '"module-name"'
assertions: [
type: 'ImportAttribute'
key:
type: 'Identifier'
name: 'type'
value:
type: 'StringLiteral'
value: 'json'
extra:
raw: '"json"'
]
exportKind: 'value'
test "AST as expected for ExportSpecifierList node", ->
testStatement 'export {a, b, c}',
type: 'ExportNamedDeclaration'
@ -22988,21 +23033,21 @@ test "`new.target` cannot be assigned", ->
^
'''
test "#4834: dynamic import requires exactly one argument", ->
test "#4834: dynamic import accepts either one or two arguments", ->
assertErrorFormat '''
import()
''', '''
[stdin]:1:1: error: import() requires exactly one argument
[stdin]:1:1: error: import() accepts either one or two arguments
import()
^^^^^^^^
'''
assertErrorFormat '''
import('x', {})
import('x', {}, 3)
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import('x', {})
^^^^^^^^^^^^^^^
[stdin]:1:1: error: import() accepts either one or two arguments
import('x', {}, 3)
^^^^^^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires explicit call parentheses", ->
@ -25667,6 +25712,97 @@ test "the `baseFileName` helper returns the file name to write to", ->
filename = name + ext
eq filename, expectedFileName
</script>
<script type="text/x-coffeescript" class="test" id="import_assertions">
# This file is running in CommonJS (in Node) or as a classic Script (in the browser tests) so it can use import() within an async function, but not at the top level; and we cant use static import.
test "dynamic import assertion", ->
{ default: secret } = await import('data:application/json,{"ofLife":42}', { assert: { type: 'json' } })
eq secret.ofLife, 42
test "assert keyword", ->
assert = 1
{ default: assert } = await import('data:application/json,{"thatIAm":42}', { assert: { type: 'json' } })
eq assert.thatIAm, 42
eqJS """
import assert from 'regression-test'
""", """
import assert from 'regression-test';
"""
test "static import assertion", ->
eqJS """
import 'data:application/json,{"foo":3}' assert { type: 'json' }
""", """
import 'data:application/json,{"foo":3}' assert {
type: 'json'
};
"""
eqJS """
import secret from 'data:application/json,{"ofLife":42}' assert { type: 'json' }
""", """
import secret from 'data:application/json,{"ofLife":42}' assert {
type: 'json'
};
"""
eqJS """
import * as secret from 'data:application/json,{"ofLife":42}' assert { type: 'json' }
""", """
import * as secret from 'data:application/json,{"ofLife":42}' assert {
type: 'json'
};
"""
# The only file types for which import assertions are currently supported are JSON (Node and browsers) and CSS (browsers), neither of which support named exports; however theres nothing in the JavaScript grammar preventing a future supported file type from providing named exports.
eqJS """
import { foo } from './file.unknown' assert { type: 'unknown' }
""", """
import {
foo
} from './file.unknown' assert {
type: 'unknown'
};
"""
eqJS """
import file, { foo } from './file.unknown' assert { type: 'unknown' }
""", """
import file, {
foo
} from './file.unknown' assert {
type: 'unknown'
};
"""
eqJS """
import foo from 'bar' assert {}
""", """
import foo from 'bar' assert {};
"""
test "static export with assertion", ->
eqJS """
export * from 'data:application/json,{"foo":3}' assert { type: 'json' }
""", """
export * from 'data:application/json,{"foo":3}' assert {
type: 'json'
};
"""
eqJS """
export { profile } from './user.json' assert { type: 'json' }
""", """
export {
profile
} from './user.json' assert {
type: 'json'
};
"""
</script>
<script type="text/x-coffeescript" class="test" id="importing">
# Importing

View file

@ -9,6 +9,8 @@ import { now as currentTimestamp } from 'underscore'
import { first, last } from 'underscore'
import utilityBelt, { each } from 'underscore'
import dates from './calendar.json' assert { type: 'json' }
export default Math
export square = (x) -> x * x
export class Mathematics
@ -20,3 +22,4 @@ export { Mathematics as default, sqrt as squareRoot }
export * from 'underscore'
export { max, min } from 'underscore'
export { version } from './package.json' assert { type: 'json' }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -58,7 +58,7 @@
// is used to make sure that newly created node class objects get correct
// location data assigned to them. By default, the grammar will assign the
// location data spanned by *all* of the tokens on the left (e.g. a string
// such as `'Body TERMINATOR Line'`) to the “top-level” node returned by
// such as `'Body TERMINATOR Line'`) to the “top-level” node returned by
// the grammar rule (the function on the right). But for “inner” node class
// objects created by grammar rules, they wont get correct location data
// assigned to them without adding `LOC`.
@ -900,41 +900,89 @@
return new ImportDeclaration(null,
$2);
}),
o('IMPORT String ASSERT Object',
function() {
return new ImportDeclaration(null,
$2,
$4);
}),
o('IMPORT ImportDefaultSpecifier FROM String',
function() {
return new ImportDeclaration(new ImportClause($2,
null),
$4);
}),
o('IMPORT ImportDefaultSpecifier FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause($2,
null),
$4,
$6);
}),
o('IMPORT ImportNamespaceSpecifier FROM String',
function() {
return new ImportDeclaration(new ImportClause(null,
$2),
$4);
}),
o('IMPORT ImportNamespaceSpecifier FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause(null,
$2),
$4,
$6);
}),
o('IMPORT { } FROM String',
function() {
return new ImportDeclaration(new ImportClause(null,
new ImportSpecifierList([])),
$5);
}),
o('IMPORT { } FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause(null,
new ImportSpecifierList([])),
$5,
$7);
}),
o('IMPORT { ImportSpecifierList OptComma } FROM String',
function() {
return new ImportDeclaration(new ImportClause(null,
new ImportSpecifierList($3)),
$7);
}),
o('IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause(null,
new ImportSpecifierList($3)),
$7,
$9);
}),
o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String',
function() {
return new ImportDeclaration(new ImportClause($2,
$4),
$6);
}),
o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause($2,
$4),
$6,
$8);
}),
o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String',
function() {
return new ImportDeclaration(new ImportClause($2,
new ImportSpecifierList($5)),
$9);
}),
o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object',
function() {
return new ImportDeclaration(new ImportClause($2,
new ImportSpecifierList($5)),
$9,
$11);
})
],
ImportSpecifierList: [
@ -1048,15 +1096,33 @@
return new ExportAllDeclaration(new Literal($2),
$4);
}),
o('EXPORT EXPORT_ALL FROM String ASSERT Object',
function() {
return new ExportAllDeclaration(new Literal($2),
$4,
$6);
}),
o('EXPORT { } FROM String',
function() {
return new ExportNamedDeclaration(new ExportSpecifierList([]),
$5);
}),
o('EXPORT { } FROM String ASSERT Object',
function() {
return new ExportNamedDeclaration(new ExportSpecifierList([]),
$5,
$7);
}),
o('EXPORT { ExportSpecifierList OptComma } FROM String',
function() {
return new ExportNamedDeclaration(new ExportSpecifierList($3),
$7);
}),
o('EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object',
function() {
return new ExportNamedDeclaration(new ExportSpecifierList($3),
$7,
$9);
})
],
ExportSpecifierList: [

View file

@ -177,6 +177,10 @@
this.token('DEFAULT', id);
return id.length;
}
if (id === 'assert' && (this.seenImport || this.seenExport) && this.tag() === 'STRING') {
this.token('ASSERT', id);
return id.length;
}
if (id === 'do' && (regExSuper = /^(\s*super)(?!\(\))/.exec(this.chunk.slice(3)))) {
this.token('SUPER', 'super');
this.token('CALL_START', '(');

View file

@ -4782,10 +4782,11 @@
//### Import and Export
exports.ModuleDeclaration = ModuleDeclaration = (function() {
class ModuleDeclaration extends Base {
constructor(clause, source1) {
constructor(clause, source1, assertions) {
super();
this.clause = clause;
this.source = source1;
this.assertions = assertions;
this.checkSource();
}
@ -4805,9 +4806,29 @@
}
}
astAssertions(o) {
var ref1;
if (((ref1 = this.assertions) != null ? ref1.properties : void 0) != null) {
return this.assertions.properties.map((assertion) => {
var end, left, loc, right, start;
({start, end, loc, left, right} = assertion.ast(o));
return {
type: 'ImportAttribute',
start,
end,
loc,
key: left,
value: right
};
});
} else {
return [];
}
}
};
ModuleDeclaration.prototype.children = ['clause', 'source'];
ModuleDeclaration.prototype.children = ['clause', 'source', 'assertions'];
ModuleDeclaration.prototype.isStatement = YES;
@ -4834,6 +4855,10 @@
code.push(this.makeCode(' from '));
}
code.push(this.makeCode(this.source.value));
if (this.assertions != null) {
code.push(this.makeCode(' assert '));
code.push(...this.assertions.compileToFragments(o));
}
}
code.push(this.makeCode(';'));
return code;
@ -4848,7 +4873,8 @@
var ref1, ref2, ret;
ret = {
specifiers: (ref1 = (ref2 = this.clause) != null ? ref2.ast(o) : void 0) != null ? ref1 : [],
source: this.source.ast(o)
source: this.source.ast(o),
assertions: this.astAssertions(o)
};
if (this.clause) {
ret.importKind = 'value';
@ -4917,6 +4943,10 @@
}
if (((ref1 = this.source) != null ? ref1.value : void 0) != null) {
code.push(this.makeCode(` from ${this.source.value}`));
if (this.assertions != null) {
code.push(this.makeCode(' assert '));
code.push(...this.assertions.compileToFragments(o));
}
}
code.push(this.makeCode(';'));
return code;
@ -4941,6 +4971,7 @@
var clauseAst, ref1, ref2, ret;
ret = {
source: (ref1 = (ref2 = this.source) != null ? ref2.ast(o) : void 0) != null ? ref1 : null,
assertions: this.astAssertions(o),
exportKind: 'value'
};
clauseAst = this.clause.ast(o);
@ -4959,7 +4990,8 @@
exports.ExportDefaultDeclaration = ExportDefaultDeclaration = class ExportDefaultDeclaration extends ExportDeclaration {
astProperties(o) {
return {
declaration: this.clause.ast(o)
declaration: this.clause.ast(o),
assertions: this.astAssertions(o)
};
}
@ -4969,6 +5001,7 @@
astProperties(o) {
return {
source: this.source.ast(o),
assertions: this.astAssertions(o),
exportKind: 'value'
};
}
@ -5165,8 +5198,9 @@
}
checkArguments() {
if (this.args.length !== 1) {
return this.error('import() requires exactly one argument');
var ref1;
if (!((1 <= (ref1 = this.args.length) && ref1 <= 2))) {
return this.error('import() accepts either one or two arguments');
}
}

File diff suppressed because one or more lines are too long

View file

@ -55,11 +55,11 @@ o = (patternString, action, options) ->
# is used to make sure that newly created node class objects get correct
# location data assigned to them. By default, the grammar will assign the
# location data spanned by *all* of the tokens on the left (e.g. a string
# such as `'Body TERMINATOR Line'`) to the top-level node returned by
# such as `'Body TERMINATOR Line'`) to the top-level node returned by
# the grammar rule (the function on the right). But for inner node class
# objects created by grammar rules, they wont get correct location data
# assigned to them without adding `LOC`.
# For example, consider the grammar rule `'NEW_TARGET . Property'`, which
# is handled by a function that returns
# `new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)`.
@ -481,13 +481,20 @@ grammar =
]
Import: [
o 'IMPORT String', -> new ImportDeclaration null, $2
o 'IMPORT ImportDefaultSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, null), $4
o 'IMPORT ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause(null, $2), $4
o 'IMPORT { } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
o 'IMPORT { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, $4), $6
o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
o 'IMPORT String', -> new ImportDeclaration null, $2
o 'IMPORT String ASSERT Object', -> new ImportDeclaration null, $2, $4
o 'IMPORT ImportDefaultSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, null), $4
o 'IMPORT ImportDefaultSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, null), $4, $6
o 'IMPORT ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause(null, $2), $4
o 'IMPORT ImportNamespaceSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, $2), $4, $6
o 'IMPORT { } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
o 'IMPORT { } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5, $7
o 'IMPORT { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
o 'IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7, $9
o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, $4), $6
o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, $4), $6, $8
o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9, $11
]
ImportSpecifierList: [
@ -514,20 +521,23 @@ grammar =
]
Export: [
o 'EXPORT { }', -> new ExportNamedDeclaration new ExportSpecifierList []
o 'EXPORT { ExportSpecifierList OptComma }', -> new ExportNamedDeclaration new ExportSpecifierList $3
o 'EXPORT Class', -> new ExportNamedDeclaration $2
o 'EXPORT Identifier = Expression', -> new ExportNamedDeclaration LOC(2,4)(new Assign $2, $4, null,
o 'EXPORT { }', -> new ExportNamedDeclaration new ExportSpecifierList []
o 'EXPORT { ExportSpecifierList OptComma }', -> new ExportNamedDeclaration new ExportSpecifierList $3
o 'EXPORT Class', -> new ExportNamedDeclaration $2
o 'EXPORT Identifier = Expression', -> new ExportNamedDeclaration LOC(2,4)(new Assign $2, $4, null,
moduleDeclaration: 'export')
o 'EXPORT Identifier = TERMINATOR Expression', -> new ExportNamedDeclaration LOC(2,5)(new Assign $2, $5, null,
o 'EXPORT Identifier = TERMINATOR Expression', -> new ExportNamedDeclaration LOC(2,5)(new Assign $2, $5, null,
moduleDeclaration: 'export')
o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration LOC(2,6)(new Assign $2, $5, null,
o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration LOC(2,6)(new Assign $2, $5, null,
moduleDeclaration: 'export')
o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3
o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4
o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4
o 'EXPORT { } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5
o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3
o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4
o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4
o 'EXPORT EXPORT_ALL FROM String ASSERT Object', -> new ExportAllDeclaration new Literal($2), $4, $6
o 'EXPORT { } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5
o 'EXPORT { } FROM String ASSERT Object', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5, $7
o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
o 'EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7, $9
]
ExportSpecifierList: [

View file

@ -158,6 +158,9 @@ exports.Lexer = class Lexer
if id is 'default' and @seenExport and @tag() in ['EXPORT', 'AS']
@token 'DEFAULT', id
return id.length
if id is 'assert' and (@seenImport or @seenExport) and @tag() is 'STRING'
@token 'ASSERT', id
return id.length
if id is 'do' and regExSuper = /^(\s*super)(?!\(\))/.exec @chunk[3...]
@token 'SUPER', 'super'
@token 'CALL_START', '('

View file

@ -3207,11 +3207,11 @@ exports.ClassPrototypeProperty = class ClassPrototypeProperty extends Base
#### Import and Export
exports.ModuleDeclaration = class ModuleDeclaration extends Base
constructor: (@clause, @source) ->
constructor: (@clause, @source, @assertions) ->
super()
@checkSource()
children: ['clause', 'source']
children: ['clause', 'source', 'assertions']
isStatement: YES
jumps: THIS
@ -3229,6 +3229,14 @@ exports.ModuleDeclaration = class ModuleDeclaration extends Base
if o.indent.length isnt 0
@error "#{moduleDeclarationType} statements must be at top-level scope"
astAssertions: (o) ->
if @assertions?.properties?
@assertions.properties.map (assertion) =>
{ start, end, loc, left, right } = assertion.ast(o)
{ type: 'ImportAttribute', start, end, loc, key: left, value: right }
else
[]
exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
compileNode: (o) ->
@checkScope o, 'import'
@ -3241,6 +3249,9 @@ exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
if @source?.value?
code.push @makeCode ' from ' unless @clause is null
code.push @makeCode @source.value
if @assertions?
code.push @makeCode ' assert '
code.push @assertions.compileToFragments(o)...
code.push @makeCode ';'
code
@ -3253,6 +3264,7 @@ exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
ret =
specifiers: @clause?.ast(o) ? []
source: @source.ast o
assertions: @astAssertions(o)
ret.importKind = 'value' if @clause
ret
@ -3301,7 +3313,12 @@ exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration
else
code = code.concat @clause.compileNode o
code.push @makeCode " from #{@source.value}" if @source?.value?
if @source?.value?
code.push @makeCode " from #{@source.value}"
if @assertions?
code.push @makeCode ' assert '
code.push @assertions.compileToFragments(o)...
code.push @makeCode ';'
code
@ -3318,6 +3335,7 @@ exports.ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDecl
astProperties: (o) ->
ret =
source: @source?.ast(o) ? null
assertions: @astAssertions(o)
exportKind: 'value'
clauseAst = @clause.ast o
if @clause instanceof ExportSpecifierList
@ -3332,11 +3350,13 @@ exports.ExportDefaultDeclaration = class ExportDefaultDeclaration extends Export
astProperties: (o) ->
return
declaration: @clause.ast o
assertions: @astAssertions(o)
exports.ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclaration
astProperties: (o) ->
return
source: @source.ast o
assertions: @astAssertions(o)
exportKind: 'value'
exports.ModuleSpecifierList = class ModuleSpecifierList extends Base
@ -3447,8 +3467,8 @@ exports.DynamicImportCall = class DynamicImportCall extends Call
super o
checkArguments: ->
unless @args.length is 1
@error 'import() requires exactly one argument'
unless 1 <= @args.length <= 2
@error 'import() accepts either one or two arguments'
astNode: (o) ->
@checkArguments()

View file

@ -1979,6 +1979,31 @@ test "AST as expected for ModuleDeclaration node", ->
type: 'StringLiteral'
value: '.'
testStatement 'import X from "." assert { type: "json" }',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'X'
declaration: no
]
importKind: 'value'
source:
type: 'StringLiteral'
value: '.'
assertions: [
type: 'ImportAttribute'
key:
type: 'Identifier'
name: 'type'
value:
type: 'StringLiteral'
value: 'json'
extra:
raw: '"json"'
]
test "AST as expected for ImportDeclaration node", ->
testStatement 'import React, {Component} from "react"',
type: 'ImportDeclaration'
@ -2130,6 +2155,26 @@ test "AST as expected for ExportAllDeclaration node", ->
raw: '"module-name"'
exportKind: 'value'
testStatement 'export * from "module-name" assert { type: "json" }',
type: 'ExportAllDeclaration'
source:
type: 'StringLiteral'
value: 'module-name'
extra:
raw: '"module-name"'
assertions: [
type: 'ImportAttribute'
key:
type: 'Identifier'
name: 'type'
value:
type: 'StringLiteral'
value: 'json'
extra:
raw: '"json"'
]
exportKind: 'value'
test "AST as expected for ExportSpecifierList node", ->
testStatement 'export {a, b, c}',
type: 'ExportNamedDeclaration'

View file

@ -1979,21 +1979,21 @@ test "`new.target` cannot be assigned", ->
^
'''
test "#4834: dynamic import requires exactly one argument", ->
test "#4834: dynamic import accepts either one or two arguments", ->
assertErrorFormat '''
import()
''', '''
[stdin]:1:1: error: import() requires exactly one argument
[stdin]:1:1: error: import() accepts either one or two arguments
import()
^^^^^^^^
'''
assertErrorFormat '''
import('x', {})
import('x', {}, 3)
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import('x', {})
^^^^^^^^^^^^^^^
[stdin]:1:1: error: import() accepts either one or two arguments
import('x', {}, 3)
^^^^^^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires explicit call parentheses", ->

View file

@ -0,0 +1,88 @@
# This file is running in CommonJS (in Node) or as a classic Script (in the browser tests) so it can use import() within an async function, but not at the top level; and we cant use static import.
test "dynamic import assertion", ->
{ default: secret } = await import('data:application/json,{"ofLife":42}', { assert: { type: 'json' } })
eq secret.ofLife, 42
test "assert keyword", ->
assert = 1
{ default: assert } = await import('data:application/json,{"thatIAm":42}', { assert: { type: 'json' } })
eq assert.thatIAm, 42
eqJS """
import assert from 'regression-test'
""", """
import assert from 'regression-test';
"""
test "static import assertion", ->
eqJS """
import 'data:application/json,{"foo":3}' assert { type: 'json' }
""", """
import 'data:application/json,{"foo":3}' assert {
type: 'json'
};
"""
eqJS """
import secret from 'data:application/json,{"ofLife":42}' assert { type: 'json' }
""", """
import secret from 'data:application/json,{"ofLife":42}' assert {
type: 'json'
};
"""
eqJS """
import * as secret from 'data:application/json,{"ofLife":42}' assert { type: 'json' }
""", """
import * as secret from 'data:application/json,{"ofLife":42}' assert {
type: 'json'
};
"""
# The only file types for which import assertions are currently supported are JSON (Node and browsers) and CSS (browsers), neither of which support named exports; however theres nothing in the JavaScript grammar preventing a future supported file type from providing named exports.
eqJS """
import { foo } from './file.unknown' assert { type: 'unknown' }
""", """
import {
foo
} from './file.unknown' assert {
type: 'unknown'
};
"""
eqJS """
import file, { foo } from './file.unknown' assert { type: 'unknown' }
""", """
import file, {
foo
} from './file.unknown' assert {
type: 'unknown'
};
"""
eqJS """
import foo from 'bar' assert {}
""", """
import foo from 'bar' assert {};
"""
test "static export with assertion", ->
eqJS """
export * from 'data:application/json,{"foo":3}' assert { type: 'json' }
""", """
export * from 'data:application/json,{"foo":3}' assert {
type: 'json'
};
"""
eqJS """
export { profile } from './user.json' assert { type: 'json' }
""", """
export {
profile
} from './user.json' assert {
type: 'json'
};
"""