mirror of https://github.com/sveltejs/svelte
parent
a023f2e049
commit
349aa0bbac
@ -1,17 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function checkForAccessors(
|
||||
component: Component,
|
||||
properties: Node[],
|
||||
label: string
|
||||
) {
|
||||
properties.forEach(prop => {
|
||||
if (prop.kind !== 'init') {
|
||||
component.error(prop, {
|
||||
code: `illegal-accessor`,
|
||||
message: `${label} cannot use getters and setters`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function checkForComputedKeys(
|
||||
component: Component,
|
||||
properties: Node[]
|
||||
) {
|
||||
properties.forEach(prop => {
|
||||
if (prop.key.computed) {
|
||||
component.error(prop, {
|
||||
code: `computed-key`,
|
||||
message: `Cannot use computed keys`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import getName from '../../../../utils/getName';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function checkForDupes(
|
||||
component: Component,
|
||||
properties: Node[]
|
||||
) {
|
||||
const seen = new Set();
|
||||
|
||||
properties.forEach(prop => {
|
||||
const name = getName(prop.key);
|
||||
|
||||
if (seen.has(name)) {
|
||||
component.error(prop, {
|
||||
code: `duplicate-property`,
|
||||
message: `Duplicate property '${name}'`
|
||||
});
|
||||
}
|
||||
|
||||
seen.add(name);
|
||||
});
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import { walk } from 'estree-walker';
|
||||
import isReference from 'is-reference';
|
||||
import { Node } from '../../../../interfaces';
|
||||
|
||||
export default function usesThisOrArguments(node: Node) {
|
||||
let result = false;
|
||||
|
||||
walk(node, {
|
||||
enter(node: Node, parent: Node) {
|
||||
if (
|
||||
result ||
|
||||
node.type === 'FunctionExpression' ||
|
||||
node.type === 'FunctionDeclaration'
|
||||
) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (node.type === 'ThisExpression') {
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (
|
||||
node.type === 'Identifier' &&
|
||||
isReference(node, parent) &&
|
||||
node.name === 'arguments'
|
||||
) {
|
||||
result = true;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import FuzzySet from './FuzzySet';
|
||||
|
||||
export default function fuzzymatch(name: string, names: string[]) {
|
||||
const set = new FuzzySet(names);
|
||||
const matches = set.get(name);
|
||||
|
||||
return matches && matches[0] && matches[0][0] > 0.7 ? matches[0][1] : null;
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
import { parseExpressionAt } from 'acorn';
|
||||
import { Parser } from '../index';
|
||||
|
||||
const DIRECTIVES: Record<string, {
|
||||
names: string[];
|
||||
attribute: (
|
||||
start: number,
|
||||
end: number,
|
||||
type: string,
|
||||
name: string,
|
||||
expression?: any,
|
||||
directiveName?: string
|
||||
) => { start: number, end: number, type: string, name: string, value?: any, expression?: any };
|
||||
allowedExpressionTypes: string[];
|
||||
error: string;
|
||||
}> = {
|
||||
Ref: {
|
||||
names: ['ref'],
|
||||
attribute(start, end, type, name) {
|
||||
return { start, end, type, name };
|
||||
},
|
||||
allowedExpressionTypes: [],
|
||||
error: 'ref directives cannot have a value'
|
||||
},
|
||||
|
||||
EventHandler: {
|
||||
names: ['on'],
|
||||
attribute(start, end, type, lhs, expression) {
|
||||
const [name, ...modifiers] = lhs.split('|');
|
||||
return { start, end, type, name, modifiers, expression };
|
||||
},
|
||||
allowedExpressionTypes: ['CallExpression'],
|
||||
error: 'Expected a method call'
|
||||
},
|
||||
|
||||
Binding: {
|
||||
names: ['bind'],
|
||||
attribute(start, end, type, name, expression) {
|
||||
return {
|
||||
start, end, type, name,
|
||||
value: expression || {
|
||||
type: 'Identifier',
|
||||
start: start + 5,
|
||||
end,
|
||||
name,
|
||||
}
|
||||
};
|
||||
},
|
||||
allowedExpressionTypes: ['Identifier', 'MemberExpression'],
|
||||
error: 'Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)'
|
||||
},
|
||||
|
||||
Transition: {
|
||||
names: ['in', 'out', 'transition'],
|
||||
attribute(start, end, type, name, expression, directiveName) {
|
||||
return {
|
||||
start, end, type, name, expression,
|
||||
intro: directiveName === 'in' || directiveName === 'transition',
|
||||
outro: directiveName === 'out' || directiveName === 'transition',
|
||||
};
|
||||
},
|
||||
allowedExpressionTypes: ['ObjectExpression'],
|
||||
error: 'Transition argument must be an object literal, e.g. `{ duration: 400 }`'
|
||||
},
|
||||
|
||||
Animation: {
|
||||
names: ['animate'],
|
||||
attribute(start, end, type, name, expression) {
|
||||
return { start, end, type, name, expression };
|
||||
},
|
||||
allowedExpressionTypes: ['ObjectExpression'],
|
||||
error: 'Animation argument must be an object literal, e.g. `{ duration: 400 }`'
|
||||
},
|
||||
|
||||
Action: {
|
||||
names: ['use'],
|
||||
attribute(start, end, type, name, expression) {
|
||||
return { start, end, type, name, expression };
|
||||
},
|
||||
allowedExpressionTypes: ['*'],
|
||||
error: 'Data passed to actions must be an identifier (e.g. `foo`), a member expression ' +
|
||||
'(e.g. `foo.bar` or `foo[baz]`), a method call (e.g. `foo()`), or a literal (e.g. `true` or `\'a string\'`'
|
||||
},
|
||||
|
||||
Class: {
|
||||
names: ['class'],
|
||||
attribute(start, end, type, name, expression) {
|
||||
return { start, end, type, name, expression };
|
||||
},
|
||||
allowedExpressionTypes: ['*'],
|
||||
error: 'Data passed to class directives must be an expression'
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const lookupByName = {};
|
||||
|
||||
Object.keys(DIRECTIVES).forEach(name => {
|
||||
const directive = DIRECTIVES[name];
|
||||
directive.names.forEach(type => lookupByName[type] = name);
|
||||
});
|
||||
|
||||
function readExpression(parser: Parser, start: number, quoteMark: string|null) {
|
||||
let i = start;
|
||||
let escaped = false;
|
||||
|
||||
for (; i < parser.template.length; i += 1) {
|
||||
const char = parser.template[i];
|
||||
|
||||
if (quoteMark) {
|
||||
if (char === quoteMark) {
|
||||
if (!escaped) break;
|
||||
} else if (escaped) {
|
||||
escaped = false;
|
||||
} else if (char === '\\') {
|
||||
escaped = true;
|
||||
}
|
||||
} else if (/[\s\/>]/.test(char)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const expression = parseExpressionAt(parser.template.slice(0, i), start, {
|
||||
ecmaVersion: 9,
|
||||
});
|
||||
parser.index = expression.end;
|
||||
|
||||
parser.allowWhitespace();
|
||||
if (quoteMark) parser.eat(quoteMark, true);
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
export function readDirective(
|
||||
parser: Parser,
|
||||
start: number,
|
||||
attrName: string
|
||||
) {
|
||||
const [directiveName, name] = attrName.split(':');
|
||||
if (name === undefined) return; // No colon in the name
|
||||
|
||||
if (directiveName === '') {
|
||||
// not a directive — :foo is short for foo={{foo}}
|
||||
return {
|
||||
start: start,
|
||||
end: start + name.length + 1,
|
||||
type: 'Attribute',
|
||||
name,
|
||||
value: getShorthandValue(start + 1, name)
|
||||
};
|
||||
}
|
||||
|
||||
const type = lookupByName[directiveName];
|
||||
if (!type) return; // not a registered directive
|
||||
|
||||
const directive = DIRECTIVES[type];
|
||||
let expression = null;
|
||||
|
||||
if (parser.eat('=')) {
|
||||
const quoteMark = parser.eat(`'`) ? `'` : parser.eat(`"`) ? `"` : null;
|
||||
|
||||
const expressionStart = parser.index;
|
||||
|
||||
try {
|
||||
expression = readExpression(parser, expressionStart, quoteMark);
|
||||
const allowed = directive.allowedExpressionTypes;
|
||||
if (allowed[0] !== '*' && allowed.indexOf(expression.type) === -1) {
|
||||
parser.error({
|
||||
code: `invalid-directive-value`,
|
||||
message: directive.error
|
||||
}, expressionStart);
|
||||
}
|
||||
} catch (err) {
|
||||
if (parser.template[expressionStart] === '{') {
|
||||
// assume the mistake was wrapping the directive arguments.
|
||||
// this could yield false positives! but hopefully not too many
|
||||
let message = 'directive values should not be wrapped';
|
||||
const expressionEnd = parser.template.indexOf('}', expressionStart);
|
||||
if (expressionEnd !== -1) {
|
||||
const value = parser.template.slice(expressionStart + 1, expressionEnd);
|
||||
message += ` — use '${value}', not '{${value}}'`;
|
||||
}
|
||||
parser.error({
|
||||
code: `invalid-directive-value`,
|
||||
message
|
||||
}, expressionStart);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return directive.attribute(start, parser.index, type, name, expression, directiveName);
|
||||
}
|
||||
|
||||
|
||||
function getShorthandValue(start: number, name: string) {
|
||||
const end = start + name.length;
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'AttributeShorthand',
|
||||
start,
|
||||
end,
|
||||
expression: {
|
||||
type: 'Identifier',
|
||||
start,
|
||||
end,
|
||||
name,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { Node } from '../interfaces';
|
||||
|
||||
export default function getMethodName(node: Node) {
|
||||
if (node.type === 'Identifier') return node.name;
|
||||
if (node.type === 'Literal') return String(node.value);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { Node } from '../interfaces';
|
||||
|
||||
export default function isThisGetCallExpression(node: Node): boolean {
|
||||
return node.type === 'CallExpression' &&
|
||||
node.callee.type === 'MemberExpression' &&
|
||||
node.callee.object.type === 'ThisExpression' &&
|
||||
node.callee.property.name === 'get';
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { Node } from '../interfaces';
|
||||
|
||||
export default function nodeToString(node: Node) {
|
||||
if (node.type === 'Literal' && typeof node.value === 'string') {
|
||||
return node.value;
|
||||
} else if (node.type === 'TemplateLiteral'
|
||||
&& node.quasis.length === 1
|
||||
&& node.expressions.length === 0) {
|
||||
return node.quasis[0].value.raw;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
const validCalleeObjects = new Set(['this', 'event', 'console']);
|
||||
|
||||
export default validCalleeObjects;
|
@ -1,21 +0,0 @@
|
||||
import { Node } from '../interfaces';
|
||||
import { walk } from 'estree-walker';
|
||||
|
||||
export default function walkThroughTopFunctionScope(body: Node, callback: Function) {
|
||||
let lexicalDepth = 0;
|
||||
walk(body, {
|
||||
enter(node: Node) {
|
||||
if (/^Function/.test(node.type)) {
|
||||
lexicalDepth += 1;
|
||||
} else if (lexicalDepth === 0) {
|
||||
callback(node)
|
||||
}
|
||||
},
|
||||
|
||||
leave(node: Node) {
|
||||
if (/^Function/.test(node.type)) {
|
||||
lexicalDepth -= 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
Loading…
Reference in new issue