@vue/language-plugin-pug 3.2.1 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,39 +1,6 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  const source_map_1 = require("@volar/source-map");
36
- const pug = __importStar(require("volar-service-pug/lib/languageService"));
3
+ const baseParse_1 = require("./lib/baseParse");
37
4
  const classRegex = /^class\s*=/;
38
5
  const plugin = ({ modules }) => {
39
6
  const CompilerDOM = modules['@vue/compiler-dom'];
@@ -72,74 +39,68 @@ const plugin = ({ modules }) => {
72
39
  },
73
40
  compileSFCTemplate(lang, template, options) {
74
41
  if (lang === 'pug') {
75
- let pugFile;
42
+ let parsed;
76
43
  let baseOffset = 0;
77
44
  const minIndent = calculateMinIndent(template);
78
45
  if (minIndent === 0) {
79
- pugFile = pug.baseParse(template);
46
+ parsed = (0, baseParse_1.baseParse)(template);
80
47
  }
81
48
  else {
82
- pugFile = pug.baseParse(`template\n${template}`);
49
+ parsed = (0, baseParse_1.baseParse)(`template\n${template}`);
83
50
  baseOffset = 'template\n'.length;
84
- pugFile.htmlCode = ' '.repeat('<template>'.length)
85
- + pugFile.htmlCode.slice('<template>'.length, -'</template>'.length)
51
+ parsed.htmlCode = ' '.repeat('<template>'.length)
52
+ + parsed.htmlCode.slice('<template>'.length, -'</template>'.length)
86
53
  + ' '.repeat('</template>'.length);
87
54
  }
88
- const map = new source_map_1.SourceMap(pugFile.mappings);
89
- const ast = CompilerDOM.parse(pugFile.htmlCode, {
55
+ const map = new source_map_1.SourceMap(parsed.mappings);
56
+ let ast = CompilerDOM.parse(parsed.htmlCode, {
90
57
  ...options,
91
58
  comments: true,
92
59
  onWarn(warning) {
93
- options.onWarn?.(createProxyObject(warning));
60
+ if (warning.loc) {
61
+ warning.loc.start.offset = toPugOffset(warning.loc.start.offset);
62
+ warning.loc.end.offset = toPugOffset(warning.loc.end.offset);
63
+ }
64
+ options.onWarn?.(warning);
94
65
  },
95
66
  onError(error) {
96
67
  // #5099
97
68
  if (error.code === 2
98
- && classRegex.test(pugFile.htmlCode.slice(error.loc?.start.offset))) {
69
+ && classRegex.test(parsed.htmlCode.slice(error.loc?.start.offset))) {
99
70
  return;
100
71
  }
101
- options.onError?.(createProxyObject(error));
72
+ if (error.loc) {
73
+ error.loc.start.offset = toPugOffset(error.loc.start.offset);
74
+ error.loc.end.offset = toPugOffset(error.loc.end.offset);
75
+ }
76
+ options.onError?.(error);
102
77
  },
103
78
  });
104
79
  CompilerDOM.transform(ast, options);
80
+ const visited = new Set();
81
+ visit(ast);
105
82
  return {
106
- ast: createProxyObject(ast),
83
+ ast,
107
84
  code: '',
108
85
  preamble: '',
109
86
  };
110
- function createProxyObject(target) {
111
- const proxys = new WeakMap();
112
- return new Proxy(target, {
113
- get(target, prop, receiver) {
114
- if (prop === 'getClassOffset') {
115
- // div.foo#baz.bar
116
- // ^^^ ^^^
117
- // class=" foo bar"
118
- // ^^^ ^^^
119
- // NOTE: we need to expose source offset getter
120
- return function (startOffset) {
121
- return getOffset(target.offset + startOffset);
122
- };
87
+ function visit(obj) {
88
+ for (const key in obj) {
89
+ const value = obj[key];
90
+ if (value && typeof value === 'object') {
91
+ if (visited.has(value)) {
92
+ continue;
123
93
  }
124
- if (prop === 'offset') {
125
- return getOffset(target.offset);
94
+ visited.add(value);
95
+ if ('offset' in value && typeof value.offset === 'number') {
96
+ const originalOffset = value.offset;
97
+ value.offset = toPugOffset(originalOffset);
126
98
  }
127
- const value = Reflect.get(target, prop, receiver);
128
- if (typeof value === 'object' && value !== null) {
129
- let proxyed = proxys.get(value);
130
- if (proxyed) {
131
- return proxyed;
132
- }
133
- proxyed = createProxyObject(value);
134
- proxys.set(value, proxyed);
135
- return proxyed;
136
- }
137
- return value;
138
- },
139
- });
99
+ visit(value);
100
+ }
101
+ }
140
102
  }
141
- function getOffset(offset) {
142
- const htmlOffset = offset;
103
+ function toPugOffset(htmlOffset) {
143
104
  const nums = [];
144
105
  for (const mapped of map.toSourceLocation(htmlOffset)) {
145
106
  nums.push(mapped[0] - baseOffset);
@@ -0,0 +1,67 @@
1
+ import { TextDocument } from 'vscode-languageserver-textdocument';
2
+ export declare function baseParse(pugCode: string): {
3
+ htmlCode: string;
4
+ mappings: import("@volar/source-map").Mapping<any>[];
5
+ pugTextDocument: TextDocument;
6
+ error: {
7
+ code: string;
8
+ msg: string;
9
+ line: number;
10
+ column: number;
11
+ filename: string;
12
+ } | undefined;
13
+ ast: Node | undefined;
14
+ emptyLineEnds: number[];
15
+ };
16
+ export type Node = BlockNode | MixinNode | TagNode | TextNode | CommentNode | BlockCommentNode;
17
+ export interface BlockNode {
18
+ type: 'Block';
19
+ nodes: Node[];
20
+ line: number;
21
+ }
22
+ export interface TagNode {
23
+ type: 'Tag';
24
+ name: string;
25
+ selfClosing: boolean;
26
+ block: BlockNode;
27
+ attrs: {
28
+ name: string;
29
+ val: string | true;
30
+ line: number;
31
+ column: number;
32
+ mustEscape: boolean;
33
+ }[];
34
+ attributeBlocks: {}[];
35
+ isInline: boolean;
36
+ line: number;
37
+ column: number;
38
+ }
39
+ export interface TextNode {
40
+ type: 'Text';
41
+ val: string;
42
+ line: number;
43
+ column: number;
44
+ }
45
+ export interface CommentNode {
46
+ type: 'Comment';
47
+ val: string;
48
+ buffer: boolean;
49
+ line: number;
50
+ column: number;
51
+ }
52
+ export interface BlockCommentNode {
53
+ type: 'BlockComment';
54
+ block: BlockNode;
55
+ val: string;
56
+ buffer: boolean;
57
+ line: number;
58
+ column: number;
59
+ }
60
+ export interface MixinNode {
61
+ type: 'Mixin';
62
+ name: string;
63
+ args: null;
64
+ block: BlockNode | null;
65
+ line: number;
66
+ column: number;
67
+ }
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.baseParse = baseParse;
7
+ const muggle_string_1 = require("muggle-string");
8
+ const pug_lexer_1 = __importDefault(require("pug-lexer"));
9
+ const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
10
+ const buildMappings_1 = require("./buildMappings");
11
+ const pugParser = require('pug-parser');
12
+ function baseParse(pugCode) {
13
+ const fileName = 'file.pug';
14
+ const pugTextDocument = vscode_languageserver_textdocument_1.TextDocument.create('file:///file.pug', 'pug', 0, pugCode);
15
+ const codes = [];
16
+ let error;
17
+ let emptyLineEnds = [];
18
+ let attrsBlocks;
19
+ let ast;
20
+ try {
21
+ const tokens = (0, pug_lexer_1.default)(pugCode, { filename: fileName });
22
+ emptyLineEnds = collectEmptyLineEnds(tokens);
23
+ attrsBlocks = collectAttrsBlocks(tokens);
24
+ ast = pugParser(tokens, { filename: fileName, src: pugCode });
25
+ visitNode(ast, undefined, undefined);
26
+ codes.push([
27
+ '',
28
+ undefined,
29
+ pugCode.trimEnd().length,
30
+ ]);
31
+ }
32
+ catch (e) {
33
+ const _error = e;
34
+ error = {
35
+ ..._error,
36
+ line: _error.line - 1,
37
+ column: _error.column - 1,
38
+ };
39
+ }
40
+ return {
41
+ htmlCode: (0, muggle_string_1.toString)(codes),
42
+ mappings: (0, buildMappings_1.buildMappings)(codes),
43
+ pugTextDocument,
44
+ error,
45
+ ast,
46
+ emptyLineEnds,
47
+ };
48
+ function visitNode(node, next, parent) {
49
+ if (node.type === 'Block') {
50
+ for (let i = 0; i < node.nodes.length; i++) {
51
+ visitNode(node.nodes[i], node.nodes[i + 1], node);
52
+ }
53
+ }
54
+ else if (node.type === 'Mixin') {
55
+ if (node.block) {
56
+ visitNode(node.block, undefined, node);
57
+ }
58
+ }
59
+ else if (node.type === 'Tag') {
60
+ const pugTagRange = getDocRange(node.line, node.column, node.name.length);
61
+ codes.push([
62
+ '',
63
+ undefined,
64
+ pugTagRange.start,
65
+ ]);
66
+ const selfClosing = node.block.nodes.length === 0;
67
+ addStartTag(node, selfClosing);
68
+ if (!selfClosing) {
69
+ visitNode(node.block, next, parent);
70
+ addEndTag(node, next, parent);
71
+ }
72
+ codes.push([
73
+ '',
74
+ undefined,
75
+ pugTagRange.start,
76
+ ]);
77
+ }
78
+ else if (node.type === 'Text') {
79
+ codes.push([
80
+ node.val,
81
+ undefined,
82
+ getDocOffset(node.line, node.column),
83
+ ]);
84
+ }
85
+ }
86
+ function addStartTag(node, selfClosing) {
87
+ codes.push([
88
+ '',
89
+ undefined,
90
+ getDocOffset(node.line, node.column),
91
+ ]);
92
+ codes.push('<');
93
+ const tagRange = getDocRange(node.line, node.column, node.name.length);
94
+ if (pugCode.substring(tagRange.start, tagRange.end) === node.name) {
95
+ codes.push([
96
+ node.name,
97
+ undefined,
98
+ tagRange.start,
99
+ ]);
100
+ }
101
+ else {
102
+ codes.push(node.name);
103
+ }
104
+ for (const attr of node.attrs.filter(attr => !attr.mustEscape)) {
105
+ codes.push(' ');
106
+ if (attr.name === 'class' || attr.name === 'id') {
107
+ const offset = getDocOffset(attr.line, attr.column);
108
+ for (const char of attr.name) {
109
+ codes.push([
110
+ char,
111
+ undefined,
112
+ offset,
113
+ ]);
114
+ }
115
+ }
116
+ else {
117
+ codes.push(attr.name);
118
+ }
119
+ if (typeof attr.val !== 'boolean') {
120
+ codes.push('=');
121
+ codes.push([
122
+ attr.val,
123
+ undefined,
124
+ getDocOffset(attr.line, attr.column),
125
+ ]);
126
+ }
127
+ }
128
+ const attrsBlock = attrsBlocks.get(getDocOffset(node.line, node.column)); // support attr auto-complete in spaces
129
+ if (attrsBlock) {
130
+ codes.push(' ');
131
+ codes.push([
132
+ attrsBlock.text,
133
+ undefined,
134
+ attrsBlock.offset,
135
+ ]);
136
+ }
137
+ if (selfClosing) {
138
+ codes.push(' />');
139
+ }
140
+ else {
141
+ codes.push('>');
142
+ }
143
+ }
144
+ function addEndTag(node, next, parent) {
145
+ let nextStart;
146
+ if (next) {
147
+ if (next.type === 'Block') {
148
+ nextStart = getDocOffset(next.line, 1);
149
+ }
150
+ else {
151
+ nextStart = getDocOffset(next.line, next.column);
152
+ }
153
+ }
154
+ else if (!parent) {
155
+ nextStart = pugCode.length;
156
+ }
157
+ if (nextStart !== undefined) {
158
+ codes.push([
159
+ '',
160
+ undefined,
161
+ nextStart,
162
+ ]);
163
+ }
164
+ codes.push(`</${node.name}>`);
165
+ }
166
+ function collectEmptyLineEnds(tokens) {
167
+ const ends = [];
168
+ for (const token of tokens) {
169
+ if (token.type === 'newline' || token.type === 'outdent') {
170
+ let currentLine = token.loc.start.line - 2;
171
+ let prevLine = getLineText(pugTextDocument, currentLine);
172
+ while (prevLine.trim() === '') {
173
+ ends.push(pugTextDocument.offsetAt({ line: currentLine + 1, character: 0 }) - 1);
174
+ if (currentLine <= 0) {
175
+ break;
176
+ }
177
+ currentLine--;
178
+ prevLine = getLineText(pugTextDocument, currentLine);
179
+ }
180
+ }
181
+ }
182
+ return ends.sort((a, b) => a - b);
183
+ }
184
+ function collectAttrsBlocks(tokens) {
185
+ const blocks = new Map();
186
+ for (let i = 0; i < tokens.length; i++) {
187
+ const token = tokens[i];
188
+ if (token.type === 'start-attributes') {
189
+ let tagStart = token;
190
+ for (let j = i - 1; j >= 0; j--) {
191
+ const prevToken = tokens[j];
192
+ if (prevToken.type === 'newline'
193
+ || prevToken.type === 'indent'
194
+ || prevToken.type === 'outdent'
195
+ || prevToken.type === ':') {
196
+ break;
197
+ }
198
+ tagStart = prevToken;
199
+ if (prevToken.type === 'tag') {
200
+ break;
201
+ }
202
+ }
203
+ let prevToken = token;
204
+ let text = '';
205
+ for (i++; i < tokens.length; i++) {
206
+ const attrToken = tokens[i];
207
+ addPrevSpace(attrToken);
208
+ if (attrToken.type === 'attribute') {
209
+ let attrText = pugCode.substring(getDocOffset(attrToken.loc.start.line, attrToken.loc.start.column), getDocOffset(attrToken.loc.end.line, attrToken.loc.end.column));
210
+ if (typeof attrToken.val === 'string' && attrText.indexOf('=') >= 0) {
211
+ let valText = attrToken.val;
212
+ if (valText.startsWith('`') && valText.endsWith('`')) {
213
+ if (valText.indexOf('"') === -1) {
214
+ valText = `"${valText.slice(1, -1)}"`;
215
+ }
216
+ else {
217
+ valText = `'${valText.slice(1, -1)}'`;
218
+ }
219
+ }
220
+ valText = valText.replace(/ \\\n/g, '//\n');
221
+ text += attrText.substring(0, attrText.lastIndexOf(attrToken.val)) + valText;
222
+ }
223
+ else {
224
+ text += attrText;
225
+ }
226
+ }
227
+ else if (attrToken.type === 'end-attributes') {
228
+ blocks.set(getDocOffset(tagStart.loc.start.line, tagStart.loc.start.column), {
229
+ offset: getDocOffset(token.loc.end.line, token.loc.end.column),
230
+ text,
231
+ });
232
+ break;
233
+ }
234
+ prevToken = attrToken;
235
+ }
236
+ function addPrevSpace(currentToken) {
237
+ text += pugCode.substring(getDocOffset(prevToken.loc.end.line, prevToken.loc.end.column), getDocOffset(currentToken.loc.start.line, currentToken.loc.start.column)).replace(/,/g, '\n');
238
+ }
239
+ }
240
+ }
241
+ return blocks;
242
+ }
243
+ function getDocOffset(pugLine, pugColumn) {
244
+ return pugTextDocument.offsetAt({ line: pugLine - 1, character: pugColumn - 1 });
245
+ }
246
+ function getDocRange(pugLine, pugColumn, length) {
247
+ const start = getDocOffset(pugLine, pugColumn);
248
+ const end = start + length;
249
+ return {
250
+ start,
251
+ end,
252
+ };
253
+ }
254
+ }
255
+ function getLineText(document, line) {
256
+ const endOffset = document.offsetAt({ line: line + 1, character: 0 });
257
+ const end = document.positionAt(endOffset);
258
+ const text = document.getText({
259
+ start: { line: line, character: 0 },
260
+ end: end.line === line ? end : document.positionAt(endOffset - 1),
261
+ });
262
+ return text;
263
+ }
264
+ //# sourceMappingURL=baseParse.js.map
@@ -0,0 +1,3 @@
1
+ import type { Mapping } from '@volar/source-map';
2
+ import type { Segment } from 'muggle-string';
3
+ export declare function buildMappings<T>(chunks: Segment<T>[]): Mapping<T>[];
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildMappings = buildMappings;
4
+ function buildMappings(chunks) {
5
+ let length = 0;
6
+ const mappings = [];
7
+ for (const segment of chunks) {
8
+ if (typeof segment === 'string') {
9
+ length += segment.length;
10
+ }
11
+ else {
12
+ mappings.push({
13
+ sourceOffsets: [segment[2]],
14
+ generatedOffsets: [length],
15
+ lengths: [segment[0].length],
16
+ data: segment[3],
17
+ });
18
+ length += segment[0].length;
19
+ }
20
+ }
21
+ return mappings;
22
+ }
23
+ //# sourceMappingURL=buildMappings.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue/language-plugin-pug",
3
- "version": "3.2.1",
3
+ "version": "3.2.2",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -14,12 +14,15 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@volar/source-map": "2.4.27",
17
- "volar-service-pug": "0.0.68"
17
+ "muggle-string": "^0.4.1",
18
+ "pug-lexer": "^5.0.1",
19
+ "pug-parser": "^6.0.0",
20
+ "vscode-languageserver-textdocument": "^1.0.11"
18
21
  },
19
22
  "devDependencies": {
20
23
  "@types/node": "^22.10.4",
21
24
  "@vue/compiler-dom": "^3.5.0",
22
- "@vue/language-core": "3.2.1"
25
+ "@vue/language-core": "3.2.2"
23
26
  },
24
- "gitHead": "fad5a89205579e6a0902d7ee5bae3db7b510e2f4"
27
+ "gitHead": "17394f4e80c2267e8b7159468ab40c948ea37d65"
25
28
  }