Merge pull request #1250 from UnwrittenFun/feat/warn-end-pos

Add end position to warnings and errors
pull/1261/head
Rich Harris 8 years ago committed by GitHub
commit 5b086df061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -102,7 +102,7 @@ export default class Selector {
while (i-- > 1) { while (i-- > 1) {
const selector = block.selectors[i]; const selector = block.selectors[i];
if (selector.type === 'PseudoClassSelector' && selector.name === 'global') { if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
validator.error(`:global(...) must be the first element in a compound selector`, selector.start); validator.error(`:global(...) must be the first element in a compound selector`, selector);
} }
} }
}); });
@ -120,7 +120,7 @@ export default class Selector {
for (let i = start; i < end; i += 1) { for (let i = start; i < end; i += 1) {
if (this.blocks[i].global) { if (this.blocks[i].global) {
validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, this.blocks[i].selectors[0].start); validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, this.blocks[i].selectors[0]);
} }
} }
} }

@ -146,4 +146,4 @@ export function create(source: string, _options: CompileOptions = {}) {
} }
} }
export { parse, validate, version as VERSION }; export { parse, validate, Stylesheet, version as VERSION };

@ -29,6 +29,7 @@ export interface Parsed {
export interface Warning { export interface Warning {
loc?: { line: number; column: number; pos?: number }; loc?: { line: number; column: number; pos?: number };
end?: { line: number; column: number; };
pos?: number; pos?: number;
message: string; message: string;
filename?: string; filename?: string;

@ -4,24 +4,28 @@ import getCodeFrame from '../utils/getCodeFrame';
export default class CompileError extends Error { export default class CompileError extends Error {
frame: string; frame: string;
loc: { line: number; column: number }; loc: { line: number; column: number };
end: { line: number; column: number };
pos: number; pos: number;
filename: string; filename: string;
constructor( constructor(
message: string, message: string,
template: string, template: string,
index: number, startPos: number,
filename: string filename: string,
endPos: number = startPos
) { ) {
super(message); super(message);
const { line, column } = locate(template, index); const start = locate(template, startPos);
const end = locate(template, endPos);
this.loc = { line: line + 1, column }; this.loc = { line: start.line + 1, column: start.column };
this.pos = index; this.end = { line: end.line + 1, column: end.column };
this.pos = startPos;
this.filename = filename; this.filename = filename;
this.frame = getCodeFrame(template, line, column); this.frame = getCodeFrame(template, start.line, start.column);
} }
public toString = () => { public toString = () => {

@ -33,7 +33,7 @@ export default function a11y(
if (name.startsWith('aria-')) { if (name.startsWith('aria-')) {
if (invisibleElements.has(node.name)) { if (invisibleElements.has(node.name)) {
// aria-unsupported-elements // aria-unsupported-elements
validator.warn(`A11y: <${node.name}> should not have aria-* attributes`, attribute.start); validator.warn(`A11y: <${node.name}> should not have aria-* attributes`, attribute);
} }
const type = name.slice(5); const type = name.slice(5);
@ -42,7 +42,7 @@ export default function a11y(
let message = `A11y: Unknown aria attribute 'aria-${type}'`; let message = `A11y: Unknown aria attribute 'aria-${type}'`;
if (match) message += ` (did you mean '${match}'?)`; if (match) message += ` (did you mean '${match}'?)`;
validator.warn(message, attribute.start); validator.warn(message, attribute);
} }
} }
@ -50,7 +50,7 @@ export default function a11y(
if (name === 'role') { if (name === 'role') {
if (invisibleElements.has(node.name)) { if (invisibleElements.has(node.name)) {
// aria-unsupported-elements // aria-unsupported-elements
validator.warn(`A11y: <${node.name}> should not have role attribute`, attribute.start); validator.warn(`A11y: <${node.name}> should not have role attribute`, attribute);
} }
const value = getStaticAttributeValue(node, 'role'); const value = getStaticAttributeValue(node, 'role');
@ -59,30 +59,30 @@ export default function a11y(
let message = `A11y: Unknown role '${value}'`; let message = `A11y: Unknown role '${value}'`;
if (match) message += ` (did you mean '${match}'?)`; if (match) message += ` (did you mean '${match}'?)`;
validator.warn(message, attribute.start); validator.warn(message, attribute);
} }
} }
// no-access-key // no-access-key
if (name === 'accesskey') { if (name === 'accesskey') {
validator.warn(`A11y: Avoid using accesskey`, attribute.start); validator.warn(`A11y: Avoid using accesskey`, attribute);
} }
// no-autofocus // no-autofocus
if (name === 'autofocus') { if (name === 'autofocus') {
validator.warn(`A11y: Avoid using autofocus`, attribute.start); validator.warn(`A11y: Avoid using autofocus`, attribute);
} }
// scope // scope
if (name === 'scope' && node.name !== 'th') { if (name === 'scope' && node.name !== 'th') {
validator.warn(`A11y: The scope attribute should only be used with <th> elements`, attribute.start); validator.warn(`A11y: The scope attribute should only be used with <th> elements`, attribute);
} }
// tabindex-no-positive // tabindex-no-positive
if (name === 'tabindex') { if (name === 'tabindex') {
const value = getStaticAttributeValue(node, 'tabindex'); const value = getStaticAttributeValue(node, 'tabindex');
if (!isNaN(value) && +value > 0) { if (!isNaN(value) && +value > 0) {
validator.warn(`A11y: avoid tabindex values above zero`, attribute.start); validator.warn(`A11y: avoid tabindex values above zero`, attribute);
} }
} }
@ -96,13 +96,13 @@ export default function a11y(
attributes.slice(0, -1).join(', ') + ` or ${attributes[attributes.length - 1]}` : attributes.slice(0, -1).join(', ') + ` or ${attributes[attributes.length - 1]}` :
attributes[0]; attributes[0];
validator.warn(`A11y: <${name}> element should have ${article} ${sequence} attribute`, node.start); validator.warn(`A11y: <${name}> element should have ${article} ${sequence} attribute`, node);
} }
} }
function shouldHaveContent() { function shouldHaveContent() {
if (node.children.length === 0) { if (node.children.length === 0) {
validator.warn(`A11y: <${node.name}> element should have child content`, node.start); validator.warn(`A11y: <${node.name}> element should have child content`, node);
} }
} }
@ -110,7 +110,7 @@ export default function a11y(
const href = attributeMap.get(attribute); const href = attributeMap.get(attribute);
const value = getStaticAttributeValue(node, attribute); const value = getStaticAttributeValue(node, attribute);
if (value === '' || value === '#') { if (value === '' || value === '#') {
validator.warn(`A11y: '${value}' is not a valid ${attribute} attribute`, href.start); validator.warn(`A11y: '${value}' is not a valid ${attribute} attribute`, href);
} }
} }
@ -122,7 +122,7 @@ export default function a11y(
// anchor-in-svg-is-valid // anchor-in-svg-is-valid
shouldHaveValidHref('xlink:href') shouldHaveValidHref('xlink:href')
} else { } else {
validator.warn(`A11y: <a> element should have an href attribute`, node.start); validator.warn(`A11y: <a> element should have an href attribute`, node);
} }
// anchor-has-content // anchor-has-content
@ -141,7 +141,7 @@ export default function a11y(
shouldHaveContent(); shouldHaveContent();
if (attributeMap.has('aria-hidden')) { if (attributeMap.has('aria-hidden')) {
validator.warn(`A11y: <${node.name}> element should not be hidden`, attributeMap.get('aria-hidden').start); validator.warn(`A11y: <${node.name}> element should not be hidden`, attributeMap.get('aria-hidden'));
} }
} }
@ -157,14 +157,14 @@ export default function a11y(
// no-distracting-elements // no-distracting-elements
if (node.name === 'marquee' || node.name === 'blink') { if (node.name === 'marquee' || node.name === 'blink') {
validator.warn(`A11y: Avoid <${node.name}> elements`, node.start); validator.warn(`A11y: Avoid <${node.name}> elements`, node);
} }
if (node.name === 'figcaption') { if (node.name === 'figcaption') {
const parent = elementStack[elementStack.length - 1]; const parent = elementStack[elementStack.length - 1];
if (parent) { if (parent) {
if (parent.name !== 'figure') { if (parent.name !== 'figure') {
validator.warn(`A11y: <figcaption> must be an immediate child of <figure>`, node.start); validator.warn(`A11y: <figcaption> must be an immediate child of <figure>`, node);
} else { } else {
const children = parent.children.filter(node => { const children = parent.children.filter(node => {
if (node.type === 'Comment') return false; if (node.type === 'Comment') return false;
@ -175,7 +175,7 @@ export default function a11y(
const index = children.indexOf(node); const index = children.indexOf(node);
if (index !== 0 && index !== children.length - 1) { if (index !== 0 && index !== children.length - 1) {
validator.warn(`A11y: <figcaption> must be first or last child of <figure>`, node.start); validator.warn(`A11y: <figcaption> must be first or last child of <figure>`, node);
} }
} }
} }

@ -52,7 +52,7 @@ export default function validateHtml(validator: Validator, html: Node) {
else if (node.type === 'EachBlock') { else if (node.type === 'EachBlock') {
if (validator.helpers.has(node.context)) { if (validator.helpers.has(node.context)) {
let c = node.expression.end; let c: number = node.expression.end;
// find start of context // find start of context
while (/\s/.test(validator.source[c])) c += 1; while (/\s/.test(validator.source[c])) c += 1;
@ -61,13 +61,13 @@ export default function validateHtml(validator: Validator, html: Node) {
validator.warn( validator.warn(
`Context clashes with a helper. Rename one or the other to eliminate any ambiguity`, `Context clashes with a helper. Rename one or the other to eliminate any ambiguity`,
c { start: c, end: c + node.context.length }
); );
} }
} }
if (validator.options.dev && isEmptyBlock(node)) { if (validator.options.dev && isEmptyBlock(node)) {
validator.warn('Empty block', node.start); validator.warn('Empty block', node);
} }
if (node.children) { if (node.children) {
@ -103,7 +103,7 @@ export default function validateHtml(validator: Validator, html: Node) {
let message = `'refs.${ref}' does not exist`; let message = `'refs.${ref}' does not exist`;
if (match) message += ` (did you mean 'refs.${match}'?)`; if (match) message += ` (did you mean 'refs.${match}'?)`;
validator.error(message, callee.start); validator.error(message, callee);
} }
}); });
} }

@ -20,13 +20,13 @@ export default function validateElement(
if (!isComponent && /^[A-Z]/.test(node.name[0])) { if (!isComponent && /^[A-Z]/.test(node.name[0])) {
// TODO upgrade to validator.error in v2 // TODO upgrade to validator.error in v2
validator.warn(`${node.name} component is not defined`, node.start); validator.warn(`${node.name} component is not defined`, node);
} }
if (elementStack.length === 0 && validator.namespace !== namespaces.svg && svg.test(node.name)) { if (elementStack.length === 0 && validator.namespace !== namespaces.svg && svg.test(node.name)) {
validator.warn( validator.warn(
`<${node.name}> is an SVG element did you forget to add { namespace: 'svg' } ?`, `<${node.name}> is an SVG element did you forget to add { namespace: 'svg' } ?`,
node.start node
); );
} }
@ -34,12 +34,12 @@ export default function validateElement(
const nameAttribute = node.attributes.find((attribute: Node) => attribute.name === 'name'); const nameAttribute = node.attributes.find((attribute: Node) => attribute.name === 'name');
if (nameAttribute) { if (nameAttribute) {
if (nameAttribute.value.length !== 1 || nameAttribute.value[0].type !== 'Text') { if (nameAttribute.value.length !== 1 || nameAttribute.value[0].type !== 'Text') {
validator.error(`<slot> name cannot be dynamic`, nameAttribute.start); validator.error(`<slot> name cannot be dynamic`, nameAttribute);
} }
const slotName = nameAttribute.value[0].data; const slotName = nameAttribute.value[0].data;
if (slotName === 'default') { if (slotName === 'default') {
validator.error(`default is a reserved word — it cannot be used as a slot name`, nameAttribute.start); validator.error(`default is a reserved word — it cannot be used as a slot name`, nameAttribute);
} }
// TODO should duplicate slots be disallowed? Feels like it's more likely to be a // TODO should duplicate slots be disallowed? Feels like it's more likely to be a
@ -63,7 +63,7 @@ export default function validateElement(
if (node.attributes.length > 0) { if (node.attributes.length > 0) {
validator.error( validator.error(
`<title> cannot have attributes`, `<title> cannot have attributes`,
node.attributes[0].start node.attributes[0]
); );
} }
@ -71,7 +71,7 @@ export default function validateElement(
if (child.type !== 'Text' && child.type !== 'MustacheTag') { if (child.type !== 'Text' && child.type !== 'MustacheTag') {
validator.error( validator.error(
`<title> can only contain text and {{tags}}`, `<title> can only contain text and {{tags}}`,
child.start child
); );
} }
}); });
@ -98,7 +98,7 @@ export default function validateElement(
) { ) {
validator.error( validator.error(
`'value' is not a valid binding on <${node.name}> elements`, `'value' is not a valid binding on <${node.name}> elements`,
attribute.start attribute
); );
} }
@ -107,21 +107,21 @@ export default function validateElement(
if (node.name !== 'input') { if (node.name !== 'input') {
validator.error( validator.error(
`'${name}' is not a valid binding on <${node.name}> elements`, `'${name}' is not a valid binding on <${node.name}> elements`,
attribute.start attribute
); );
} }
if (checkTypeAttribute(validator, node) !== 'checkbox') { if (checkTypeAttribute(validator, node) !== 'checkbox') {
validator.error( validator.error(
`'${name}' binding can only be used with <input type="checkbox">`, `'${name}' binding can only be used with <input type="checkbox">`,
attribute.start attribute
); );
} }
} else if (name === 'group') { } else if (name === 'group') {
if (node.name !== 'input') { if (node.name !== 'input') {
validator.error( validator.error(
`'group' is not a valid binding on <${node.name}> elements`, `'group' is not a valid binding on <${node.name}> elements`,
attribute.start attribute
); );
} }
@ -130,7 +130,7 @@ export default function validateElement(
if (type !== 'checkbox' && type !== 'radio') { if (type !== 'checkbox' && type !== 'radio') {
validator.error( validator.error(
`'checked' binding can only be used with <input type="checkbox"> or <input type="radio">`, `'checked' binding can only be used with <input type="checkbox"> or <input type="radio">`,
attribute.start attribute
); );
} }
} else if ( } else if (
@ -145,13 +145,13 @@ export default function validateElement(
if (node.name !== 'audio' && node.name !== 'video') { if (node.name !== 'audio' && node.name !== 'video') {
validator.error( validator.error(
`'${name}' binding can only be used with <audio> or <video>`, `'${name}' binding can only be used with <audio> or <video>`,
attribute.start attribute
); );
} }
} else { } else {
validator.error( validator.error(
`'${attribute.name}' is not a valid binding`, `'${attribute.name}' is not a valid binding`,
attribute.start attribute
); );
} }
} else if (attribute.type === 'EventHandler') { } else if (attribute.type === 'EventHandler') {
@ -159,7 +159,7 @@ export default function validateElement(
validateEventHandler(validator, attribute, refCallees); validateEventHandler(validator, attribute, refCallees);
} else if (attribute.type === 'Transition') { } else if (attribute.type === 'Transition') {
if (isComponent) { if (isComponent) {
validator.error(`Transitions can only be applied to DOM elements, not components`, attribute.start); validator.error(`Transitions can only be applied to DOM elements, not components`, attribute);
} }
validator.used.transitions.add(attribute.name); validator.used.transitions.add(attribute.name);
@ -170,13 +170,13 @@ export default function validateElement(
if (bidi) if (bidi)
validator.error( validator.error(
`An element can only have one 'transition' directive`, `An element can only have one 'transition' directive`,
attribute.start attribute
); );
validator.error( validator.error(
`An element cannot have both a 'transition' directive and an '${attribute.intro `An element cannot have both a 'transition' directive and an '${attribute.intro
? 'in' ? 'in'
: 'out'}' directive`, : 'out'}' directive`,
attribute.start attribute
); );
} }
@ -186,11 +186,11 @@ export default function validateElement(
`An element cannot have both an '${hasIntro `An element cannot have both an '${hasIntro
? 'in' ? 'in'
: 'out'}' directive and a 'transition' directive`, : 'out'}' directive and a 'transition' directive`,
attribute.start attribute
); );
validator.error( validator.error(
`An element can only have one '${hasIntro ? 'in' : 'out'}' directive`, `An element can only have one '${hasIntro ? 'in' : 'out'}' directive`,
attribute.start attribute
); );
} }
@ -201,7 +201,7 @@ export default function validateElement(
if (!validator.transitions.has(attribute.name)) { if (!validator.transitions.has(attribute.name)) {
validator.error( validator.error(
`Missing transition '${attribute.name}'`, `Missing transition '${attribute.name}'`,
attribute.start attribute
); );
} }
} else if (attribute.type === 'Attribute') { } else if (attribute.type === 'Attribute') {
@ -209,7 +209,7 @@ export default function validateElement(
if (node.children.length) { if (node.children.length) {
validator.error( validator.error(
`A <textarea> can have either a value attribute or (equivalently) child content, but not both`, `A <textarea> can have either a value attribute or (equivalently) child content, but not both`,
attribute.start attribute
); );
} }
} }
@ -228,13 +228,13 @@ function checkTypeAttribute(validator: Validator, node: Node) {
if (!attribute) return null; if (!attribute) return null;
if (attribute.value === true) { if (attribute.value === true) {
validator.error(`'type' attribute must be specified`, attribute.start); validator.error(`'type' attribute must be specified`, attribute);
} }
if (isDynamic(attribute)) { if (isDynamic(attribute)) {
validator.error( validator.error(
`'type' attribute cannot be dynamic if input uses two-way binding`, `'type' attribute cannot be dynamic if input uses two-way binding`,
attribute.start attribute
); );
} }
@ -245,7 +245,7 @@ function checkSlotAttribute(validator: Validator, node: Node, attribute: Node, s
if (isDynamic(attribute)) { if (isDynamic(attribute)) {
validator.error( validator.error(
`slot attribute cannot have a dynamic value`, `slot attribute cannot have a dynamic value`,
attribute.start attribute
); );
} }
@ -260,11 +260,11 @@ function checkSlotAttribute(validator: Validator, node: Node, attribute: Node, s
if (parent.type === 'IfBlock' || parent.type === 'EachBlock') { if (parent.type === 'IfBlock' || parent.type === 'EachBlock') {
const message = `Cannot place slotted elements inside an ${parent.type === 'IfBlock' ? 'if' : 'each'}-block`; const message = `Cannot place slotted elements inside an ${parent.type === 'IfBlock' ? 'if' : 'each'}-block`;
validator.error(message, attribute.start); validator.error(message, attribute);
} }
} }
validator.error(`Element with a slot='...' attribute must be a descendant of a component or custom element`, attribute.start); validator.error(`Element with a slot='...' attribute must be a descendant of a component or custom element`, attribute);
} }
function isDynamic(attribute: Node) { function isDynamic(attribute: Node) {

@ -13,10 +13,10 @@ export default function validateEventHandlerCallee(
) { ) {
if (!attribute.expression) return; if (!attribute.expression) return;
const { callee, start, type } = attribute.expression; const { callee, type } = attribute.expression;
if (type !== 'CallExpression') { if (type !== 'CallExpression') {
validator.error(`Expected a call expression`, start); validator.error(`Expected a call expression`, attribute.expression);
} }
const { name } = flattenReference(callee); const { name } = flattenReference(callee);
@ -30,7 +30,10 @@ export default function validateEventHandlerCallee(
if (name === 'store' && attribute.expression.callee.type === 'MemberExpression') { if (name === 'store' && attribute.expression.callee.type === 'MemberExpression') {
if (!validator.options.store) { if (!validator.options.store) {
validator.warn('compile with `store: true` in order to call store methods', attribute.expression.start); validator.warn(
'compile with `store: true` in order to call store methods',
attribute.expression
);
} }
return; return;
} }
@ -56,5 +59,5 @@ export default function validateEventHandlerCallee(
message += `. '${callee.name}' exists on 'helpers', did you put it in the wrong place?`; message += `. '${callee.name}' exists on 'helpers', did you put it in the wrong place?`;
} }
validator.warn(message, start); validator.warn(message, attribute.expression);
} }

@ -4,7 +4,7 @@ import { Node } from '../../interfaces';
export default function validateHead(validator: Validator, node: Node, refs: Map<string, Node[]>, refCallees: Node[]) { export default function validateHead(validator: Validator, node: Node, refs: Map<string, Node[]>, refCallees: Node[]) {
if (node.attributes.length) { if (node.attributes.length) {
validator.error(`<:Head> should not have any attributes or directives`, node.start); validator.error(`<:Head> should not have any attributes or directives`, node);
} }
// TODO ensure only valid elements are included here // TODO ensure only valid elements are included here

@ -25,7 +25,7 @@ export default function validateWindow(validator: Validator, node: Node, refs: M
`Bindings on <:Window/> must be to top-level properties, e.g. '${parts[ `Bindings on <:Window/> must be to top-level properties, e.g. '${parts[
parts.length - 1 parts.length - 1
]}' rather than '${parts.join('.')}'`, ]}' rather than '${parts.join('.')}'`,
attribute.value.start attribute.value
); );
} }
@ -41,12 +41,12 @@ export default function validateWindow(validator: Validator, node: Node, refs: M
if (match) { if (match) {
validator.error( validator.error(
`${message} (did you mean '${match}'?)`, `${message} (did you mean '${match}'?)`,
attribute.start attribute
); );
} else { } else {
validator.error( validator.error(
`${message} — valid bindings are ${list(validBindings)}`, `${message} — valid bindings are ${list(validBindings)}`,
attribute.start attribute
); );
} }
} }

@ -10,10 +10,10 @@ class ValidationError extends CompileError {
constructor( constructor(
message: string, message: string,
template: string, template: string,
index: number, pos: { start: number, end: number },
filename: string filename: string,
) { ) {
super(message, template, index, filename); super(message, template, pos.start, filename, pos.end);
this.name = 'ValidationError'; this.name = 'ValidationError';
} }
} }
@ -66,23 +66,25 @@ export class Validator {
}; };
} }
error(message: string, pos: number) { error(message: string, pos: { start: number, end: number }) {
throw new ValidationError(message, this.source, pos, this.filename); throw new ValidationError(message, this.source, pos, this.filename);
} }
warn(message: string, pos: number) { warn(message: string, pos: { start: number, end: number }) {
if (!this.locator) this.locator = getLocator(this.source); if (!this.locator) this.locator = getLocator(this.source);
const { line, column } = this.locator(pos); const start = this.locator(pos.start);
const end = this.locator(pos.end);
const frame = getCodeFrame(this.source, line, column); const frame = getCodeFrame(this.source, start.line, start.column);
this.onwarn({ this.onwarn({
message, message,
frame, frame,
loc: { line: line + 1, column }, loc: { line: start.line + 1, column: start.column },
pos, end: { line: end.line + 1, column: end.column },
pos: pos.start,
filename: this.filename, filename: this.filename,
toString: () => `${message} (${line + 1}:${column})\n${frame}`, toString: () => `${message} (${start.line + 1}:${start.column})\n${frame}`,
}); });
} }
} }
@ -148,7 +150,7 @@ export default function validate(
if (!validator.used[category].has(name)) { if (!validator.used[category].has(name)) {
validator.warn( validator.warn(
`The '${name}' ${categories[category]} is unused`, `The '${name}' ${categories[category]} is unused`,
prop.start prop
); );
} }
}); });

@ -13,14 +13,14 @@ export default function validateJs(validator: Validator, js: Node) {
js.content.body.forEach((node: Node) => { js.content.body.forEach((node: Node) => {
// check there are no named exports // check there are no named exports
if (node.type === 'ExportNamedDeclaration') { if (node.type === 'ExportNamedDeclaration') {
validator.error(`A component can only have a default export`, node.start); validator.error(`A component can only have a default export`, node);
} }
if (node.type === 'ExportDefaultDeclaration') { if (node.type === 'ExportDefaultDeclaration') {
if (node.declaration.type !== 'ObjectExpression') { if (node.declaration.type !== 'ObjectExpression') {
return validator.error( return validator.error(
`Default export must be an object literal`, `Default export must be an object literal`,
node.declaration.start node.declaration
); );
} }
@ -37,14 +37,14 @@ export default function validateJs(validator: Validator, js: Node) {
if (props.has('oncreate') && props.has('onrender')) { if (props.has('oncreate') && props.has('onrender')) {
validator.error( validator.error(
'Cannot have both oncreate and onrender', 'Cannot have both oncreate and onrender',
props.get('onrender').start props.get('onrender')
); );
} }
if (props.has('ondestroy') && props.has('onteardown')) { if (props.has('ondestroy') && props.has('onteardown')) {
validator.error( validator.error(
'Cannot have both ondestroy and onteardown', 'Cannot have both ondestroy and onteardown',
props.get('onteardown').start props.get('onteardown')
); );
} }
@ -60,17 +60,17 @@ export default function validateJs(validator: Validator, js: Node) {
if (match) { if (match) {
validator.error( validator.error(
`Unexpected property '${name}' (did you mean '${match}'?)`, `Unexpected property '${name}' (did you mean '${match}'?)`,
prop.start prop
); );
} else if (/FunctionExpression/.test(prop.value.type)) { } else if (/FunctionExpression/.test(prop.value.type)) {
validator.error( validator.error(
`Unexpected property '${name}' (did you mean to include it in 'methods'?)`, `Unexpected property '${name}' (did you mean to include it in 'methods'?)`,
prop.start prop
); );
} else { } else {
validator.error( validator.error(
`Unexpected property '${name}'`, `Unexpected property '${name}'`,
prop.start prop
); );
} }
} }

@ -8,7 +8,7 @@ export default function components(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'components' property must be an object literal`, `The 'components' property must be an object literal`,
prop.start prop
); );
} }
@ -21,12 +21,12 @@ export default function components(validator: Validator, prop: Node) {
if (name === 'state') { if (name === 'state') {
validator.error( validator.error(
`Component constructors cannot be called 'state' due to technical limitations`, `Component constructors cannot be called 'state' due to technical limitations`,
component.start component
); );
} }
if (!/^[A-Z]/.test(name)) { if (!/^[A-Z]/.test(name)) {
validator.warn(`Component names should be capitalised`, component.start); validator.warn(`Component names should be capitalised`, component);
} }
}); });
} }

@ -17,7 +17,7 @@ export default function computed(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'computed' property must be an object literal`, `The 'computed' property must be an object literal`,
prop.start prop
); );
} }
@ -31,21 +31,21 @@ export default function computed(validator: Validator, prop: Node) {
const suggestion = name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&'); const suggestion = name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&');
validator.error( validator.error(
`Computed property name '${name}' is invalid — must be a valid identifier such as ${suggestion}`, `Computed property name '${name}' is invalid — must be a valid identifier such as ${suggestion}`,
computation.start computation
); );
} }
if (reservedNames.has(name)) { if (reservedNames.has(name)) {
validator.error( validator.error(
`Computed property name '${name}' is invalid — cannot be a JavaScript reserved word`, `Computed property name '${name}' is invalid — cannot be a JavaScript reserved word`,
computation.start computation
); );
} }
if (!isFunctionExpression.has(computation.value.type)) { if (!isFunctionExpression.has(computation.value.type)) {
validator.error( validator.error(
`Computed properties can be function expressions or arrow function expressions`, `Computed properties can be function expressions or arrow function expressions`,
computation.value.start computation.value
); );
} }
@ -55,14 +55,14 @@ export default function computed(validator: Validator, prop: Node) {
if (isThisGetCallExpression(node) && !node.callee.property.computed) { if (isThisGetCallExpression(node) && !node.callee.property.computed) {
validator.error( validator.error(
`Cannot use this.get(...) — values must be passed into the function as arguments`, `Cannot use this.get(...) — values must be passed into the function as arguments`,
node.start node
); );
} }
if (node.type === 'ThisExpression') { if (node.type === 'ThisExpression') {
validator.error( validator.error(
`Computed properties should be pure functions — they do not have access to the component instance and cannot use 'this'. Did you mean to put this in 'methods'?`, `Computed properties should be pure functions — they do not have access to the component instance and cannot use 'this'. Did you mean to put this in 'methods'?`,
node.start node
); );
} }
}); });
@ -70,7 +70,7 @@ export default function computed(validator: Validator, prop: Node) {
if (params.length === 0) { if (params.length === 0) {
validator.error( validator.error(
`A computed value must depend on at least one property`, `A computed value must depend on at least one property`,
computation.value.start computation.value
); );
} }
@ -83,7 +83,7 @@ export default function computed(validator: Validator, prop: Node) {
if (!valid) { if (!valid) {
validator.error( validator.error(
`Computed properties cannot use destructuring in function parameters`, `Computed properties cannot use destructuring in function parameters`,
param.start param
); );
} }
}); });

@ -7,6 +7,6 @@ export default function data(validator: Validator, prop: Node) {
while (prop.type === 'ParenthesizedExpression') prop = prop.expression; while (prop.type === 'ParenthesizedExpression') prop = prop.expression;
if (disallowed.has(prop.value.type)) { if (disallowed.has(prop.value.type)) {
validator.error(`'data' must be a function`, prop.value.start); validator.error(`'data' must be a function`, prop.value);
} }
} }

@ -7,7 +7,7 @@ export default function events(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'events' property must be an object literal`, `The 'events' property must be an object literal`,
prop.start prop
); );
} }

@ -10,7 +10,7 @@ export default function helpers(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'helpers' property must be an object literal`, `The 'helpers' property must be an object literal`,
prop.start prop
); );
} }
@ -26,14 +26,14 @@ export default function helpers(validator: Validator, prop: Node) {
if (isThisGetCallExpression(node) && !node.callee.property.computed) { if (isThisGetCallExpression(node) && !node.callee.property.computed) {
validator.error( validator.error(
`Cannot use this.get(...) — values must be passed into the helper function as arguments`, `Cannot use this.get(...) — values must be passed into the helper function as arguments`,
node.start node
); );
} }
if (node.type === 'ThisExpression') { if (node.type === 'ThisExpression') {
validator.error( validator.error(
`Helpers should be pure functions — they do not have access to the component instance and cannot use 'this'. Did you mean to put this in 'methods'?`, `Helpers should be pure functions — they do not have access to the component instance and cannot use 'this'. Did you mean to put this in 'methods'?`,
node.start node
); );
} else if (node.type === 'Identifier' && node.name === 'arguments') { } else if (node.type === 'Identifier' && node.name === 'arguments') {
usesArguments = true; usesArguments = true;
@ -43,7 +43,7 @@ export default function helpers(validator: Validator, prop: Node) {
if (prop.value.params.length === 0 && !usesArguments) { if (prop.value.params.length === 0 && !usesArguments) {
validator.warn( validator.warn(
`Helpers should be pure functions, with at least one argument`, `Helpers should be pure functions, with at least one argument`,
prop.start prop
); );
} }
}); });

@ -5,7 +5,7 @@ export default function immutable(validator: Validator, prop: Node) {
if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'boolean') { if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'boolean') {
validator.error( validator.error(
`'immutable' must be a boolean literal`, `'immutable' must be a boolean literal`,
prop.value.start prop.value
); );
} }
} }

@ -12,7 +12,7 @@ export default function methods(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'methods' property must be an object literal`, `The 'methods' property must be an object literal`,
prop.start prop
); );
} }
@ -26,7 +26,7 @@ export default function methods(validator: Validator, prop: Node) {
if (builtin.has(name)) { if (builtin.has(name)) {
validator.error( validator.error(
`Cannot overwrite built-in method '${name}'`, `Cannot overwrite built-in method '${name}'`,
prop.start prop
); );
} }
@ -35,7 +35,7 @@ export default function methods(validator: Validator, prop: Node) {
validator.error( validator.error(
`Method '${prop.key `Method '${prop.key
.name}' should be a function expression, not an arrow function expression`, .name}' should be a function expression, not an arrow function expression`,
prop.start prop
); );
} }
} }

@ -11,7 +11,7 @@ export default function namespace(validator: Validator, prop: Node) {
if (prop.value.type !== 'Literal' || typeof ns !== 'string') { if (prop.value.type !== 'Literal' || typeof ns !== 'string') {
validator.error( validator.error(
`The 'namespace' property must be a string literal representing a valid namespace`, `The 'namespace' property must be a string literal representing a valid namespace`,
prop.start prop
); );
} }
@ -20,10 +20,10 @@ export default function namespace(validator: Validator, prop: Node) {
if (match) { if (match) {
validator.error( validator.error(
`Invalid namespace '${ns}' (did you mean '${match}'?)`, `Invalid namespace '${ns}' (did you mean '${match}'?)`,
prop.start prop
); );
} else { } else {
validator.error(`Invalid namespace '${ns}'`, prop.start); validator.error(`Invalid namespace '${ns}'`, prop);
} }
} }
} }

@ -7,7 +7,7 @@ export default function oncreate(validator: Validator, prop: Node) {
if (usesThisOrArguments(prop.value.body)) { if (usesThisOrArguments(prop.value.body)) {
validator.error( validator.error(
`'oncreate' should be a function expression, not an arrow function expression`, `'oncreate' should be a function expression, not an arrow function expression`,
prop.start prop
); );
} }
} }

@ -7,7 +7,7 @@ export default function ondestroy(validator: Validator, prop: Node) {
if (usesThisOrArguments(prop.value.body)) { if (usesThisOrArguments(prop.value.body)) {
validator.error( validator.error(
`'ondestroy' should be a function expression, not an arrow function expression`, `'ondestroy' should be a function expression, not an arrow function expression`,
prop.start prop
); );
} }
} }

@ -5,7 +5,7 @@ import { Node } from '../../../interfaces';
export default function onrender(validator: Validator, prop: Node) { export default function onrender(validator: Validator, prop: Node) {
validator.warn( validator.warn(
`'onrender' has been deprecated in favour of 'oncreate', and will cause an error in Svelte 2.x`, `'onrender' has been deprecated in favour of 'oncreate', and will cause an error in Svelte 2.x`,
prop.start prop
); );
oncreate(validator, prop); oncreate(validator, prop);
} }

@ -5,7 +5,7 @@ import { Node } from '../../../interfaces';
export default function onteardown(validator: Validator, prop: Node) { export default function onteardown(validator: Validator, prop: Node) {
validator.warn( validator.warn(
`'onteardown' has been deprecated in favour of 'ondestroy', and will cause an error in Svelte 2.x`, `'onteardown' has been deprecated in favour of 'ondestroy', and will cause an error in Svelte 2.x`,
prop.start prop
); );
ondestroy(validator, prop); ondestroy(validator, prop);
} }

@ -5,7 +5,7 @@ export default function props(validator: Validator, prop: Node) {
if (prop.value.type !== 'ArrayExpression') { if (prop.value.type !== 'ArrayExpression') {
validator.error( validator.error(
`'props' must be an array expression, if specified`, `'props' must be an array expression, if specified`,
prop.value.start prop.value
); );
} }
@ -13,7 +13,7 @@ export default function props(validator: Validator, prop: Node) {
if (element.type !== 'Literal' || typeof element.value !== 'string') { if (element.type !== 'Literal' || typeof element.value !== 'string') {
validator.error( validator.error(
`'props' must be an array of string literals`, `'props' must be an array of string literals`,
element.start element
); );
} }
}); });

@ -7,6 +7,6 @@ export default function setup(validator: Validator, prop: Node) {
while (prop.type === 'ParenthesizedExpression') prop = prop.expression; while (prop.type === 'ParenthesizedExpression') prop = prop.expression;
if (disallowed.has(prop.value.type)) { if (disallowed.has(prop.value.type)) {
validator.error(`'setup' must be a function`, prop.value.start); validator.error(`'setup' must be a function`, prop.value);
} }
} }

@ -5,7 +5,7 @@ export default function tag(validator: Validator, prop: Node) {
if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'string') { if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'string') {
validator.error( validator.error(
`'tag' must be a string literal`, `'tag' must be a string literal`,
prop.value.start prop.value
); );
} }
@ -13,7 +13,7 @@ export default function tag(validator: Validator, prop: Node) {
if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) { if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) {
validator.error( validator.error(
`tag name must be two or more words joined by the '-' character`, `tag name must be two or more words joined by the '-' character`,
prop.value.start prop.value
); );
} }
} }

@ -7,7 +7,7 @@ export default function transitions(validator: Validator, prop: Node) {
if (prop.value.type !== 'ObjectExpression') { if (prop.value.type !== 'ObjectExpression') {
validator.error( validator.error(
`The 'transitions' property must be an object literal`, `The 'transitions' property must be an object literal`,
prop.start prop
); );
} }

@ -8,7 +8,7 @@ export default function checkForAccessors(
) { ) {
properties.forEach(prop => { properties.forEach(prop => {
if (prop.kind !== 'init') { if (prop.kind !== 'init') {
validator.error(`${label} cannot use getters and setters`, prop.start); validator.error(`${label} cannot use getters and setters`, prop);
} }
}); });
} }

@ -7,7 +7,7 @@ export default function checkForComputedKeys(
) { ) {
properties.forEach(prop => { properties.forEach(prop => {
if (prop.key.computed) { if (prop.key.computed) {
validator.error(`Cannot use computed keys`, prop.start); validator.error(`Cannot use computed keys`, prop);
} }
}); });
} }

@ -12,7 +12,7 @@ export default function checkForDupes(
const name = getName(prop.key); const name = getName(prop.key);
if (seen.has(name)) { if (seen.has(name)) {
validator.error(`Duplicate property '${name}'`, prop.start); validator.error(`Duplicate property '${name}'`, prop);
} }
seen.add(name); seen.add(name);

@ -31,7 +31,8 @@ describe("validate", () => {
warnings.push({ warnings.push({
message: warning.message, message: warning.message,
pos: warning.pos, pos: warning.pos,
loc: warning.loc loc: warning.loc,
end: warning.end,
}); });
}, },
dev: config.dev dev: config.dev
@ -55,6 +56,7 @@ describe("validate", () => {
assert.equal(error.message, expected.message); assert.equal(error.message, expected.message);
assert.deepEqual(error.loc, expected.loc); assert.deepEqual(error.loc, expected.loc);
assert.deepEqual(error.end, expected.end);
assert.equal(error.pos, expected.pos); assert.equal(error.pos, expected.pos);
} }
}); });

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 19
},
"pos": 0 "pos": 0
}, },
@ -14,6 +18,10 @@
"line": 4, "line": 4,
"column": 1 "column": 1
}, },
"end": {
"line": 4,
"column": 7
},
"pos": 28 "pos": 28
}, },
@ -23,6 +31,10 @@
"line": 7, "line": 7,
"column": 0 "column": 0
}, },
"end": {
"line": 7,
"column": 17
},
"pos": 43 "pos": 43
}, },
@ -32,6 +44,10 @@
"line": 9, "line": 9,
"column": 0 "column": 0
}, },
"end": {
"line": 9,
"column": 20
},
"pos": 62 "pos": 62
} }
] ]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 19
},
"pos": 0 "pos": 0
}] }]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 11 "column": 11
}, },
"end": {
"line": 1,
"column": 37
},
"pos": 11 "pos": 11
}, },
{ {
@ -13,6 +17,10 @@
"line": 2, "line": 2,
"column": 14 "column": 14
}, },
"end": {
"line": 2,
"column": 27
},
"pos": 65 "pos": 65
}, },
{ {
@ -21,6 +29,10 @@
"line": 3, "line": 3,
"column": 14 "column": 14
}, },
"end": {
"line": 3,
"column": 28
},
"pos": 130 "pos": 130
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 26
},
"pos": 0 "pos": 0
}, },
{ {
@ -13,6 +17,10 @@
"line": 2, "line": 2,
"column": 3 "column": 3
}, },
"end": {
"line": 2,
"column": 10
},
"pos": 30 "pos": 30
}, },
{ {
@ -21,6 +29,10 @@
"line": 3, "line": 3,
"column": 3 "column": 3
}, },
"end": {
"line": 3,
"column": 11
},
"pos": 53 "pos": 53
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 20 "column": 20
}, },
"end": {
"line": 1,
"column": 40
},
"pos": 20 "pos": 20
}, },
@ -14,6 +18,10 @@
"column": 0, "column": 0,
"line": 1 "line": 1
}, },
"end": {
"line": 1,
"column": 41
},
"pos": 0 "pos": 0
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 5 "column": 5
}, },
"end": {
"line": 1,
"column": 20
},
"pos": 5 "pos": 5
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 6 "column": 6
}, },
"end": {
"line": 1,
"column": 25
},
"pos": 6 "pos": 6
}, },
@ -14,6 +18,10 @@
"line": 2, "line": 2,
"column": 6 "column": 6
}, },
"end": {
"line": 2,
"column": 20
},
"pos": 33 "pos": 33
} }
] ]

@ -5,6 +5,10 @@
"line": 4, "line": 4,
"column": 1 "column": 1
}, },
"end": {
"line": 6,
"column": 14
},
"pos": 57 "pos": 57
}, },
{ {
@ -13,6 +17,10 @@
"line": 15, "line": 15,
"column": 2 "column": 2
}, },
"end": {
"line": 17,
"column": 15
},
"pos": 252 "pos": 252
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 9
},
"pos": 0 "pos": 0
}, },
@ -14,6 +18,10 @@
"line": 2, "line": 2,
"column": 4 "column": 4
}, },
"end": {
"line": 2,
"column": 15
},
"pos": 14 "pos": 14
} }
] ]

@ -4,6 +4,10 @@
"column": 0, "column": 0,
"line": 5 "line": 5
}, },
"end": {
"line": 5,
"column": 13
},
"message": "A11y: <html> element should have a lang attribute", "message": "A11y: <html> element should have a lang attribute",
"pos": 84 "pos": 84
} }

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 31
},
"pos": 0 "pos": 0
} }
] ]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 5 "column": 5
}, },
"end": {
"line": 1,
"column": 18
},
"pos": 5 "pos": 5
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 5 "column": 5
}, },
"end": {
"line": 1,
"column": 14
},
"pos": 5 "pos": 5
}] }]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 1,
"column": 10
},
"pos": 0 "pos": 0
}, },
@ -14,6 +18,10 @@
"line": 2, "line": 2,
"column": 0 "column": 0
}, },
"end": {
"line": 2,
"column": 8
},
"pos": 11 "pos": 11
} }
] ]

@ -5,6 +5,10 @@
"column": 8, "column": 8,
"line": 2 "line": 2
}, },
"end": {
"line": 2,
"column": 17
},
"pos": 29 "pos": 29
} }
] ]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 5 "column": 5
}, },
"end": {
"line": 1,
"column": 10
},
"pos": 5 "pos": 5
} }
] ]

@ -5,6 +5,10 @@
"line": 3, "line": 3,
"column": 5 "column": 5
}, },
"end": {
"line": 3,
"column": 17
},
"pos": 46 "pos": 46
} }
] ]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 7 "column": 7
}, },
"end": {
"line": 1,
"column": 25
},
"pos": 7 "pos": 7
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 24 "column": 24
}, },
"end": {
"line": 1,
"column": 28
},
"pos": 24 "pos": 24
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 24 "column": 24
}, },
"end": {
"line": 1,
"column": 44
},
"pos": 24 "pos": 24
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 1, "line": 1,
"column": 5 "column": 5
},
"end": {
"line": 1,
"column": 15
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 1, "line": 1,
"column": 5 "column": 5
},
"end": {
"line": 1,
"column": 18
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 6, "line": 6,
"column": 3 "column": 3
},
"end": {
"line": 6,
"column": 8
} }
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 6 "column": 6
}, },
"end": {
"line": 1,
"column": 20
},
"pos": 6 "pos": 6
}] }]

@ -4,5 +4,9 @@
"line": 2, "line": 2,
"column": 9 "column": 9
}, },
"end": {
"line": 2,
"column": 23
},
"pos": 18 "pos": 18
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 6 "column": 6
}, },
"end": {
"line": 1,
"column": 20
},
"pos": 6 "pos": 6
}] }]

@ -4,5 +4,9 @@
"line": 2, "line": 2,
"column": 1 "column": 1
}, },
"end": {
"line": 2,
"column": 1
},
"pos": 27 "pos": 27
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 7 "column": 7
}, },
"end": {
"line": 3,
"column": 17
},
"pos": 43 "pos": 43
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 7 "column": 7
}, },
"end": {
"line": 3,
"column": 17
},
"pos": 31 "pos": 31
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 7, "line": 7,
"column": 4 "column": 4
},
"end": {
"line": 7,
"column": 8
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 7, "line": 7,
"column": 11 "column": 11
},
"end": {
"line": 7,
"column": 28
} }
}] }]

@ -4,5 +4,9 @@
"line": 2, "line": 2,
"column": 6 "column": 6
}, },
"end": {
"line": 2,
"column": 19
},
"pos": 14 "pos": 14
}] }]

@ -4,5 +4,9 @@
"line": 2, "line": 2,
"column": 5 "column": 5
}, },
"end": {
"line": 2,
"column": 18
},
"pos": 13 "pos": 13
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 18 "column": 18
}, },
"end": {
"line": 1,
"column": 18
},
"pos": 18 "pos": 18
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 17 "column": 17
}, },
"end": {
"line": 1,
"column": 17
},
"pos": 17 "pos": 17
}] }]

@ -5,6 +5,10 @@
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": {
"line": 3,
"column": 9
},
"pos": 0 "pos": 0
}, },
{ {
@ -13,6 +17,10 @@
"line": 5, "line": 5,
"column": 0 "column": 0
}, },
"end": {
"line": 5,
"column": 34
},
"pos": 38 "pos": 38
} }
] ]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 2, "line": 2,
"column": 18 "column": 18
},
"end": {
"line": 2,
"column": 35
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 3, "line": 3,
"column": 8 "column": 8
},
"end": {
"line": 3,
"column": 8
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 2, "line": 2,
"column": 16 "column": 16
},
"end": {
"line": 2,
"column": 22
} }
}] }]

@ -4,5 +4,9 @@
"line": 1, "line": 1,
"column": 18 "column": 18
}, },
"end": {
"line": 1,
"column": 23
},
"pos": 18 "pos": 18
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 6, "line": 6,
"column": 3 "column": 3
},
"end": {
"line": 8,
"column": 4
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 7, "line": 7,
"column": 4 "column": 4
},
"end": {
"line": 7,
"column": 8
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 7, "line": 7,
"column": 11 "column": 11
},
"end": {
"line": 7,
"column": 28
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 6, "line": 6,
"column": 3 "column": 3
},
"end": {
"line": 8,
"column": 4
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 1, "line": 1,
"column": 18 "column": 18
},
"end": {
"line": 1,
"column": 23
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 1, "line": 1,
"column": 18 "column": 18
},
"end": {
"line": 1,
"column": 23
} }
}] }]

@ -4,5 +4,9 @@
"line": 2, "line": 2,
"column": 1 "column": 1
}, },
"end": {
"line": 2,
"column": 10
},
"pos": 7 "pos": 7
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 2, "line": 2,
"column": 1 "column": 1
},
"end": {
"line": 2,
"column": 21
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 3, "line": 3,
"column": 2 "column": 2
},
"end": {
"line": 3,
"column": 18
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 3, "line": 3,
"column": 2 "column": 2
},
"end": {
"line": 3,
"column": 41
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 5, "line": 5,
"column": 2 "column": 2
},
"end": {
"line": 5,
"column": 11
} }
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 2 "column": 2
}, },
"end": {
"line": 3,
"column": 37
},
"pos": 29 "pos": 29
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 2 "column": 2
}, },
"end": {
"line": 3,
"column": 33
},
"pos": 29 "pos": 29
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 2 "column": 2
}, },
"end": {
"line": 3,
"column": 34
},
"pos": 29 "pos": 29
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 2 "column": 2
}, },
"end": {
"line": 3,
"column": 34
},
"pos": 29 "pos": 29
}] }]

@ -4,5 +4,9 @@
"line": 3, "line": 3,
"column": 2 "column": 2
}, },
"end": {
"line": 3,
"column": 38
},
"pos": 29 "pos": 29
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 3, "line": 3,
"column": 2 "column": 2
},
"end": {
"line": 5,
"column": 3
} }
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 3, "line": 3,
"column": 2 "column": 2
},
"end": {
"line": 5,
"column": 3
} }
}] }]

@ -4,5 +4,9 @@
"line": 6, "line": 6,
"column": 3 "column": 3
}, },
"end": {
"line": 6,
"column": 6
},
"pos": 59 "pos": 59
}] }]

@ -5,5 +5,9 @@
"line": 9, "line": 9,
"column": 3 "column": 3
}, },
"end": {
"line": 9,
"column": 18
},
"pos": 87 "pos": 87
}] }]

@ -4,5 +4,9 @@
"line": 5, "line": 5,
"column": 2 "column": 2
}, },
"end": {
"line": 5,
"column": 23
},
"pos": 42 "pos": 42
}] }]

@ -4,5 +4,9 @@
"line": 6, "line": 6,
"column": 8 "column": 8
}, },
"end": {
"line": 6,
"column": 20
},
"pos": 62 "pos": 62
}] }]

@ -4,5 +4,9 @@
"line": 9, "line": 9,
"column": 3 "column": 3
}, },
"end": {
"line": 9,
"column": 28
},
"pos": 87 "pos": 87
}] }]

@ -4,5 +4,9 @@
"line": 6, "line": 6,
"column": 8 "column": 8
}, },
"end": {
"line": 6,
"column": 16
},
"pos": 62 "pos": 62
}] }]

@ -4,5 +4,9 @@
"loc": { "loc": {
"line": 4, "line": 4,
"column": 8 "column": 8
},
"end": {
"line": 4,
"column": 16
} }
}] }]

@ -4,5 +4,9 @@
"line": 5, "line": 5,
"column": 8 "column": 8
}, },
"end": {
"line": 7,
"column": 3
},
"pos": 48 "pos": 48
}] }]

@ -4,5 +4,9 @@
"line": 9, "line": 9,
"column": 2 "column": 2
}, },
"end": {
"line": 11,
"column": 3
},
"pos": 74 "pos": 74
}] }]

@ -4,5 +4,9 @@
"line": 4, "line": 4,
"column": 3 "column": 3
}, },
"end": {
"line": 6,
"column": 4
},
"pos": 43 "pos": 43
}] }]

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save