From 0f241279dc412ff4bb0faa9211233a944465f9b4 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Tue, 5 Feb 2019 17:02:06 +0900 Subject: [PATCH 001/112] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20dependenc?= =?UTF-8?q?ies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.yml | 9 +++---- .vscode/settings.json | 3 ++- README.md | 4 ++-- package.json | 28 ++++++++++------------ src/external/node-event-generator.ts | 6 ++--- src/html/intermediate-tokenizer.ts | 3 --- src/html/parser.ts | 7 ++---- src/parser-services.ts | 4 ++-- src/script/index.ts | 2 +- src/template/index.ts | 36 ++-------------------------- test/fixtures/eslint | 2 +- test/index.js | 15 +++++------- tsconfig.json | 1 - 13 files changed, 37 insertions(+), 83 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index d1ee2dff..3c484428 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,14 +1,11 @@ extends: - plugin:@mysticatea/es2015 - plugin:@mysticatea/+node - - plugin:@mysticatea/+modules + overrides: - - files: "*.ts" - rules: - "@mysticatea/ts/no-use-before-define": "off" - files: "typings/**" rules: - node/no-missing-import: + node/no-missing-import: - error - - allowModules: + - allowModules: - estree diff --git a/.vscode/settings.json b/.vscode/settings.json index 0bcb47f3..e4ba81f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ {"language": "html", "autoFix": true}, {"language": "vue", "autoFix": true}, {"language": "typescript", "autoFix": true} - ] + ], + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/README.md b/README.md index e7e7933c..ce9881ed 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ $ npm install --save-dev eslint vue-eslint-parser - Requires Node.js 6.5.0 or later. - Requires ESLint 5.0.0 or later. - Requires `babel-eslint` 8.1.1 or later if you want it. (optional) -- Requires `typescript-eslint-parser` 21.0.0 or later if you want it. (optional) +- Requires `@typescript-eslint/parser` 1.0.0 or later if you want it. (optional) ## 📖 Usage @@ -82,7 +82,7 @@ For example: { "parser": "vue-eslint-parser", "parserOptions": { - "parser": "typescript-eslint-parser" + "parser": "@typescript-eslint/parser" } } ``` diff --git a/package.json b/package.json index f6054ed6..598da2ca 100644 --- a/package.json +++ b/package.json @@ -13,40 +13,38 @@ "eslint": "^5.0.0" }, "dependencies": { - "debug": "^4.1.0", + "debug": "^4.1.1", "eslint-scope": "^4.0.0", "eslint-visitor-keys": "^1.0.0", - "espree": "^4.1.0", + "espree": "^5.0.0", "esquery": "^1.0.1", "lodash": "^4.17.11" }, "devDependencies": { - "@mysticatea/eslint-plugin": "^7.0.0", + "@mysticatea/eslint-plugin": "^9.0.1", "@types/debug": "0.0.30", "@types/estree": "0.0.38", - "@types/lodash": "^4.14.118", + "@types/lodash": "^4.14.120", "@types/mocha": "^5.2.4", - "@types/node": "^10.12.9", - "acorn": "^6.0.4", - "acorn-jsx": "^5.0.0", + "@types/node": "^10.12.21", + "@typescript-eslint/parser": "^1.2.0", "babel-eslint": "^10.0.1", "chokidar": "^2.0.4", "codecov": "^3.1.0", "cross-spawn": "^6.0.5", "dts-bundle": "^0.7.3", - "eslint": "^5.9.0", + "eslint": "^5.13.0", "fs-extra": "^7.0.1", "mocha": "^5.2.0", - "npm-run-all": "^4.1.3", - "nyc": "^13.1.0", + "npm-run-all": "^4.1.5", + "nyc": "^13.2.0", "opener": "^1.5.1", - "rimraf": "^2.6.2", - "rollup": "^0.67.1", - "rollup-plugin-node-resolve": "^3.4.0", + "rimraf": "^2.6.3", + "rollup": "^1.1.2", + "rollup-plugin-node-resolve": "^4.0.0", "rollup-plugin-sourcemaps": "^0.4.2", "rollup-watch": "^4.3.1", - "typescript": "~3.1.6", - "typescript-eslint-parser": "^21.0.1", + "typescript": "~3.3.1", "wait-on": "^3.2.0", "warun": "^1.0.0" }, diff --git a/src/external/node-event-generator.ts b/src/external/node-event-generator.ts index 0c1eaa2b..c4221247 100644 --- a/src/external/node-event-generator.ts +++ b/src/external/node-event-generator.ts @@ -31,13 +31,13 @@ function getPossibleTypes(parsedSelector: Selector): string[] | null { const typesForComponents = parsedSelector.selectors.map(getPossibleTypes) if (typesForComponents.every(Boolean)) { - return union.apply(null, typesForComponents) + return union(...(typesForComponents as string[][])) } return null } case "compound": { - const typesForComponents = parsedSelector.selectors.map(getPossibleTypes).filter(typesForComponent => typesForComponent) + const typesForComponents = parsedSelector.selectors.map(getPossibleTypes).filter(Boolean) as string[][] // If all of the components could match any type, then the compound could also match any type. if (!typesForComponents.length) { @@ -48,7 +48,7 @@ function getPossibleTypes(parsedSelector: Selector): string[] | null { * If at least one of the components could only match a particular type, the compound could only match * the intersection of those types. */ - return intersection.apply(null, typesForComponents) + return intersection(...typesForComponents) } case "child": diff --git a/src/html/intermediate-tokenizer.ts b/src/html/intermediate-tokenizer.ts index 03c0d9b5..5d072517 100644 --- a/src/html/intermediate-tokenizer.ts +++ b/src/html/intermediate-tokenizer.ts @@ -103,7 +103,6 @@ export class IntermediateTokenizer { public get state(): TokenizerState { return this.tokenizer.state } - //eslint-disable-next-line require-jsdoc public set state(value: TokenizerState) { this.tokenizer.state = value } @@ -114,7 +113,6 @@ export class IntermediateTokenizer { public get namespace(): Namespace { return this.tokenizer.namespace } - //eslint-disable-next-line require-jsdoc public set namespace(value: Namespace) { this.tokenizer.namespace = value } @@ -125,7 +123,6 @@ export class IntermediateTokenizer { public get expressionEnabled(): boolean { return this.tokenizer.expressionEnabled } - //eslint-disable-next-line require-jsdoc public set expressionEnabled(value: boolean) { this.tokenizer.expressionEnabled = value } diff --git a/src/html/parser.ts b/src/html/parser.ts index 91f9c286..f5872171 100644 --- a/src/html/parser.ts +++ b/src/html/parser.ts @@ -187,7 +187,6 @@ export class Parser { private get namespace(): Namespace { return this.tokenizer.namespace } - //eslint-disable-next-line require-jsdoc private set namespace(value: Namespace) { this.tokenizer.namespace = value } @@ -196,11 +195,9 @@ export class Parser { * The current flag of expression enabled. */ // @ts-ignore - //eslint-disable-next-line require-jsdoc private get expressionEnabled(): boolean { return this.tokenizer.expressionEnabled } - //eslint-disable-next-line require-jsdoc private set expressionEnabled(value: boolean) { this.tokenizer.expressionEnabled = value } @@ -321,7 +318,7 @@ export class Parser { * @param token The StartTag token to detect. * @returns The namespace of the new element. */ - //eslint-disable-next-line complexity, require-jsdoc + //eslint-disable-next-line complexity private detectNamespace(token: StartTag): Namespace { const name = token.name let ns = this.namespace @@ -431,7 +428,7 @@ export class Parser { * Handle the start tag token. * @param token The token to handle. */ - //eslint-disable-next-line complexity, require-jsdoc + //eslint-disable-next-line complexity protected StartTag(token: StartTag): void { debug("[html] StartTag %j", token) diff --git a/src/parser-services.ts b/src/parser-services.ts index 3ff443a7..afd3cd46 100644 --- a/src/parser-services.ts +++ b/src/parser-services.ts @@ -66,10 +66,10 @@ export function define(rootAST: ESLintProgram): ParserServices { emitters.set(rootAST, (emitter = new EventEmitter())) const programExitHandler = scriptVisitor["Program:exit"] - scriptVisitor["Program:exit"] = function() { + scriptVisitor["Program:exit"] = node => { try { if (typeof programExitHandler === "function") { - programExitHandler.apply(this, arguments) //eslint-disable-line prefer-rest-params + programExitHandler(node) } // Traverse template body. diff --git a/src/script/index.ts b/src/script/index.ts index 3ea63259..d5fa1292 100644 --- a/src/script/index.ts +++ b/src/script/index.ts @@ -254,7 +254,7 @@ const validDivisionCharRE = /[\w).+\-_$\]]/u * This is a fork of https://github.com/vuejs/vue/blob/2686818beb5728e3b7aa22f47a3b3f0d39d90c8e/src/compiler/parser/filter-parser.js * @param exp the expression to process filters. */ -//eslint-disable-next-line complexity, require-jsdoc +//eslint-disable-next-line complexity function splitFilters(exp: string): string[] { const result: string[] = [] let inSingle = false diff --git a/src/template/index.ts b/src/template/index.ts index e64e7f90..09dbe7e3 100644 --- a/src/template/index.ts +++ b/src/template/index.ts @@ -137,38 +137,6 @@ function createDirectiveKey(node: VIdentifier): VDirectiveKey { return ret } -/** - * Do splice. - * @param items The array to operate. - * @param start The start index. - * @param deleteCount The count of items to delete. - * @param newItems The array of items to insert. - */ -function splice( - items: T[], - start: number, - deleteCount: number, - newItems: T[], -): void { - switch (newItems.length) { - case 0: - items.splice(start, deleteCount) - break - case 1: - items.splice(start, deleteCount, newItems[0]) - break - case 2: - items.splice(start, deleteCount, newItems[0], newItems[1]) - break - default: - Array.prototype.splice.apply( - items, - ([start, deleteCount] as any[]).concat(newItems), - ) - break - } -} - interface HasRange { range: [number, number] } @@ -217,7 +185,7 @@ function replaceTokens( const index = sortedIndexBy(document.tokens, node, byRange0) const count = sortedLastIndexBy(document.tokens, node, byRange1) - index - splice(document.tokens, index, count, newTokens) + document.tokens.splice(index, count, ...newTokens) } /** @@ -234,7 +202,7 @@ function insertComments( } const index = sortedIndexBy(document.comments, newComments[0], byRange0) - splice(document.comments, index, 0, newComments) + document.comments.splice(index, 0, ...newComments) } /** diff --git a/test/fixtures/eslint b/test/fixtures/eslint index f7633b7a..9441ce77 160000 --- a/test/fixtures/eslint +++ b/test/fixtures/eslint @@ -1 +1 @@ -Subproject commit f7633b7a022d9d4e93016f7918f2bb5f9588a32b +Subproject commit 9441ce77b7228f2c4562e158a10905afe11f31f2 diff --git a/test/index.js b/test/index.js index ed85d7c7..84c9cb89 100644 --- a/test/index.js +++ b/test/index.js @@ -232,14 +232,13 @@ describe("Basic tests", () => { assert(messages.length === 0) }) - it("should notify no error with 'typescript-eslint-parser'", () => { + it("should notify no error with '@typescript-eslint/parser'", () => { const cli = new CLIEngine({ cwd: FIXTURE_DIR, envs: ["es6", "node"], parser: PARSER_PATH, parserOptions: { - // - parser: "typescript-eslint-parser", + parser: "@typescript-eslint/parser", }, rules: { semi: ["error", "never"] }, useEslintrc: false, @@ -270,14 +269,13 @@ describe("Basic tests", () => { assert(messages.length === 0) }) - it("should notify no error with 'typescript-eslint-parser'", () => { + it("should notify no error with '@typescript-eslint/parser'", () => { const cli = new CLIEngine({ cwd: FIXTURE_DIR, envs: ["es6", "node"], parser: PARSER_PATH, parserOptions: { - // - parser: "typescript-eslint-parser", + parser: "@typescript-eslint/parser", }, rules: { semi: ["error", "never"] }, useEslintrc: false, @@ -315,15 +313,14 @@ describe("Basic tests", () => { assert(actual === expected) }) - it("should fix 'semi' errors with --fix option with 'typescript-eslint-parser'", () => { + it("should fix 'semi' errors with --fix option with '@typescript-eslint/parser'", () => { const cli = new CLIEngine({ cwd: FIXTURE_DIR, envs: ["es6", "node"], fix: true, parser: PARSER_PATH, parserOptions: { - // - parser: "typescript-eslint-parser", + parser: "@typescript-eslint/parser", }, rules: { semi: ["error", "always"] }, useEslintrc: false, diff --git a/tsconfig.json b/tsconfig.json index c8432660..1cdab4bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "baseUrl": ".", "checkJs": false, "declaration": true, - "diagnostics": true, "forceConsistentCasingInFileNames": true, "inlineSources": true, "lib": [ From ff1a51a4b398f9e5a7bd0840c23427930d951646 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Tue, 5 Feb 2019 17:26:59 +0900 Subject: [PATCH 002/112] =?UTF-8?q?=E2=9C=A8=20support=20v-slot=20[RFC0001?= =?UTF-8?q?]=20(refs=20#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ast.md | 5 +- src/template/index.ts | 4 + test/fixtures/ast/v-slot-default/ast.json | 891 ++++++++++++++ test/fixtures/ast/v-slot-default/source.vue | 5 + .../ast/v-slot-default/token-ranges.json | 25 + test/fixtures/ast/v-slot-default/tree.json | 111 ++ test/fixtures/ast/v-slot-named/ast.json | 1094 +++++++++++++++++ test/fixtures/ast/v-slot-named/source.vue | 7 + .../ast/v-slot-named/token-ranges.json | 31 + test/fixtures/ast/v-slot-named/tree.json | 137 +++ 10 files changed, 2308 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/ast/v-slot-default/ast.json create mode 100644 test/fixtures/ast/v-slot-default/source.vue create mode 100644 test/fixtures/ast/v-slot-default/token-ranges.json create mode 100644 test/fixtures/ast/v-slot-default/tree.json create mode 100644 test/fixtures/ast/v-slot-named/ast.json create mode 100644 test/fixtures/ast/v-slot-named/source.vue create mode 100644 test/fixtures/ast/v-slot-named/token-ranges.json create mode 100644 test/fixtures/ast/v-slot-named/tree.json diff --git a/docs/ast.md b/docs/ast.md index 58b30979..730a007c 100644 --- a/docs/ast.md +++ b/docs/ast.md @@ -130,7 +130,7 @@ interface VFilter <: Node { - `Reference#variable` is the variable which is defined by a `VElement`. If a reference uses a global variable or a member of VM, this is `null`. - `VForExpression` is an expression node like [ForInStatement] but it has an array as `left` property and does not have `body` property. This is the value of [`v-for` directives]. - `VOnExpression` is an expression node like [BlockStatement] but it does not have braces. This is the value of [`v-on` directives] only if the `v-on` directive doesn't have that argument. -- `VSlotScopeExpression` is an expression node like [VariableDeclarator]. This is the value of [`slot-scope` attribute] or the `scope` attribute of `", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-2/ast.json b/test/fixtures/ast/directive-error-2/ast.json new file mode 100644 index 00000000..f59e6a92 --- /dev/null +++ b/test/fixtures/ast/directive-error-2/ast.json @@ -0,0 +1,517 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 43 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 20 + } + }, + "name": "div", + "rawName": "div", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 25 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 20, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 20, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 20, + 22 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 11, + "line": 2 + } + }, + "name": "", + "rawName": "" + }, + "argument": null, + "modifiers": [ + { + "type": "VIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "name": "a", + "rawName": "a" + } + ] + }, + "value": null + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 25, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 32, + 43 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 19 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "value": "div" + }, + { + "type": "HTMLIdentifier", + "range": [ + 20, + 22 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 11, + "line": 2 + } + }, + "value": "v-" + }, + { + "type": "Punctuator", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "column": 11, + "line": 2 + }, + "end": { + "column": 12, + "line": 2 + } + }, + "value": "." + }, + { + "type": "HTMLIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "value": "a" + }, + { + "type": "HTMLTagClose", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 25, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "value": "div" + }, + { + "type": "HTMLTagClose", + "range": [ + 30, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 2, + "column": 20 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 32, + 42 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 42, + 43 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 43, + 44 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [ + { + "message": "Unexpected token '.'", + "index": 22, + "lineNumber": 2, + "column": 11 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-2/source.vue b/test/fixtures/ast/directive-error-2/source.vue new file mode 100644 index 00000000..8f52cc61 --- /dev/null +++ b/test/fixtures/ast/directive-error-2/source.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/ast/directive-error-2/token-ranges.json b/test/fixtures/ast/directive-error-2/token-ranges.json new file mode 100644 index 00000000..1f83196e --- /dev/null +++ b/test/fixtures/ast/directive-error-2/token-ranges.json @@ -0,0 +1,16 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-2/tree.json b/test/fixtures/ast/directive-error-2/tree.json new file mode 100644 index 00000000..64425516 --- /dev/null +++ b/test/fixtures/ast/directive-error-2/tree.json @@ -0,0 +1,67 @@ +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-3/ast.json b/test/fixtures/ast/directive-error-3/ast.json new file mode 100644 index 00000000..b7e95cc6 --- /dev/null +++ b/test/fixtures/ast/directive-error-3/ast.json @@ -0,0 +1,517 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 42 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "name": "div", + "rawName": "div", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 20, + 23 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 20, + 23 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 10, + "line": 2 + } + }, + "name": "bind", + "rawName": ":" + }, + "argument": null, + "modifiers": [ + { + "type": "VIdentifier", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "column": 11, + "line": 2 + }, + "end": { + "column": 12, + "line": 2 + } + }, + "name": "a", + "rawName": "a" + } + ] + }, + "value": null + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 24, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 19 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 30, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 31, + 42 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 19 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "value": "div" + }, + { + "type": "Punctuator", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 10, + "line": 2 + } + }, + "value": ":" + }, + { + "type": "Punctuator", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "column": 10, + "line": 2 + }, + "end": { + "column": 11, + "line": 2 + } + }, + "value": "." + }, + { + "type": "HTMLIdentifier", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "column": 11, + "line": 2 + }, + "end": { + "column": 12, + "line": 2 + } + }, + "value": "a" + }, + { + "type": "HTMLTagClose", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 24, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "value": "div" + }, + { + "type": "HTMLTagClose", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 30, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 31, + 41 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 41, + 42 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 42, + 43 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [ + { + "message": "Unexpected token '.'", + "index": 21, + "lineNumber": 2, + "column": 10 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-3/source.vue b/test/fixtures/ast/directive-error-3/source.vue new file mode 100644 index 00000000..5fc99f7e --- /dev/null +++ b/test/fixtures/ast/directive-error-3/source.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/ast/directive-error-3/token-ranges.json b/test/fixtures/ast/directive-error-3/token-ranges.json new file mode 100644 index 00000000..c93ea59a --- /dev/null +++ b/test/fixtures/ast/directive-error-3/token-ranges.json @@ -0,0 +1,16 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error/tree.json b/test/fixtures/ast/directive-error-3/tree.json similarity index 62% rename from test/fixtures/ast/dynamic-argument-error/tree.json rename to test/fixtures/ast/directive-error-3/tree.json index e2856e9f..9ee91385 100644 --- a/test/fixtures/ast/dynamic-argument-error/tree.json +++ b/test/fixtures/ast/directive-error-3/tree.json @@ -1,7 +1,7 @@ [ { "type": "VElement", - "text": "", + "text": "", "children": [ { "type": "VStartTag", @@ -15,19 +15,19 @@ }, { "type": "VElement", - "text": "", + "text": "
", "children": [ { "type": "VStartTag", - "text": "", + "text": "", "children": [] } ] diff --git a/test/fixtures/ast/directive-error-4/ast.json b/test/fixtures/ast/directive-error-4/ast.json new file mode 100644 index 00000000..3888d0db --- /dev/null +++ b/test/fixtures/ast/directive-error-4/ast.json @@ -0,0 +1,529 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 45 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "name": "div", + "rawName": "div", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 27 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 20, + 26 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 15 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 20, + 26 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 15 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 20, + 22 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 11, + "line": 2 + } + }, + "name": "", + "rawName": "" + }, + "argument": null, + "modifiers": [ + { + "type": "VIdentifier", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "column": 14, + "line": 2 + }, + "end": { + "column": 15, + "line": 2 + } + }, + "name": "b", + "rawName": "b" + } + ] + }, + "value": null + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 27, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 33, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 34, + 45 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 19 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "value": "div" + }, + { + "type": "HTMLIdentifier", + "range": [ + 20, + 22 + ], + "loc": { + "start": { + "column": 9, + "line": 2 + }, + "end": { + "column": 11, + "line": 2 + } + }, + "value": "v-" + }, + { + "type": "Punctuator", + "range": [ + 22, + 25 + ], + "loc": { + "start": { + "column": 11, + "line": 2 + }, + "end": { + "column": 14, + "line": 2 + } + }, + "value": "." + }, + { + "type": "HTMLIdentifier", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "column": 14, + "line": 2 + }, + "end": { + "column": 15, + "line": 2 + } + }, + "value": "b" + }, + { + "type": "HTMLTagClose", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 27, + 32 + ], + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 21 + } + }, + "value": "div" + }, + { + "type": "HTMLTagClose", + "range": [ + 32, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 33, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 34, + 44 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 44, + 45 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 45, + 46 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [ + { + "message": "Unexpected token ':'", + "index": 22, + "lineNumber": 2, + "column": 11 + }, + { + "message": "Unexpected token '.'", + "index": 23, + "lineNumber": 2, + "column": 12 + }, + { + "message": "Unexpected token '.'", + "index": 24, + "lineNumber": 2, + "column": 13 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-4/source.vue b/test/fixtures/ast/directive-error-4/source.vue new file mode 100644 index 00000000..5c69e57f --- /dev/null +++ b/test/fixtures/ast/directive-error-4/source.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/ast/directive-error-4/token-ranges.json b/test/fixtures/ast/directive-error-4/token-ranges.json new file mode 100644 index 00000000..907da872 --- /dev/null +++ b/test/fixtures/ast/directive-error-4/token-ranges.json @@ -0,0 +1,16 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/directive-error-4/tree.json b/test/fixtures/ast/directive-error-4/tree.json new file mode 100644 index 00000000..b24c143a --- /dev/null +++ b/test/fixtures/ast/directive-error-4/tree.json @@ -0,0 +1,67 @@ +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file From 9326fa091aefb4ad022f0cf842c7ac680c117ccc Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 8 Feb 2019 05:39:06 +0900 Subject: [PATCH 009/112] =?UTF-8?q?=E2=9C=A8=20add=20parsing=20error=20abo?= =?UTF-8?q?ut=20invalid=20dynamic=20argument=20(refs=20#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/template/index.ts | 20 + .../ast/dynamic-argument-error-1/ast.json | 632 ++++++++++++++++ .../source.vue | 0 .../token-ranges.json | 19 + .../ast/dynamic-argument-error-1/tree.json | 78 ++ .../ast/dynamic-argument-error-2/ast.json | 674 ++++++++++++++++++ .../ast/dynamic-argument-error-2/source.vue | 3 + .../token-ranges.json | 19 + .../ast/dynamic-argument-error-2/tree.json | 94 +++ 9 files changed, 1539 insertions(+) create mode 100644 test/fixtures/ast/dynamic-argument-error-1/ast.json rename test/fixtures/ast/{dynamic-argument-error => dynamic-argument-error-1}/source.vue (100%) create mode 100644 test/fixtures/ast/dynamic-argument-error-1/token-ranges.json create mode 100644 test/fixtures/ast/dynamic-argument-error-1/tree.json create mode 100644 test/fixtures/ast/dynamic-argument-error-2/ast.json create mode 100644 test/fixtures/ast/dynamic-argument-error-2/source.vue create mode 100644 test/fixtures/ast/dynamic-argument-error-2/token-ranges.json create mode 100644 test/fixtures/ast/dynamic-argument-error-2/tree.json diff --git a/src/template/index.ts b/src/template/index.ts index 02b152e7..a9b1d06d 100644 --- a/src/template/index.ts +++ b/src/template/index.ts @@ -36,6 +36,7 @@ import { const shorthandSign = /^[.:@#]/u const shorthandNameMap = { ":": "bind", ".": "bind", "@": "on", "#": "slot" } +const invalidDynamicArgumentNextChar = /^[\s\r\n=/>]$/u /** * Get the belonging document of the given node. @@ -649,6 +650,25 @@ export function convertToDirective( locationCalculator, ) + const { argument } = directive.key + if ( + argument && + argument.type === "VIdentifier" && + argument.name.startsWith("[") && + invalidDynamicArgumentNextChar.test(code[argument.range[1]]) + ) { + insertError( + document, + new ParseError( + "Dynamic argument cannot contain spaces, '=', '/', or '>'.", + undefined, + argument.range[1], + argument.loc.end.line, + argument.loc.end.column, + ), + ) + } + if (node.value == null) { return } diff --git a/test/fixtures/ast/dynamic-argument-error-1/ast.json b/test/fixtures/ast/dynamic-argument-error-1/ast.json new file mode 100644 index 00000000..6a8e5a06 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-1/ast.json @@ -0,0 +1,632 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 59 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 47 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 36 + } + }, + "name": "button", + "rawName": "button", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 27 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 23, + 37 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 26 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 23, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 20 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "name": "bind", + "rawName": ":" + }, + "argument": { + "type": "VExpressionContainer", + "range": [ + 24, + 31 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 20, + "line": 2 + } + }, + "expression": null, + "references": [] + }, + "modifiers": [] + }, + "value": { + "type": "VExpressionContainer", + "range": [ + 32, + 37 + ], + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 26 + } + }, + "expression": { + "type": "Identifier", + "start": 33, + "end": 36, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "range": [ + 33, + 36 + ], + "name": "foo" + }, + "references": [ + { + "id": { + "type": "Identifier", + "start": 33, + "end": 36, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "range": [ + 33, + 36 + ], + "name": "foo" + }, + "mode": "r" + } + ] + } + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 38, + 47 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 36 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 2, + "column": 36 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 48, + 59 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 22 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "value": "button" + }, + { + "type": "Punctuator", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "value": ":" + }, + { + "type": "HTMLIdentifier", + "range": [ + 24, + 31 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 20, + "line": 2 + } + }, + "value": "[key+!]" + }, + { + "type": "HTMLAssociation", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 21 + } + }, + "value": "" + }, + { + "type": "Punctuator", + "range": [ + 32, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "value": "\"" + }, + { + "type": "Identifier", + "value": "foo", + "start": 33, + "end": 36, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "range": [ + 33, + 36 + ] + }, + { + "type": "Punctuator", + "range": [ + 36, + 37 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 26 + } + }, + "value": "\"" + }, + { + "type": "HTMLTagClose", + "range": [ + 37, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 26 + }, + "end": { + "line": 2, + "column": 27 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 38, + 46 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 35 + } + }, + "value": "button" + }, + { + "type": "HTMLTagClose", + "range": [ + 46, + 47 + ], + "loc": { + "start": { + "line": 2, + "column": 35 + }, + "end": { + "line": 2, + "column": 36 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 2, + "column": 36 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 48, + 58 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 58, + 59 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 59, + 60 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [ + { + "message": "Unexpected end of expression.", + "index": 30, + "lineNumber": 2, + "column": 19 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error/source.vue b/test/fixtures/ast/dynamic-argument-error-1/source.vue similarity index 100% rename from test/fixtures/ast/dynamic-argument-error/source.vue rename to test/fixtures/ast/dynamic-argument-error-1/source.vue diff --git a/test/fixtures/ast/dynamic-argument-error-1/token-ranges.json b/test/fixtures/ast/dynamic-argument-error-1/token-ranges.json new file mode 100644 index 00000000..4c1d9d62 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-1/token-ranges.json @@ -0,0 +1,19 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-1/tree.json b/test/fixtures/ast/dynamic-argument-error-1/tree.json new file mode 100644 index 00000000..e2856e9f --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-1/tree.json @@ -0,0 +1,78 @@ +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-2/ast.json b/test/fixtures/ast/dynamic-argument-error-2/ast.json new file mode 100644 index 00000000..267871be --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-2/ast.json @@ -0,0 +1,674 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 64 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 52 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 41 + } + }, + "name": "button", + "rawName": "button", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 43 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 32 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 23, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 23, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "name": "bind", + "rawName": ":" + }, + "argument": { + "type": "VIdentifier", + "range": [ + 24, + 28 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 17, + "line": 2 + } + }, + "name": "[\"a\"", + "rawName": "[\"a\"" + }, + "modifiers": [] + }, + "value": null + }, + { + "type": "VAttribute", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "directive": false, + "key": { + "type": "VIdentifier", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "name": "+", + "rawName": "+" + }, + "value": null + }, + { + "type": "VAttribute", + "range": [ + 31, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 31 + } + }, + "directive": false, + "key": { + "type": "VIdentifier", + "range": [ + 31, + 36 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "name": "name]", + "rawName": "name]" + }, + "value": { + "type": "VLiteral", + "range": [ + 37, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 26 + }, + "end": { + "line": 2, + "column": 31 + } + }, + "value": "foo" + } + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 43, + 52 + ], + "loc": { + "start": { + "line": 2, + "column": 32 + }, + "end": { + "line": 2, + "column": 41 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 52, + 53 + ], + "loc": { + "start": { + "line": 2, + "column": 41 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 53, + 64 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 22 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "value": "button" + }, + { + "type": "Punctuator", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "value": ":" + }, + { + "type": "HTMLIdentifier", + "range": [ + 24, + 28 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 17, + "line": 2 + } + }, + "value": "[\"a\"" + }, + { + "type": "HTMLIdentifier", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "value": "+" + }, + { + "type": "HTMLIdentifier", + "range": [ + 31, + 36 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "value": "name]" + }, + { + "type": "HTMLAssociation", + "range": [ + 36, + 37 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 26 + } + }, + "value": "" + }, + { + "type": "HTMLLiteral", + "range": [ + 37, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 26 + }, + "end": { + "line": 2, + "column": 31 + } + }, + "value": "foo" + }, + { + "type": "HTMLTagClose", + "range": [ + 42, + 43 + ], + "loc": { + "start": { + "line": 2, + "column": 31 + }, + "end": { + "line": 2, + "column": 32 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 43, + 51 + ], + "loc": { + "start": { + "line": 2, + "column": 32 + }, + "end": { + "line": 2, + "column": 40 + } + }, + "value": "button" + }, + { + "type": "HTMLTagClose", + "range": [ + 51, + 52 + ], + "loc": { + "start": { + "line": 2, + "column": 40 + }, + "end": { + "line": 2, + "column": 41 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 52, + 53 + ], + "loc": { + "start": { + "line": 2, + "column": 41 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 53, + 63 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 63, + 64 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 64, + 65 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [ + { + "message": "unexpected-character-in-attribute-name", + "index": 25, + "lineNumber": 2, + "column": 14 + }, + { + "message": "unexpected-character-in-attribute-name", + "index": 27, + "lineNumber": 2, + "column": 16 + }, + { + "message": "Dynamic argument cannot contain spaces, '=', '/', or '>'.", + "index": 28, + "lineNumber": 2, + "column": 17 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-2/source.vue b/test/fixtures/ast/dynamic-argument-error-2/source.vue new file mode 100644 index 00000000..9c712eba --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-2/source.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/ast/dynamic-argument-error-2/token-ranges.json b/test/fixtures/ast/dynamic-argument-error-2/token-ranges.json new file mode 100644 index 00000000..08d20608 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-2/token-ranges.json @@ -0,0 +1,19 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-2/tree.json b/test/fixtures/ast/dynamic-argument-error-2/tree.json new file mode 100644 index 00000000..abef1aa5 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-2/tree.json @@ -0,0 +1,94 @@ +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file From 3c356d974b4fb49f1f8371282707b40841abe4a7 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 8 Feb 2019 05:46:15 +0900 Subject: [PATCH 010/112] =?UTF-8?q?=F0=9F=94=96=206.0.0-beta.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 598da2ca..ff72e254 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-eslint-parser", - "version": "5.0.0", + "version": "6.0.0-beta.0", "description": "The ESLint custom parser for `.vue` files.", "engines": { "node": ">=6.5" From 28729dde1c1e088b3d0344a95b535210a7fd33a4 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 8 Feb 2019 06:55:24 +0900 Subject: [PATCH 011/112] =?UTF-8?q?=F0=9F=94=96=206.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff72e254..6f79ae42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-eslint-parser", - "version": "6.0.0-beta.0", + "version": "6.0.0", "description": "The ESLint custom parser for `.vue` files.", "engines": { "node": ">=6.5" From 7a1bffda55ea727d002cf2c2bbdb6800bc9a644f Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sun, 10 Feb 2019 02:04:42 +0900 Subject: [PATCH 012/112] =?UTF-8?q?=F0=9F=90=9B=20fix=20wrong=20location?= =?UTF-8?q?=20of=20auto-generated=20.prop=20modifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/template/index.ts | 3 ++- test/fixtures/ast/v-bind-prop-shorthand/ast.json | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/template/index.ts b/src/template/index.ts index a9b1d06d..bb0e2df4 100644 --- a/src/template/index.ts +++ b/src/template/index.ts @@ -185,7 +185,8 @@ function parseDirectiveKeyStatically( directiveKey.name.rawName === "." && !directiveKey.modifiers.some(isPropModifier) ) { - const pos = (directiveKey.argument || directiveKey.name).range[1] + const pos = + (directiveKey.argument || directiveKey.name).range[1] - offset const propModifier = createIdentifier(pos, pos, "prop") directiveKey.modifiers.unshift(propModifier) } diff --git a/test/fixtures/ast/v-bind-prop-shorthand/ast.json b/test/fixtures/ast/v-bind-prop-shorthand/ast.json index 7fddf2d4..ba515f2f 100644 --- a/test/fixtures/ast/v-bind-prop-shorthand/ast.json +++ b/test/fixtures/ast/v-bind-prop-shorthand/ast.json @@ -189,16 +189,16 @@ { "type": "VIdentifier", "range": [ - 42, - 42 + 22, + 22 ], "loc": { "start": { - "column": 31, + "column": 11, "line": 2 }, "end": { - "column": 31, + "column": 11, "line": 2 } }, From fb08ee11b732a4264b6b626cceef111750ebc704 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sun, 10 Feb 2019 02:10:58 +0900 Subject: [PATCH 013/112] =?UTF-8?q?=F0=9F=94=96=206.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f79ae42..573df41f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-eslint-parser", - "version": "6.0.0", + "version": "6.0.1", "description": "The ESLint custom parser for `.vue` files.", "engines": { "node": ">=6.5" From ba72875586379c11a8dc6697bf203caaebf2249d Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sun, 10 Feb 2019 16:56:07 +0900 Subject: [PATCH 014/112] =?UTF-8?q?=F0=9F=90=9B=20fix=20to=20resolve=20ref?= =?UTF-8?q?erences=20in=20dynamic=20arguments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/parser.ts | 12 ++++++++++-- test/variables-references.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/html/parser.ts b/src/html/parser.ts index 61b72854..c4f38c20 100644 --- a/src/html/parser.ts +++ b/src/html/parser.ts @@ -475,8 +475,16 @@ export class Parser { // Resolve references. for (const attribute of element.startTag.attributes) { - if (attribute.directive && attribute.value != null) { - resolveReferences(attribute.value) + if (attribute.directive) { + if ( + attribute.key.argument != null && + attribute.key.argument.type === "VExpressionContainer" + ) { + resolveReferences(attribute.key.argument) + } + if (attribute.value != null) { + resolveReferences(attribute.value) + } } } diff --git a/test/variables-references.js b/test/variables-references.js index 256b6da3..1cb3ba9f 100644 --- a/test/variables-references.js +++ b/test/variables-references.js @@ -328,3 +328,33 @@ describe("Variables of template-scope and references", () => { } }) }) + +describe("Variables of v-for and references of dynamic arguments", () => { + const code = '' + let variables = null + let vForReferences = null + let vBindKeyReferences = null + + before(() => { + const ast = parse( + code, + Object.assign({ filePath: "test.vue" }, PARSER_OPTIONS) + ).ast + variables = ast.templateBody.children[0].variables + vForReferences = + ast.templateBody.children[0].startTag.attributes[0].value.references + vBindKeyReferences = + ast.templateBody.children[0].startTag.attributes[1].key.argument + .references + }) + + it("should have relationship each other", () => { + assert(variables.length === 1) + assert(vForReferences.length === 1) + assert(vBindKeyReferences.length === 1) + assert(variables[0].references.length === 1) + assert(variables[0].references[0] === vBindKeyReferences[0]) + assert(vForReferences[0].variable === null) + assert(vBindKeyReferences[0].variable === variables[0]) + }) +}) From 47c0c1af92f64e96ac33795a54e93a8b4ed6f0b7 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sun, 10 Feb 2019 17:05:02 +0900 Subject: [PATCH 015/112] =?UTF-8?q?=F0=9F=94=96=206.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 573df41f..f9c83f84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-eslint-parser", - "version": "6.0.1", + "version": "6.0.2", "description": "The ESLint custom parser for `.vue` files.", "engines": { "node": ">=6.5" From 4d734ecc37d74d682b49cdad3f38e639fc3d4012 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Thu, 28 Feb 2019 16:55:22 +0900 Subject: [PATCH 016/112] =?UTF-8?q?=F0=9F=90=9B=20fix=20dot=20in=20dynamic?= =?UTF-8?q?=20arguments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/template/index.ts | 47 +- .../ast/dynamic-argument-dot/ast.json | 786 ++++++++++++++++++ .../ast/dynamic-argument-dot/source.vue | 3 + .../dynamic-argument-dot/token-ranges.json | 23 + .../ast/dynamic-argument-dot/tree.json | 95 +++ .../ast/dynamic-argument-error-2/ast.json | 2 +- .../ast/dynamic-argument-error-4/ast.json | 327 ++++++++ .../ast/dynamic-argument-error-4/source.vue | 2 + .../token-ranges.json | 8 + .../ast/dynamic-argument-error-4/tree.json | 52 ++ .../ast/dynamic-argument-error-5/ast.json | 327 ++++++++ .../ast/dynamic-argument-error-5/source.vue | 2 + .../token-ranges.json | 8 + .../ast/dynamic-argument-error-5/tree.json | 52 ++ 14 files changed, 1716 insertions(+), 18 deletions(-) create mode 100644 test/fixtures/ast/dynamic-argument-dot/ast.json create mode 100644 test/fixtures/ast/dynamic-argument-dot/source.vue create mode 100644 test/fixtures/ast/dynamic-argument-dot/token-ranges.json create mode 100644 test/fixtures/ast/dynamic-argument-dot/tree.json create mode 100644 test/fixtures/ast/dynamic-argument-error-4/ast.json create mode 100644 test/fixtures/ast/dynamic-argument-error-4/source.vue create mode 100644 test/fixtures/ast/dynamic-argument-error-4/token-ranges.json create mode 100644 test/fixtures/ast/dynamic-argument-error-4/tree.json create mode 100644 test/fixtures/ast/dynamic-argument-error-5/ast.json create mode 100644 test/fixtures/ast/dynamic-argument-error-5/source.vue create mode 100644 test/fixtures/ast/dynamic-argument-error-5/token-ranges.json create mode 100644 test/fixtures/ast/dynamic-argument-error-5/tree.json diff --git a/src/template/index.ts b/src/template/index.ts index bb0e2df4..ae776770 100644 --- a/src/template/index.ts +++ b/src/template/index.ts @@ -137,12 +137,21 @@ function parseDirectiveKeyStatically( } } - const [nameOrArgument, ...modifiers] = text + if (directiveKey.name != null && text[i] === "[") { + // Dynamic argument. + const len = text.slice(i).lastIndexOf("]") + if (len !== -1) { + directiveKey.argument = createIdentifier(i, i + len + 1) + i = i + len + 1 + (text[i + len + 1] === "." ? 1 : 0) + } + } + + const modifiers = text .slice(i) .split(".") .map(modifierName => { const modifier = createIdentifier(i, i + modifierName.length) - if (modifierName === "") { + if (modifierName === "" && i < text.length) { insertError( document, new ParseError( @@ -159,9 +168,9 @@ function parseDirectiveKeyStatically( }) if (directiveKey.name == null) { - directiveKey.name = nameOrArgument - } else if (nameOrArgument.name !== "") { - directiveKey.argument = nameOrArgument + directiveKey.name = modifiers.shift()! + } else if (directiveKey.argument == null && modifiers[0].name !== "") { + directiveKey.argument = modifiers.shift() || null } directiveKey.modifiers = modifiers.filter(isNotEmptyModifier) @@ -655,19 +664,23 @@ export function convertToDirective( if ( argument && argument.type === "VIdentifier" && - argument.name.startsWith("[") && - invalidDynamicArgumentNextChar.test(code[argument.range[1]]) + argument.name.startsWith("[") ) { - insertError( - document, - new ParseError( - "Dynamic argument cannot contain spaces, '=', '/', or '>'.", - undefined, - argument.range[1], - argument.loc.end.line, - argument.loc.end.column, - ), - ) + const nextChar = code[argument.range[1]] + if (nextChar == null || invalidDynamicArgumentNextChar.test(nextChar)) { + const char = + nextChar == null ? "EOF" : JSON.stringify(nextChar).slice(1, -1) + insertError( + document, + new ParseError( + `Dynamic argument cannot contain the '${char}' character.`, + undefined, + argument.range[1], + argument.loc.end.line, + argument.loc.end.column, + ), + ) + } } if (node.value == null) { diff --git a/test/fixtures/ast/dynamic-argument-dot/ast.json b/test/fixtures/ast/dynamic-argument-dot/ast.json new file mode 100644 index 00000000..9ba66f85 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-dot/ast.json @@ -0,0 +1,786 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 62 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 50 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 39 + } + }, + "name": "button", + "rawName": "button", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 41 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 23, + 40 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 29 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 23, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "name": "bind", + "rawName": ":" + }, + "argument": { + "type": "VExpressionContainer", + "range": [ + 24, + 34 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 23, + "line": 2 + } + }, + "expression": { + "type": "MemberExpression", + "start": 25, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "range": [ + 25, + 33 + ], + "object": { + "type": "Identifier", + "start": 25, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "range": [ + 25, + 28 + ], + "name": "obj" + }, + "property": { + "type": "Identifier", + "start": 29, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "range": [ + 29, + 33 + ], + "name": "prop" + }, + "computed": false + }, + "references": [ + { + "id": { + "type": "Identifier", + "start": 25, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "range": [ + 25, + 28 + ], + "name": "obj" + }, + "mode": "r" + } + ] + }, + "modifiers": [] + }, + "value": { + "type": "VExpressionContainer", + "range": [ + 35, + 40 + ], + "loc": { + "start": { + "line": 2, + "column": 24 + }, + "end": { + "line": 2, + "column": 29 + } + }, + "expression": { + "type": "Identifier", + "start": 36, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 28 + } + }, + "range": [ + 36, + 39 + ], + "name": "foo" + }, + "references": [ + { + "id": { + "type": "Identifier", + "start": 36, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 28 + } + }, + "range": [ + 36, + 39 + ], + "name": "foo" + }, + "mode": "r" + } + ] + } + } + ] + }, + "children": [], + "endTag": { + "type": "VEndTag", + "range": [ + 41, + 50 + ], + "loc": { + "start": { + "line": 2, + "column": 30 + }, + "end": { + "line": 2, + "column": 39 + } + } + }, + "variables": [] + }, + { + "type": "VText", + "range": [ + 50, + 51 + ], + "loc": { + "start": { + "line": 2, + "column": 39 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 51, + 62 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 11 + } + } + }, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 22 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "value": "button" + }, + { + "type": "Punctuator", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "value": ":" + }, + { + "type": "Punctuator", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "value": "[" + }, + { + "type": "Identifier", + "value": "obj", + "start": 25, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "range": [ + 25, + 28 + ] + }, + { + "type": "Punctuator", + "value": ".", + "start": 28, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "range": [ + 28, + 29 + ] + }, + { + "type": "Identifier", + "value": "prop", + "start": 29, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "range": [ + 29, + 33 + ] + }, + { + "type": "Punctuator", + "range": [ + 33, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "value": "]" + }, + { + "type": "HTMLAssociation", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 2, + "column": 23 + }, + "end": { + "line": 2, + "column": 24 + } + }, + "value": "" + }, + { + "type": "Punctuator", + "range": [ + 35, + 36 + ], + "loc": { + "start": { + "line": 2, + "column": 24 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "value": "\"" + }, + { + "type": "Identifier", + "value": "foo", + "start": 36, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 28 + } + }, + "range": [ + 36, + 39 + ] + }, + { + "type": "Punctuator", + "range": [ + 39, + 40 + ], + "loc": { + "start": { + "line": 2, + "column": 28 + }, + "end": { + "line": 2, + "column": 29 + } + }, + "value": "\"" + }, + { + "type": "HTMLTagClose", + "range": [ + 40, + 41 + ], + "loc": { + "start": { + "line": 2, + "column": 29 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "value": "" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 41, + 49 + ], + "loc": { + "start": { + "line": 2, + "column": 30 + }, + "end": { + "line": 2, + "column": 38 + } + }, + "value": "button" + }, + { + "type": "HTMLTagClose", + "range": [ + 49, + 50 + ], + "loc": { + "start": { + "line": 2, + "column": 38 + }, + "end": { + "line": 2, + "column": 39 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 50, + 51 + ], + "loc": { + "start": { + "line": 2, + "column": 39 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 51, + 61 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 61, + 62 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 62, + 63 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-dot/source.vue b/test/fixtures/ast/dynamic-argument-dot/source.vue new file mode 100644 index 00000000..d1ff60cc --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-dot/source.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/ast/dynamic-argument-dot/token-ranges.json b/test/fixtures/ast/dynamic-argument-dot/token-ranges.json new file mode 100644 index 00000000..f69491e2 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-dot/token-ranges.json @@ -0,0 +1,23 @@ +[ + "", + "\n ", + "", + "", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-dot/tree.json b/test/fixtures/ast/dynamic-argument-dot/tree.json new file mode 100644 index 00000000..67360bb8 --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-dot/tree.json @@ -0,0 +1,95 @@ +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-2/ast.json b/test/fixtures/ast/dynamic-argument-error-2/ast.json index 267871be..a337e3c1 100644 --- a/test/fixtures/ast/dynamic-argument-error-2/ast.json +++ b/test/fixtures/ast/dynamic-argument-error-2/ast.json @@ -664,7 +664,7 @@ "column": 16 }, { - "message": "Dynamic argument cannot contain spaces, '=', '/', or '>'.", + "message": "Dynamic argument cannot contain the ' ' character.", "index": 28, "lineNumber": 2, "column": 17 diff --git a/test/fixtures/ast/dynamic-argument-error-4/ast.json b/test/fixtures/ast/dynamic-argument-error-4/ast.json new file mode 100644 index 00000000..a4b2104e --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-4/ast.json @@ -0,0 +1,327 @@ +{ + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "name": "template", + "rawName": "template", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "VElement", + "range": [ + 15, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "name": "button", + "rawName": "button", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 15, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 23, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "directive": true, + "key": { + "type": "VDirectiveKey", + "range": [ + 23, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "name": { + "type": "VIdentifier", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "name": "bind", + "rawName": ":" + }, + "argument": { + "type": "VIdentifier", + "range": [ + 24, + 28 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 17, + "line": 2 + } + }, + "name": "[obj", + "rawName": "[obj" + }, + "modifiers": [] + }, + "value": null + } + ] + }, + "children": [], + "endTag": null, + "variables": [] + } + ], + "endTag": null, + "variables": [], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLTagOpen", + "range": [ + 15, + 22 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "value": "button" + }, + { + "type": "Punctuator", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "column": 12, + "line": 2 + }, + "end": { + "column": 13, + "line": 2 + } + }, + "value": ":" + }, + { + "type": "HTMLIdentifier", + "range": [ + 24, + 28 + ], + "loc": { + "start": { + "column": 13, + "line": 2 + }, + "end": { + "column": 17, + "line": 2 + } + }, + "value": "[obj" + } + ], + "comments": [], + "errors": [ + { + "message": "Dynamic argument cannot contain the '\\n' character.", + "index": 28, + "lineNumber": 2, + "column": 17 + }, + { + "message": "eof-in-tag", + "index": 29, + "lineNumber": 3, + "column": 0 + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/ast/dynamic-argument-error-4/source.vue b/test/fixtures/ast/dynamic-argument-error-4/source.vue new file mode 100644 index 00000000..d859f01c --- /dev/null +++ b/test/fixtures/ast/dynamic-argument-error-4/source.vue @@ -0,0 +1,2 @@ +