diff --git a/src/jshint.js b/src/jshint.js index 96439b702a..5f22b56d6e 100644 --- a/src/jshint.js +++ b/src/jshint.js @@ -5528,7 +5528,23 @@ var JSHINT = (function() { return this; }).exps = true; - stmt("import", function(context) { + prefix("import", function(context) { + var mp = metaProperty(context, "meta", function() { + if (!state.inES11(true)) { + warning("W119", state.tokens.prev, "import.meta", "11"); + } + if (!state.option.module) { + error("E068", state.tokens.prev); + } + }); + + if (!mp) { + return state.syntax["(identifier)"].nud.call(this, context); + } + return mp; + }); + + var importSymbol = stmt("import", function(context) { if (!state.funct["(scope)"].block.isGlobal()) { error("E053", state.tokens.curr, "Import"); } @@ -5630,7 +5646,13 @@ var JSHINT = (function() { // } return this; - }).exps = true; + }); + importSymbol.exps = true; + importSymbol.reserved = true; + importSymbol.meta = { isFutureReservedWord: true, es5: true }; + importSymbol.useFud = function() { + return !(checkPunctuator(state.tokens.next, ".") && peek().identifier); + }; stmt("export", function(context) { var ok = true; @@ -5837,7 +5859,6 @@ var JSHINT = (function() { FutureReservedWord("float"); FutureReservedWord("goto"); FutureReservedWord("implements", { es5: true, strictOnly: true }); - FutureReservedWord("import", { es5: true }); FutureReservedWord("int"); FutureReservedWord("interface", { es5: true, strictOnly: true }); FutureReservedWord("long"); diff --git a/src/messages.js b/src/messages.js index e541cdeb19..242bc49368 100644 --- a/src/messages.js +++ b/src/messages.js @@ -83,7 +83,8 @@ var errors = { E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + "enable strict mode.", E066: "Asynchronous iteration is only available with for-of loops.", - E067: "Malformed numeric literal: '{a}'." + E067: "Malformed numeric literal: '{a}'.", + E068: "import.meta may only be used in module code." }; var warnings = { diff --git a/src/options.js b/src/options.js index ab9c26a34f..f45e9b6206 100644 --- a/src/options.js +++ b/src/options.js @@ -1051,7 +1051,8 @@ exports.val = { * - `10` - To enable language features introduced by ECMAScript * 10](https://www.ecma-international.org/ecma-262/10.0/index.html). * Notable additions: optional catch bindings. - * - `11` - To enable language features introduced by ECMAScript 11. + * - `11` - To enable language features introduced by ECMAScript 11. Notable + * additions: `import.meta`. */ esversion: 5 }; diff --git a/tests/test262/expectations.txt b/tests/test262/expectations.txt index dc934a124e..ca1d3000e8 100644 --- a/tests/test262/expectations.txt +++ b/tests/test262/expectations.txt @@ -1532,12 +1532,6 @@ test/language/expressions/dynamic-import/reuse-namespace-object.js(default) test/language/expressions/dynamic-import/reuse-namespace-object.js(strict mode) test/language/expressions/dynamic-import/update-to-dynamic-import.js(default) test/language/expressions/dynamic-import/update-to-dynamic-import.js(strict mode) -test/language/expressions/import.meta/distinct-for-each-module.js(default) -test/language/expressions/import.meta/distinct-for-each-module.js(strict mode) -test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js(default) -test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js(strict mode) -test/language/expressions/import.meta/same-object-returned.js(default) -test/language/expressions/import.meta/same-object-returned.js(strict mode) test/language/statements/class/classelementname-abrupt-completion.js(default) test/language/statements/class/classelementname-abrupt-completion.js(strict mode) test/language/statements/class/static-classelementname-abrupt-completion.js(default) @@ -5193,10 +5187,6 @@ test/language/expressions/dynamic-import/usage/top-level-import-then-returns-the test/language/expressions/dynamic-import/usage/top-level-import-then-returns-thenable.js(strict mode) test/language/expressions/dynamic-import/usage/top-level-import-then-specifier-tostring.js(default) test/language/expressions/dynamic-import/usage/top-level-import-then-specifier-tostring.js(strict mode) -test/language/expressions/import.meta/syntax/goal-module-nested-function.js(default) -test/language/expressions/import.meta/syntax/goal-module-nested-function.js(strict mode) -test/language/expressions/import.meta/syntax/goal-module.js(default) -test/language/expressions/import.meta/syntax/goal-module.js(strict mode) test/language/statements/class/accessor-name-inst/literal-string-unicode-escape.js(default) test/language/statements/class/accessor-name-inst/literal-string-unicode-escape.js(strict mode) test/language/statements/class/accessor-name-static/literal-string-unicode-escape.js(default) @@ -10536,4 +10526,8 @@ test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref-i test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref-init.js(default) test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref-init.js(strict mode) test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref.js(default) -test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref.js(strict mode) \ No newline at end of file +test/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref.js(strict mode) +test/language/expressions/import.meta/syntax/escape-sequence-import.js(default) +test/language/expressions/import.meta/syntax/escape-sequence-import.js(strict mode) +test/language/expressions/import.meta/syntax/escape-sequence-meta.js(default) +test/language/expressions/import.meta/syntax/escape-sequence-meta.js(strict mode) \ No newline at end of file diff --git a/tests/unit/parser.js b/tests/unit/parser.js index c1c8159237..2533c36ebc 100644 --- a/tests/unit/parser.js +++ b/tests/unit/parser.js @@ -10226,3 +10226,61 @@ exports.asyncIteration = function (test) { test.done(); }; + +exports.importMeta = function (test) { + TestRun(test) + .addError(1, 6, "Expected an identifier and instead saw 'import' (a reserved word).") + .test("void import;"); + + TestRun(test) + .addError(1, 6, "Expected an identifier and instead saw 'import' (a reserved word).") + .test( + "void import;", + { esversion: 11 } + ); + + TestRun(test) + .addError(1, 12, "'import.meta' is only available in ES11 (use 'esversion: 11').") + .addError(1, 12, "import.meta may only be used in module code.") + .test( + "void import.meta;", + { esversion: 10 } + ); + + TestRun(test) + .addError(1, 12, "import.meta may only be used in module code.") + .test( + "void import.meta;", + { esversion: 11 } + ); + + TestRun(test, "valid usage (expression position)") + .test( + "void import.meta;", + { esversion: 11, module: true } + ); + + TestRun(test, "valid usage (statement position)") + .addError(1, 8, "Expected an assignment or function call and instead saw an expression.") + .test( + "import.meta;", + { esversion: 11, module: true } + ); + + TestRun(test, "Other property name (expression position)") + .addError(1, 12, "Invalid meta property: 'import.target'.") + .test( + "void import.target;", + { esversion: 11, module: true } + ); + + TestRun(test, "Other property name (statement position)") + .addError(1, 7, "Invalid meta property: 'import.target'.") + .addError(1, 8, "Expected an assignment or function call and instead saw an expression.") + .test( + "import.target;", + { esversion: 11, module: true } + ); + + test.done(); +};