diff --git a/.gitignore b/.gitignore index 6ea559ee..de0f22fd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ /npm-debug.log /test.js /test/fixtures/espree-v8/node_modules +.yarn +.yarnrc.yml +yarn.lock \ No newline at end of file diff --git a/package.json b/package.json index 50dc44cb..fee5973e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,13 @@ "index.*" ], "peerDependencies": { - "eslint": ">=5.0.0" + "eslint": ">=5.0.0", + "pug-lexer": ">=5.0.0" + }, + "peerDependenciesMeta": { + "pug-lexer": { + "optional": true + } }, "dependencies": { "debug": "^4.1.1", @@ -52,8 +58,10 @@ "nyc": "^14.0.0", "opener": "^1.5.1", "prettier": "^2.3.1", + "pug-lexer": "^5.0.1", "rimraf": "^2.6.3", "rollup": "^1.1.2", + "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^4.0.0", "rollup-plugin-sourcemaps": "^0.4.2", "ts-node": "^8.1.0", diff --git a/rollup.config.js b/rollup.config.js index ccd8c5ff..3c623e44 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -5,6 +5,7 @@ */ import resolve from "rollup-plugin-node-resolve" import sourcemaps from "rollup-plugin-sourcemaps" +import commonjs from "rollup-plugin-commonjs" const pkg = require("./package.json") const deps = new Set( @@ -23,6 +24,6 @@ export default { * See LICENSE file in root directory for full license. */`, }, - plugins: [sourcemaps(), resolve()], + plugins: [sourcemaps(), resolve(), commonjs()], external: id => deps.has(id) || id.startsWith("lodash"), } diff --git a/src/ast/nodes.ts b/src/ast/nodes.ts index a6c1c647..98b63063 100644 --- a/src/ast/nodes.ts +++ b/src/ast/nodes.ts @@ -3,6 +3,7 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ +import type { Token as PugToken } from "pug-lexer" import type { ScopeManager } from "eslint-scope" import type { ParseError } from "./errors" import type { HasLocation } from "./locations" @@ -860,6 +861,7 @@ export interface VDocumentFragment type: "VDocumentFragment" parent: null children: (VElement | VText | VExpressionContainer | VStyleElement)[] + pugTokens?: PugToken[] } /** diff --git a/src/html/parser.ts b/src/html/parser.ts index 538e5f24..e022b5e4 100644 --- a/src/html/parser.ts +++ b/src/html/parser.ts @@ -51,6 +51,7 @@ import { getScriptParser, getParserLangFromSFC, } from "../common/parser-options" +import lex from "pug-lexer" const DIRECTIVE_NAME = /^(?:v-|[.:@#]).*[^.:@#]$/u const DT_DD = /^d[dt]$/u @@ -300,6 +301,19 @@ export class Parser { } this.postProcessesForScript = [] + try { + // Process pug + const match = + /(?.*)<\/template>/isu.exec( + this.text, + ) + if (match && match.groups && match.groups.content) { + doc.pugTokens = lex(match.groups.content) + } + } catch { + /* ignore */ + } + return doc } diff --git a/src/index.ts b/src/index.ts index 6bf09da3..8a90776c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -103,7 +103,8 @@ export function parseForESLint( errors: rootAST.errors, } const templateBody = - template != null && templateLang === "html" + template != null && + (templateLang === "html" || templateLang === "pug") ? Object.assign(template, concreteInfo) : undefined diff --git a/test/fixtures/ast/pug/ast.json b/test/fixtures/ast/pug/ast.json index 0905cb4d..4be2cf1e 100644 --- a/test/fixtures/ast/pug/ast.json +++ b/test/fixtures/ast/pug/ast.json @@ -19,5 +19,530 @@ "body": [], "sourceType": "script", "comments": [], - "tokens": [] + "tokens": [], + "templateBody": { + "type": "VElement", + "range": [ + 0, + 57 + ], + "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, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "selfClosing": false, + "attributes": [ + { + "type": "VAttribute", + "range": [ + 10, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "directive": false, + "key": { + "type": "VIdentifier", + "range": [ + 10, + 14 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 14 + } + }, + "name": "lang", + "rawName": "lang" + }, + "value": { + "type": "VLiteral", + "range": [ + 15, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "value": "pug" + } + } + ] + }, + "children": [ + { + "type": "VText", + "range": [ + 21, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "value": "\np " + }, + { + "type": "VExpressionContainer", + "range": [ + 24, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "expression": { + "type": "Identifier", + "start": 27, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "range": [ + 27, + 35 + ], + "name": "greeting" + }, + "references": [ + { + "id": { + "type": "Identifier", + "start": 27, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "range": [ + 27, + 35 + ], + "name": "greeting" + }, + "mode": "r" + } + ] + }, + { + "type": "VText", + "range": [ + 38, + 46 + ], + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": " World!\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 46, + 57 + ], + "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": "HTMLIdentifier", + "range": [ + 10, + 14 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 14 + } + }, + "value": "lang" + }, + { + "type": "HTMLAssociation", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + }, + "value": "" + }, + { + "type": "HTMLLiteral", + "range": [ + 15, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "value": "pug" + }, + { + "type": "HTMLTagClose", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 2, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLRawText", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "value": "p" + }, + { + "type": "HTMLWhitespace", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "value": " " + }, + { + "type": "VExpressionStart", + "range": [ + 24, + 26 + ], + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "value": "{{" + }, + { + "type": "Identifier", + "value": "greeting", + "start": 27, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "range": [ + 27, + 35 + ] + }, + { + "type": "VExpressionEnd", + "range": [ + 36, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "value": "}}" + }, + { + "type": "HTMLWhitespace", + "range": [ + 38, + 39 + ], + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "value": " " + }, + { + "type": "HTMLRawText", + "range": [ + 39, + 45 + ], + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "value": "World!" + }, + { + "type": "HTMLWhitespace", + "range": [ + 45, + 46 + ], + "loc": { + "start": { + "line": 2, + "column": 23 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 46, + 56 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "template" + }, + { + "type": "HTMLTagClose", + "range": [ + 56, + 57 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 57, + 58 + ], + "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/pug/source.vue b/test/fixtures/ast/pug/source.vue index ab1c2e5e..3cabe675 100644 --- a/test/fixtures/ast/pug/source.vue +++ b/test/fixtures/ast/pug/source.vue @@ -1,3 +1,3 @@ diff --git a/test/fixtures/ast/pug/token-ranges.json b/test/fixtures/ast/pug/token-ranges.json index 0637a088..a99867e3 100644 --- a/test/fixtures/ast/pug/token-ranges.json +++ b/test/fixtures/ast/pug/token-ranges.json @@ -1 +1,19 @@ -[] \ No newline at end of file +[ + "", + "\n", + "p", + " ", + "{{", + "greeting", + "}}", + " ", + "World!", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/ast/pug/tree.json b/test/fixtures/ast/pug/tree.json index 0637a088..4cb94d09 100644 --- a/test/fixtures/ast/pug/tree.json +++ b/test/fixtures/ast/pug/tree.json @@ -1 +1,56 @@ -[] \ No newline at end of file +[ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + } +] \ No newline at end of file