Skip to content

Commit 410f44d

Browse files
committed
Merge branch 'master' into gh-1197
2 parents 33afb7e + 7fe139f commit 410f44d

File tree

197 files changed

+800
-394
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+800
-394
lines changed

src/css/Selector.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ export default class Selector {
102102
while (i-- > 1) {
103103
const selector = block.selectors[i];
104104
if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
105-
validator.error(`:global(...) must be the first element in a compound selector`, selector);
105+
validator.error(selector, {
106+
code: `css-invalid-global`,
107+
message: `:global(...) must be the first element in a compound selector`
108+
});
106109
}
107110
}
108111
});
@@ -120,7 +123,10 @@ export default class Selector {
120123

121124
for (let i = start; i < end; i += 1) {
122125
if (this.blocks[i].global) {
123-
validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, this.blocks[i].selectors[0]);
126+
validator.error(this.blocks[i].selectors[0], {
127+
code: `css-invalid-global`,
128+
message: `:global(...) can be at the start or end of a selector sequence, but not in the middle`
129+
});
124130
}
125131
}
126132
}

src/css/Stylesheet.ts

+1
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ export default class Stylesheet {
435435
const message = `Unused CSS selector`;
436436

437437
onwarn({
438+
code: `css-unused-selector`,
438439
message,
439440
frame,
440441
loc: { line: line + 1, column },

src/generators/wrapModule.ts

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ function getGlobals(dependencies: Dependency[], options: CompileOptions) {
276276
onerror(error);
277277
} else {
278278
const warning = {
279+
code: `options-missing-globals`,
279280
message: `No name was supplied for imported module '${d.source}'. Guessing '${d.name}', but you should use options.globals`,
280281
};
281282

src/interfaces.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface Warning {
3131
loc?: { line: number; column: number; pos?: number };
3232
end?: { line: number; column: number; };
3333
pos?: number;
34+
code: string;
3435
message: string;
3536
filename?: string;
3637
frame?: string;

src/parse/index.ts

+32-8
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,19 @@ export class Parser {
7171
const current = this.current();
7272

7373
const type = current.type === 'Element' ? `<${current.name}>` : 'Block';
74-
this.error(`${type} was left open`, current.start);
74+
const slug = current.type === 'Element' ? 'element' : 'block';
75+
76+
this.error({
77+
code: `unclosed-${slug}`,
78+
message: `${type} was left open`
79+
}, current.start);
7580
}
7681

7782
if (state !== fragment) {
78-
this.error('Unexpected end of input');
83+
this.error({
84+
code: `unexpected-eof`,
85+
message: 'Unexpected end of input'
86+
});
7987
}
8088

8189
if (this.html.children.length) {
@@ -97,12 +105,16 @@ export class Parser {
97105
}
98106

99107
acornError(err: any) {
100-
this.error(err.message.replace(/ \(\d+:\d+\)$/, ''), err.pos);
108+
this.error({
109+
code: `parse-error`,
110+
message: err.message.replace(/ \(\d+:\d+\)$/, '')
111+
}, err.pos);
101112
}
102113

103-
error(message: string, index = this.index) {
114+
error({ code, message }: { code: string, message: string }, index = this.index) {
104115
error(message, {
105116
name: 'ParseError',
117+
code,
106118
source: this.template,
107119
start: index,
108120
filename: this.filename
@@ -116,7 +128,10 @@ export class Parser {
116128
}
117129

118130
if (required) {
119-
this.error(message || `Expected ${str}`);
131+
this.error({
132+
code: `unexpected-${this.index === this.template.length ? 'eof' : 'token'}`,
133+
message: message || `Expected ${str}`
134+
});
120135
}
121136

122137
return false;
@@ -164,15 +179,21 @@ export class Parser {
164179
const identifier = this.template.slice(this.index, this.index = i);
165180

166181
if (reservedNames.has(identifier)) {
167-
this.error(`'${identifier}' is a reserved word in JavaScript and cannot be used here`, start);
182+
this.error({
183+
code: `unexpected-reserved-word`,
184+
message: `'${identifier}' is a reserved word in JavaScript and cannot be used here`
185+
}, start);
168186
}
169187

170188
return identifier;
171189
}
172190

173191
readUntil(pattern: RegExp) {
174192
if (this.index >= this.template.length)
175-
this.error('Unexpected end of input');
193+
this.error({
194+
code: `unexpected-eof`,
195+
message: 'Unexpected end of input'
196+
});
176197

177198
const start = this.index;
178199
const match = pattern.exec(this.template.slice(start));
@@ -192,7 +213,10 @@ export class Parser {
192213

193214
requireWhitespace() {
194215
if (!whitespace.test(this.template[this.index])) {
195-
this.error(`Expected whitespace`);
216+
this.error({
217+
code: `missing-whitespace`,
218+
message: `Expected whitespace`
219+
});
196220
}
197221

198222
this.allowWhitespace();

src/parse/read/directives.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@ import { parseExpressionAt } from 'acorn';
22
import repeat from '../../utils/repeat';
33
import { Parser } from '../index';
44

5-
const DIRECTIVES = {
5+
const DIRECTIVES: Record<string, {
6+
names: string[];
7+
attribute: (
8+
start: number,
9+
end: number,
10+
type: string,
11+
name: string,
12+
expression?: any,
13+
directiveName?: string
14+
) => { start: number, end: number, type: string, name: string, value?: any, expression?: any };
15+
allowedExpressionTypes: string[];
16+
error: string;
17+
}> = {
618
Ref: {
719
names: ['ref'],
820
attribute(start, end, type, name) {
@@ -143,7 +155,10 @@ export function readDirective(
143155
try {
144156
expression = readExpression(parser, expressionStart, quoteMark);
145157
if (directive.allowedExpressionTypes.indexOf(expression.type) === -1) {
146-
parser.error(directive.error, expressionStart);
158+
parser.error({
159+
code: `invalid-directive-value`,
160+
message: directive.error
161+
}, expressionStart);
147162
}
148163
} catch (err) {
149164
if (parser.template[expressionStart] === '{') {
@@ -155,7 +170,10 @@ export function readDirective(
155170
const value = parser.template.slice(expressionStart + (parser.v2 ? 1 : 2), expressionEnd);
156171
message += ` — use '${value}', not '${parser.v2 ? `{${value}}` : `{{${value}}}`}'`;
157172
}
158-
parser.error(message, expressionStart);
173+
parser.error({
174+
code: `invalid-directive-value`,
175+
message
176+
}, expressionStart);
159177
}
160178

161179
throw err;

src/parse/read/script.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ export default function readScript(parser: Parser, start: number, attributes: No
1212
const scriptStart = parser.index;
1313
const scriptEnd = parser.template.indexOf(scriptClosingTag, scriptStart);
1414

15-
if (scriptEnd === -1) parser.error(`<script> must have a closing tag`);
15+
if (scriptEnd === -1) parser.error({
16+
code: `unclosed-script`,
17+
message: `<script> must have a closing tag`
18+
});
1619

1720
const source =
1821
repeat(' ', scriptStart) + parser.template.slice(scriptStart, scriptEnd);

src/parse/read/style.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ export default function readStyle(parser: Parser, start: number, attributes: Nod
1717
});
1818
} catch (err) {
1919
if (err.name === 'CssSyntaxError') {
20-
parser.error(err.message, err.offset);
20+
parser.error({
21+
code: `css-syntax-error`,
22+
message: err.message
23+
}, err.offset);
2124
} else {
2225
throw err;
2326
}

src/parse/state/mustache.ts

+42-14
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ export default function mustache(parser: Parser) {
5656
} else if (block.type === 'AwaitBlock') {
5757
expected = 'await';
5858
} else {
59-
parser.error(`Unexpected block closing tag`);
59+
parser.error({
60+
code: `unexpected-block-close`,
61+
message: `Unexpected block closing tag`
62+
});
6063
}
6164

6265
parser.eat(expected, true);
@@ -86,9 +89,10 @@ export default function mustache(parser: Parser) {
8689
} else if (parser.eat(parser.v2 ? ':elseif' : 'elseif')) {
8790
const block = parser.current();
8891
if (block.type !== 'IfBlock')
89-
parser.error(
90-
'Cannot have an {{elseif ...}} block outside an {{#if ...}} block'
91-
);
92+
parser.error({
93+
code: `invalid-elseif-placement`,
94+
message: 'Cannot have an {{elseif ...}} block outside an {{#if ...}} block'
95+
});
9296

9397
parser.requireWhitespace();
9498

@@ -117,9 +121,10 @@ export default function mustache(parser: Parser) {
117121
} else if (parser.eat(parser.v2 ? ':else' : 'else')) {
118122
const block = parser.current();
119123
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
120-
parser.error(
121-
'Cannot have an {{else}} block outside an {{#if ...}} or {{#each ...}} block'
122-
);
124+
parser.error({
125+
code: `invalid-else-placement`,
126+
message: 'Cannot have an {{else}} block outside an {{#if ...}} or {{#each ...}} block'
127+
});
123128
}
124129

125130
parser.allowWhitespace();
@@ -191,7 +196,10 @@ export default function mustache(parser: Parser) {
191196
} else if (parser.eat('await')) {
192197
type = 'AwaitBlock';
193198
} else {
194-
parser.error(`Expected if, each or await`);
199+
parser.error({
200+
code: `expected-block-type`,
201+
message: `Expected if, each or await`
202+
});
195203
}
196204

197205
parser.requireWhitespace();
@@ -249,28 +257,42 @@ export default function mustache(parser: Parser) {
249257
parser.allowWhitespace();
250258

251259
const destructuredContext = parser.readIdentifier();
252-
if (!destructuredContext) parser.error(`Expected name`);
260+
if (!destructuredContext) parser.error({
261+
code: `expected-name`,
262+
message: `Expected name`
263+
});
253264

254265
block.destructuredContexts.push(destructuredContext);
255266
parser.allowWhitespace();
256267
} while (parser.eat(','));
257268

258-
if (!block.destructuredContexts.length) parser.error(`Expected name`);
269+
if (!block.destructuredContexts.length) parser.error({
270+
code: `expected-name`,
271+
message: `Expected name`
272+
});
273+
259274
block.context = block.destructuredContexts.join('_');
260275

261276
parser.allowWhitespace();
262277
parser.eat(']', true);
263278
} else {
264279
block.context = parser.readIdentifier();
265-
if (!block.context) parser.error(`Expected name`);
280+
if (!block.context) parser.error({
281+
code: `expected-name`,
282+
message: `Expected name`
283+
});
266284
}
267285

268286
parser.allowWhitespace();
269287

270288
if (parser.eat(',')) {
271289
parser.allowWhitespace();
272290
block.index = parser.readIdentifier();
273-
if (!block.index) parser.error(`Expected name`);
291+
if (!block.index) parser.error({
292+
code: `expected-name`,
293+
message: `Expected name`
294+
});
295+
274296
parser.allowWhitespace();
275297
}
276298

@@ -287,7 +309,10 @@ export default function mustache(parser: Parser) {
287309
expression.property.computed ||
288310
expression.property.type !== 'Identifier'
289311
) {
290-
parser.error('invalid key', expression.start);
312+
parser.error({
313+
code: `invalid-key`,
314+
message: 'invalid key'
315+
}, expression.start);
291316
}
292317

293318
block.key = expression.property.name;
@@ -296,7 +321,10 @@ export default function mustache(parser: Parser) {
296321
parser.allowWhitespace();
297322
} else if (parser.eat('@')) {
298323
block.key = parser.readIdentifier();
299-
if (!block.key) parser.error(`Expected name`);
324+
if (!block.key) parser.error({
325+
code: `expected-name`,
326+
message: `Expected name`
327+
});
300328
parser.allowWhitespace();
301329
}
302330
}

0 commit comments

Comments
 (0)