mirror of https://github.com/sveltejs/svelte
parent
1638aec061
commit
d704bac8e7
@ -1,16 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function actions(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-actions`,
|
||||
message: `The 'actions' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function transitions(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-transitions-property`,
|
||||
message: `The 'transitions' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach(() => {
|
||||
// TODO probably some validation that can happen here...
|
||||
// checking for use of `this` etc?
|
||||
});
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import getName from '../../../../utils/getName';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function components(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-components-property`,
|
||||
message: `The 'components' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach((node: Node) => {
|
||||
const name = getName(node.key);
|
||||
|
||||
if (name === 'state') {
|
||||
// TODO is this still true?
|
||||
component.error(node, {
|
||||
code: `invalid-name`,
|
||||
message: `Component constructors cannot be called 'state' due to technical limitations`
|
||||
});
|
||||
}
|
||||
|
||||
if (!/^[A-Z]/.test(name)) {
|
||||
component.error(node, {
|
||||
code: `component-lowercase`,
|
||||
message: `Component names must be capitalised`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import getName from '../../../../utils/getName';
|
||||
import isValidIdentifier from '../../../../utils/isValidIdentifier';
|
||||
import reservedNames from '../../../../utils/reservedNames';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import walkThroughTopFunctionScope from '../../../../utils/walkThroughTopFunctionScope';
|
||||
import isThisGetCallExpression from '../../../../utils/isThisGetCallExpression';
|
||||
import Component from '../../../Component';
|
||||
|
||||
const isFunctionExpression = new Set([
|
||||
'FunctionExpression',
|
||||
'ArrowFunctionExpression',
|
||||
]);
|
||||
|
||||
export default function computed(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-computed-property`,
|
||||
message: `The 'computed' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach((computation: Node) => {
|
||||
const name = getName(computation.key);
|
||||
|
||||
if (!isValidIdentifier(name)) {
|
||||
const suggestion = name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&');
|
||||
component.error(computation.key, {
|
||||
code: `invalid-computed-name`,
|
||||
message: `Computed property name '${name}' is invalid — must be a valid identifier such as ${suggestion}`
|
||||
});
|
||||
}
|
||||
|
||||
if (reservedNames.has(name)) {
|
||||
component.error(computation.key, {
|
||||
code: `invalid-computed-name`,
|
||||
message: `Computed property name '${name}' is invalid — cannot be a JavaScript reserved word`
|
||||
});
|
||||
}
|
||||
|
||||
if (!isFunctionExpression.has(computation.value.type)) {
|
||||
component.error(computation.value, {
|
||||
code: `invalid-computed-value`,
|
||||
message: `Computed properties can be function expressions or arrow function expressions`
|
||||
});
|
||||
}
|
||||
|
||||
const { body, params } = computation.value;
|
||||
|
||||
walkThroughTopFunctionScope(body, (node: Node) => {
|
||||
if (isThisGetCallExpression(node) && !node.callee.property.computed) {
|
||||
component.error(node, {
|
||||
code: `impure-computed`,
|
||||
message: `Cannot use this.get(...) — values must be passed into the function as arguments`
|
||||
});
|
||||
}
|
||||
|
||||
if (node.type === 'ThisExpression') {
|
||||
component.error(node, {
|
||||
code: `impure-computed`,
|
||||
message: `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'?`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (params.length === 0) {
|
||||
component.error(computation.value, {
|
||||
code: `impure-computed`,
|
||||
message: `A computed value must depend on at least one property`
|
||||
});
|
||||
}
|
||||
|
||||
if (params.length > 1) {
|
||||
component.error(computation.value, {
|
||||
code: `invalid-computed-arguments`,
|
||||
message: `Computed properties must take a single argument`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
const disallowed = new Set(['Literal', 'ObjectExpression', 'ArrayExpression']);
|
||||
|
||||
export default function data(component: Component, prop: Node) {
|
||||
while (prop.type === 'ParenthesizedExpression') prop = prop.expression;
|
||||
|
||||
if (disallowed.has(prop.value.type)) {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-data-property`,
|
||||
message: `'data' must be a function`
|
||||
});
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function events(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-events-property`,
|
||||
message: `The 'events' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import walkThroughTopFunctionScope from '../../../../utils/walkThroughTopFunctionScope';
|
||||
import isThisGetCallExpression from '../../../../utils/isThisGetCallExpression';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function helpers(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-helpers-property`,
|
||||
message: `The 'helpers' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach((prop: Node) => {
|
||||
if (!/FunctionExpression/.test(prop.value.type)) return;
|
||||
|
||||
let usesArguments = false;
|
||||
|
||||
walkThroughTopFunctionScope(prop.value.body, (node: Node) => {
|
||||
if (isThisGetCallExpression(node) && !node.callee.property.computed) {
|
||||
component.error(node, {
|
||||
code: `impure-helper`,
|
||||
message: `Cannot use this.get(...) — values must be passed into the helper function as arguments`
|
||||
});
|
||||
}
|
||||
|
||||
if (node.type === 'ThisExpression') {
|
||||
component.error(node, {
|
||||
code: `impure-helper`,
|
||||
message: `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'?`
|
||||
});
|
||||
} else if (node.type === 'Identifier' && node.name === 'arguments') {
|
||||
usesArguments = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (prop.value.params.length === 0 && !usesArguments) {
|
||||
component.warn(prop, {
|
||||
code: `impure-helper`,
|
||||
message: `Helpers should be pure functions, with at least one argument`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function immutable(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'boolean') {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-immutable-property`,
|
||||
message: `'immutable' must be a boolean literal`
|
||||
});
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import data from './data';
|
||||
import actions from './actions';
|
||||
import animations from './animations';
|
||||
import computed from './computed';
|
||||
import oncreate from './oncreate';
|
||||
import ondestroy from './ondestroy';
|
||||
import onstate from './onstate';
|
||||
import onupdate from './onupdate';
|
||||
import onrender from './onrender';
|
||||
import onteardown from './onteardown';
|
||||
import helpers from './helpers';
|
||||
import methods from './methods';
|
||||
import components from './components';
|
||||
import events from './events';
|
||||
import namespace from './namespace';
|
||||
import preload from './preload';
|
||||
import props from './props';
|
||||
import tag from './tag';
|
||||
import transitions from './transitions';
|
||||
import setup from './setup';
|
||||
import store from './store';
|
||||
import immutable from './immutable';
|
||||
|
||||
export default {
|
||||
data,
|
||||
actions,
|
||||
animations,
|
||||
computed,
|
||||
oncreate,
|
||||
ondestroy,
|
||||
onstate,
|
||||
onupdate,
|
||||
onrender,
|
||||
onteardown,
|
||||
helpers,
|
||||
methods,
|
||||
components,
|
||||
events,
|
||||
namespace,
|
||||
preload,
|
||||
props,
|
||||
tag,
|
||||
transitions,
|
||||
setup,
|
||||
store,
|
||||
immutable,
|
||||
};
|
@ -1,42 +0,0 @@
|
||||
import checkForAccessors from '../utils/checkForAccessors';
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import usesThisOrArguments from '../utils/usesThisOrArguments';
|
||||
import getName from '../../../../utils/getName';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
const builtin = new Set(['set', 'get', 'on', 'fire', 'destroy']);
|
||||
|
||||
export default function methods(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-methods-property`,
|
||||
message: `The 'methods' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForAccessors(component, prop.value.properties, 'Methods');
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach((prop: Node) => {
|
||||
const name = getName(prop.key);
|
||||
|
||||
if (builtin.has(name)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-method-name`,
|
||||
message: `Cannot overwrite built-in method '${name}'`
|
||||
});
|
||||
}
|
||||
|
||||
if (prop.value.type === 'ArrowFunctionExpression') {
|
||||
if (usesThisOrArguments(prop.value.body)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-method-value`,
|
||||
message: `Method '${prop.key.name}' should be a function expression, not an arrow function expression`
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import * as namespaces from '../../../../utils/namespaces';
|
||||
import nodeToString from '../../../../utils/nodeToString'
|
||||
import fuzzymatch from '../../utils/fuzzymatch';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
const valid = new Set(namespaces.validNamespaces);
|
||||
|
||||
export default function namespace(component: Component, prop: Node) {
|
||||
const ns = nodeToString(prop.value);
|
||||
|
||||
if (typeof ns !== 'string') {
|
||||
component.error(prop, {
|
||||
code: `invalid-namespace-property`,
|
||||
message: `The 'namespace' property must be a string literal representing a valid namespace`
|
||||
});
|
||||
}
|
||||
|
||||
if (!valid.has(ns)) {
|
||||
const match = fuzzymatch(ns, namespaces.validNamespaces);
|
||||
if (match) {
|
||||
component.error(prop, {
|
||||
code: `invalid-namespace-property`,
|
||||
message: `Invalid namespace '${ns}' (did you mean '${match}'?)`
|
||||
});
|
||||
} else {
|
||||
component.error(prop, {
|
||||
code: `invalid-namespace-property`,
|
||||
message: `Invalid namespace '${ns}'`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import usesThisOrArguments from '../utils/usesThisOrArguments';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function oncreate(component: Component, prop: Node) {
|
||||
if (prop.value.type === 'ArrowFunctionExpression') {
|
||||
if (usesThisOrArguments(prop.value.body)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-oncreate-property`,
|
||||
message: `'oncreate' should be a function expression, not an arrow function expression`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import usesThisOrArguments from '../utils/usesThisOrArguments';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function ondestroy(component: Component, prop: Node) {
|
||||
if (prop.value.type === 'ArrowFunctionExpression') {
|
||||
if (usesThisOrArguments(prop.value.body)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-ondestroy-property`,
|
||||
message: `'ondestroy' should be a function expression, not an arrow function expression`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import oncreate from './oncreate';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function onrender(component: Component, prop: Node) {
|
||||
component.warn(prop, {
|
||||
code: `deprecated-onrender`,
|
||||
message: `'onrender' has been deprecated in favour of 'oncreate', and will cause an error in Svelte 2.x`
|
||||
});
|
||||
|
||||
oncreate(component, prop);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import usesThisOrArguments from '../utils/usesThisOrArguments';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function onstate(component: Component, prop: Node) {
|
||||
if (prop.value.type === 'ArrowFunctionExpression') {
|
||||
if (usesThisOrArguments(prop.value.body)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-onstate-property`,
|
||||
message: `'onstate' should be a function expression, not an arrow function expression`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import ondestroy from './ondestroy';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function onteardown(component: Component, prop: Node) {
|
||||
component.warn(prop, {
|
||||
code: `deprecated-onteardown`,
|
||||
message: `'onteardown' has been deprecated in favour of 'ondestroy', and will cause an error in Svelte 2.x`
|
||||
});
|
||||
|
||||
ondestroy(component, prop);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import usesThisOrArguments from '../utils/usesThisOrArguments';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function onupdate(component: Component, prop: Node) {
|
||||
if (prop.value.type === 'ArrowFunctionExpression') {
|
||||
if (usesThisOrArguments(prop.value.body)) {
|
||||
component.error(prop, {
|
||||
code: `invalid-onupdate-property`,
|
||||
message: `'onupdate' should be a function expression, not an arrow function expression`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function preload(component: Component, prop: Node) {
|
||||
// not sure there's anything we need to check here...
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import nodeToString from '../../../../utils/nodeToString';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function props(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ArrayExpression') {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-props-property`,
|
||||
message: `'props' must be an array expression, if specified`
|
||||
});
|
||||
}
|
||||
|
||||
prop.value.elements.forEach((element: Node) => {
|
||||
if (typeof nodeToString(element) !== 'string') {
|
||||
component.error(element, {
|
||||
code: `invalid-props-property`,
|
||||
message: `'props' must be an array of string literals`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
const disallowed = new Set(['Literal', 'ObjectExpression', 'ArrayExpression']);
|
||||
|
||||
export default function setup(component: Component, prop: Node) {
|
||||
while (prop.type === 'ParenthesizedExpression') prop = prop.expression;
|
||||
|
||||
if (disallowed.has(prop.value.type)) {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-setup-property`,
|
||||
message: `'setup' must be a function`
|
||||
});
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function store(component: Component, prop: Node) {
|
||||
// not sure there's anything we need to check here...
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { Node } from '../../../../interfaces';
|
||||
import nodeToString from '../../../../utils/nodeToString';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function tag(component: Component, prop: Node) {
|
||||
const tag = nodeToString(prop.value);
|
||||
if (typeof tag !== 'string') {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-tag-property`,
|
||||
message: `'tag' must be a string literal`
|
||||
});
|
||||
}
|
||||
|
||||
if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) {
|
||||
component.error(prop.value, {
|
||||
code: `invalid-tag-property`,
|
||||
message: `tag name must be two or more words joined by the '-' character`
|
||||
});
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import checkForDupes from '../utils/checkForDupes';
|
||||
import checkForComputedKeys from '../utils/checkForComputedKeys';
|
||||
import { Node } from '../../../../interfaces';
|
||||
import Component from '../../../Component';
|
||||
|
||||
export default function transitions(component: Component, prop: Node) {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
component.error(prop, {
|
||||
code: `invalid-transitions-property`,
|
||||
message: `The 'transitions' property must be an object literal`
|
||||
});
|
||||
}
|
||||
|
||||
checkForDupes(component, prop.value.properties);
|
||||
checkForComputedKeys(component, prop.value.properties);
|
||||
|
||||
prop.value.properties.forEach(() => {
|
||||
// TODO probably some validation that can happen here...
|
||||
// checking for use of `this` etc?
|
||||
});
|
||||
}
|
Loading…
Reference in new issue