Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 29 additions & 19 deletions docs/v2/annotated-source/grammar.html

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions docs/v2/annotated-source/lexer.html
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,9 @@ <h2 id="tokenizers">Tokenizers</h2>
<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>
Expand Down
30 changes: 25 additions & 5 deletions docs/v2/annotated-source/nodes.html
Original file line number Diff line number Diff line change
Expand Up @@ -5845,11 +5845,11 @@ <h3 id="import-and-export">Import and Export</h3>

<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
Expand Down Expand Up @@ -5880,6 +5880,14 @@ <h3 id="import-and-export">Import and Export</h3>
<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>
Expand All @@ -5892,6 +5900,9 @@ <h3 id="import-and-export">Import and Export</h3>
<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
Expand All @@ -5904,6 +5915,7 @@ <h3 id="import-and-export">Import and Export</h3>
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

Expand Down Expand Up @@ -5965,7 +5977,12 @@ <h3 id="import-and-export">Import and Export</h3>
<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>

Expand Down Expand Up @@ -5994,6 +6011,7 @@ <h3 id="import-and-export">Import and Export</h3>
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
Expand All @@ -6008,11 +6026,13 @@ <h3 id="import-and-export">Import and Export</h3>
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>
Expand Down Expand Up @@ -6148,8 +6168,8 @@ <h3 id="import-and-export">Import and Export</h3>
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()
Expand Down
4 changes: 2 additions & 2 deletions docs/v2/browser-compiler-legacy/coffeescript.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/v2/browser-compiler-modern/coffeescript.js

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions docs/v2/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4268,6 +4268,8 @@ <h2>Modules</h2>
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
Expand All @@ -4279,6 +4281,7 @@ <h2>Modules</h2>

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>
Expand All @@ -4291,6 +4294,8 @@ <h2>Modules</h2>
<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>
Expand All @@ -4302,6 +4307,7 @@ <h2>Modules</h2>

<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">
Expand Down Expand Up @@ -4330,6 +4336,10 @@ <h2>Modules</h2>
each
} from 'underscore';

import dates from './calendar.json' assert {
type: 'json'
};

export default Math;

export var square = function(x) {
Expand Down Expand Up @@ -4366,6 +4376,12 @@ <h2>Modules</h2>
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>;

Expand All @@ -4392,6 +4408,10 @@ <h2>Modules</h2>
<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>) {
Expand Down Expand Up @@ -4428,6 +4448,12 @@ <h2>Modules</h2>
<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>
Expand Down
148 changes: 142 additions & 6 deletions docs/v2/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -2218,6 +2218,31 @@ <h1>CoffeeScript Test Suite</h1>
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'
Expand Down Expand Up @@ -2369,6 +2394,26 @@ <h1>CoffeeScript Test Suite</h1>
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'
Expand Down Expand Up @@ -22988,21 +23033,21 @@ <h1>CoffeeScript Test Suite</h1>
^
'''

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", ->
Expand Down Expand Up @@ -25667,6 +25712,97 @@ <h1>CoffeeScript Test Suite</h1>
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 can’t 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 there’s 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
Expand Down
3 changes: 3 additions & 0 deletions documentation/examples/modules.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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' }
Loading