Merge branch 'master' into gh-371

pull/391/head
Rich Harris 8 years ago committed by GitHub
commit 3ead9bfc3f

@ -18,15 +18,15 @@ export default class Generator {
this.options = options;
this.imports = [];
this.helpers = {};
this.components = {};
this.events = {};
this.helpers = new Set();
this.components = new Set();
this.events = new Set();
this.bindingGroups = [];
// track which properties are needed, so we can provide useful info
// in dev mode
this.expectedProperties = {};
this.expectedProperties = new Set();
this.elementDepth = 0;
@ -37,11 +37,11 @@ export default class Generator {
// allow compiler to deconflict user's `import { get } from 'whatever'` and
// Svelte's builtin `import { get, ... } from 'svelte/shared.js'`;
this.importedNames = {};
this.importedNames = new Set();
this.aliases = {};
this.aliases = new Map();
this._callbacks = {};
this._callbacks = new Map();
}
addSourcemapLocations ( node ) {
@ -54,17 +54,17 @@ export default class Generator {
}
alias ( name ) {
if ( !( name in this.aliases ) ) {
if ( !( this.aliases.has( name ) ) ) {
let alias = name;
let i = 1;
while ( alias in this.importedNames ) {
alias = `${name}$${i++}`;
}
this.aliases[ name ] = alias;
this.aliases.set( name, alias );
}
return this.aliases[ name ];
return this.aliases.get( name );
}
contextualise ( expression, isEventHandler ) {
@ -91,7 +91,7 @@ export default class Generator {
const { name } = flattenReference( node );
if ( scope.has( name ) ) return;
if ( parent && parent.type === 'CallExpression' && node === parent.callee && helpers[ name ] ) {
if ( parent && parent.type === 'CallExpression' && node === parent.callee && helpers.has( name ) ) {
code.prependRight( node.start, `${self.alias( 'template' )}.helpers.` );
}
@ -99,19 +99,19 @@ export default class Generator {
// noop
}
else if ( name in contexts ) {
const context = contexts[ name ];
else if ( contexts.has( name ) ) {
const context = contexts.get( name );
if ( context !== name ) {
// this is true for 'reserved' names like `root` and `component`
code.overwrite( node.start, node.start + name.length, context, true );
}
dependencies.push( ...contextDependencies[ name ] );
dependencies.push( ...contextDependencies.get( name ) );
if ( !~usedContexts.indexOf( name ) ) usedContexts.push( name );
}
else if ( indexes[ name ] ) {
const context = indexes[ name ];
else if ( indexes.has( name ) ) {
const context = indexes.get( name );
if ( !~usedContexts.indexOf( context ) ) usedContexts.push( context );
}
@ -145,7 +145,7 @@ export default class Generator {
});
dependencies.forEach( name => {
this.expectedProperties[ name ] = true;
this.expectedProperties.add( name );
});
return {
@ -157,7 +157,7 @@ export default class Generator {
}
fire ( eventName, data ) {
const handlers = eventName in this._callbacks && this._callbacks[ eventName ].slice();
const handlers = this._callbacks.has( eventName ) && this._callbacks.get( eventName ).slice();
if ( !handlers ) return;
for ( let i = 0; i < handlers.length; i += 1 ) {
@ -287,7 +287,7 @@ export default class Generator {
} else {
const { declarations } = annotateWithScopes( js );
let template = 'template';
for ( let i = 1; template in declarations; template = `template$${i++}` );
for ( let i = 1; declarations.has( template ); template = `template$${i++}` );
this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `var ${template} = ` );
@ -312,7 +312,7 @@ export default class Generator {
[ 'helpers', 'events', 'components' ].forEach( key => {
if ( templateProperties[ key ] ) {
templateProperties[ key ].value.properties.forEach( prop => {
this[ key ][ prop.key.name ] = prop.value;
this[ key ].add( prop.key.name );
});
}
});
@ -354,8 +354,11 @@ export default class Generator {
}
on ( eventName, handler ) {
const handlers = this._callbacks[ eventName ] || ( this._callbacks[ eventName ] = [] );
handlers.push( handler );
if ( this._callbacks.has( eventName ) ) {
this._callbacks.get( eventName ).push( handler );
} else {
this._callbacks.set( eventName, [ handler ] );
}
}
pop () {

@ -7,15 +7,15 @@ export default function annotateWithScopes ( expression ) {
enter ( node ) {
if ( /Function/.test( node.type ) ) {
if ( node.type === 'FunctionDeclaration' ) {
scope.declarations[ node.id.name ] = true;
scope.declarations.add( node.id.name );
} else {
node._scope = scope = new Scope( scope, false );
if ( node.id ) scope.declarations[ node.id.name ] = true;
if ( node.id ) scope.declarations.add( node.id.name );
}
node.params.forEach( param => {
extractNames( param ).forEach( name => {
scope.declarations[ name ] = true;
scope.declarations.add( name );
});
});
}
@ -47,7 +47,7 @@ class Scope {
constructor ( parent, block ) {
this.parent = parent;
this.block = block;
this.declarations = Object.create( null );
this.declarations = new Set();
}
addDeclaration ( node ) {
@ -56,16 +56,16 @@ class Scope {
} else if ( node.type === 'VariableDeclaration' ) {
node.declarations.forEach( declarator => {
extractNames( declarator.id ).forEach( name => {
this.declarations[ name ] = true;
this.declarations.add( name );
});
});
} else {
this.declarations[ node.id.name ] = true;
this.declarations.add( node.id.name );
}
}
has ( name ) {
return name in this.declarations || this.parent && this.parent.has( name );
return this.declarations.has( name ) || this.parent && this.parent.has( name );
}
}

@ -12,7 +12,7 @@ class DomGenerator extends Generator {
constructor ( parsed, source, name, names, visitors, options ) {
super( parsed, source, name, names, visitors, options );
this.renderers = [];
this.uses = {};
this.uses = new Set();
// allow compiler to deconflict user's `import { get } from 'whatever'` and
// Svelte's builtin `import { get, ... } from 'svelte/shared.js'`;
@ -24,7 +24,7 @@ class DomGenerator extends Generator {
metaBindings: new CodeBuilder()
};
this.importedComponents = {};
this.importedComponents = new Map();
}
addElement ( name, renderStatement, needsIdentifier = false ) {
@ -144,7 +144,7 @@ class DomGenerator extends Generator {
name = `${name}Dev`;
}
this.uses[ name ] = true;
this.uses.add( name );
return this.alias( name );
}
@ -184,15 +184,15 @@ export default function dom ( parsed, source, options, names ) {
templateProperties.components.value.properties.forEach( property => {
const key = property.key.name;
const value = source.slice( property.value.start, property.value.end );
if ( generator.importedNames[ value ] ) {
generator.importedComponents[ key ] = value;
if ( generator.importedNames.has( value ) ) {
generator.importedComponents.set( key, value );
} else {
hasNonImportedComponent = true;
}
});
if ( hasNonImportedComponent ) {
// remove the specific components that were imported, as we'll refer to them directly
Object.keys( generator.importedComponents ).forEach( key => {
Array.from( generator.importedComponents.keys() ).forEach( key => {
removeObjectKey( generator, templateProperties.components.value, key );
});
} else {
@ -208,12 +208,12 @@ export default function dom ( parsed, source, options, names ) {
localElementDepth: 0,
key: null,
contexts: {},
indexes: {},
contexts: new Map(),
indexes: new Map(),
params: [ 'root' ],
indexNames: {},
listNames: {},
indexNames: new Map(),
listNames: new Map(),
builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker()
@ -350,7 +350,7 @@ export default function dom ( parsed, source, options, names ) {
}
if ( options.dev ) {
Object.keys( generator.expectedProperties ).forEach( prop => {
generator.expectedProperties.forEach( prop => {
constructorBlock.addLine(
`if ( !( '${prop}' in this._state ) ) throw new Error( "Component was created without expected data property '${prop}'" );`
);
@ -422,17 +422,17 @@ export default function dom ( parsed, source, options, names ) {
throw new Error( `Components with shared helpers must be compiled to ES2015 modules (format: 'es')` );
}
const names = Object.keys( generator.uses ).map( name => {
return name !== generator.aliases[ name ] ? `${name} as ${generator.aliases[ name ]}` : name;
const names = Array.from( generator.uses ).map( name => {
return name !== generator.aliases.get( name ) ? `${name} as ${generator.aliases.get( name )}` : name;
});
builders.main.addLineAtStart(
`import { ${names.join( ', ' )} } from ${JSON.stringify( sharedPath )}`
);
} else {
Object.keys( generator.uses ).forEach( key => {
generator.uses.forEach( key => {
const fn = shared[ key ]; // eslint-disable-line import/namespace
builders.main.addBlock( fn.toString().replace( /^function [^(]*/, 'function ' + generator.aliases[ key ] ) );
builders.main.addBlock( fn.toString().replace( /^function [^(]*/, 'function ' + generator.aliases.get( key ) ) );
});
}

@ -32,8 +32,8 @@ export default {
const initialProps = local.allUsedContexts.map( contextName => {
if ( contextName === 'root' ) return `root: root`;
const listName = generator.current.listNames[ contextName ];
const indexName = generator.current.indexNames[ contextName ];
const listName = generator.current.listNames.get( contextName );
const indexName = generator.current.indexNames.get( contextName );
return `${listName}: ${listName},\n${indexName}: ${indexName}`;
}).join( ',\n' );
@ -41,8 +41,8 @@ export default {
const updates = local.allUsedContexts.map( contextName => {
if ( contextName === 'root' ) return `${name}._context.root = root;`;
const listName = generator.current.listNames[ contextName ];
const indexName = generator.current.indexNames[ contextName ];
const listName = generator.current.listNames.get( contextName );
const indexName = generator.current.indexNames.get( contextName );
return `${name}._context.${listName} = ${listName};\n${name}._context.${indexName} = ${indexName};`;
}).join( '\n' );
@ -106,7 +106,7 @@ export default {
componentInitProperties.push(`data: ${name}_initialData`);
}
const expression = node.name === ':Self' ? generator.name : generator.importedComponents[ node.name ] || `${generator.alias( 'template' )}.components.${node.name}`;
const expression = node.name === ':Self' ? generator.name : generator.importedComponents.get( node.name ) || `${generator.alias( 'template' )}.components.${node.name}`;
local.init.addBlockAtStart( deindent`
${statements.join( '\n\n' )}

@ -2,10 +2,7 @@ import CodeBuilder from '../../../utils/CodeBuilder.js';
import deindent from '../../../utils/deindent.js';
import getBuilders from '../utils/getBuilders.js';
const reserved = {
component: true,
root: true
};
const reserved = new Set( [ 'component', 'root' ] );
export default {
enter ( generator, node ) {
@ -171,28 +168,29 @@ export default {
generator.generateBlock( node.else, renderElse );
}
const indexNames = Object.assign( {}, generator.current.indexNames );
const indexName = indexNames[ node.context ] = ( node.index || `${node.context}__index` );
const indexNames = new Map( generator.current.indexNames );
const indexName = node.index || `${node.context}__index`;
indexNames.set( node.context, indexName );
const listNames = Object.assign( {}, generator.current.listNames );
listNames[ node.context ] = listName;
const listNames = new Map( generator.current.listNames );
listNames.set( node.context, listName );
// ensure that contexts like `root` or `component` don't blow up the whole show
let context = node.context;
let c = 1;
while ( context in reserved || ~generator.current.params.indexOf( context ) ) {
while ( reserved.has( context ) || ~generator.current.params.indexOf( context ) ) {
context = `${node.context}$${c++}`;
}
const contexts = Object.assign( {}, generator.current.contexts );
contexts[ node.context ] = context;
const contexts = new Map( generator.current.contexts );
contexts.set( node.context, context );
const indexes = Object.assign( {}, generator.current.indexes );
if ( node.index ) indexes[ indexName ] = node.context;
const indexes = new Map( generator.current.indexes );
if ( node.index ) indexes.set( indexName, node.context );
const contextDependencies = Object.assign( {}, generator.current.contextDependencies );
contextDependencies[ node.context ] = dependencies;
const contextDependencies = new Map( generator.current.contextDependencies );
contextDependencies.set( node.context, dependencies );
const blockParams = generator.current.params.concat( listName, context, indexName );

@ -14,7 +14,8 @@ export default {
return meta[ node.name ].enter( generator, node );
}
const isComponent = node.name in generator.components || node.name === ':Self';
const isComponent = generator.components.has( node.name ) || node.name === ':Self';
if ( isComponent ) {
return Component.enter( generator, node );
}
@ -41,8 +42,8 @@ export default {
const initialProps = local.allUsedContexts.map( contextName => {
if ( contextName === 'root' ) return `root: root`;
const listName = generator.current.listNames[ contextName ];
const indexName = generator.current.indexNames[ contextName ];
const listName = generator.current.listNames.get( contextName );
const indexName = generator.current.indexNames.get( contextName );
return `${listName}: ${listName},\n${indexName}: ${indexName}`;
}).join( ',\n' );
@ -50,8 +51,8 @@ export default {
const updates = local.allUsedContexts.map( contextName => {
if ( contextName === 'root' ) return `${name}.__svelte.root = root;`;
const listName = generator.current.listNames[ contextName ];
const indexName = generator.current.indexNames[ contextName ];
const listName = generator.current.listNames.get( contextName );
const indexName = generator.current.indexNames.get( contextName );
return `${name}.__svelte.${listName} = ${listName};\n${name}.__svelte.${indexName} = ${indexName};`;
}).join( '\n' );
@ -114,7 +115,8 @@ export default {
return;
}
const isComponent = node.name in generator.components;
const isComponent = generator.components.has( node.name );
if ( isComponent ) {
return Component.leave( generator, node );
}

@ -94,8 +94,8 @@ export default function addComponentAttributes ( generator, node, local ) {
const declarations = usedContexts.map( name => {
if ( name === 'root' ) return 'var root = this._context.root;';
const listName = generator.current.listNames[ name ];
const indexName = generator.current.indexNames[ name ];
const listName = generator.current.listNames.get( name );
const indexName = generator.current.indexNames.get( name );
return `var ${listName} = this._context.${listName}, ${indexName} = this._context.${indexName}, ${name} = ${listName}[${indexName}]`;
});

@ -12,14 +12,14 @@ export default function createBinding ( generator, node, attribute, current, loc
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
});
const contextual = name in current.contexts;
const contextual = current.contexts.has( name );
let obj;
let prop;
if ( contextual ) {
obj = current.listNames[ name ];
prop = current.indexNames[ name ];
obj = current.listNames.get( name );
prop = current.indexNames.get( name );
} else if ( attribute.value.type === 'MemberExpression' ) {
prop = `'[✂${attribute.value.property.start}-${attribute.value.property.end}✂]}'`;
obj = `root.[✂${attribute.value.object.start}-${attribute.value.object.end}✂]}`;

@ -171,8 +171,8 @@ export default function addElementAttributes ( generator, node, local ) {
const declarations = usedContexts.map( name => {
if ( name === 'root' ) return 'var root = this.__svelte.root;';
const listName = generator.current.listNames[ name ];
const indexName = generator.current.indexNames[ name ];
const listName = generator.current.listNames.get( name );
const indexName = generator.current.indexNames.get( name );
return `var ${listName} = this.__svelte.${listName}, ${indexName} = this.__svelte.${indexName}, ${name} = ${listName}[${indexName}]`;
});
@ -180,7 +180,7 @@ export default function addElementAttributes ( generator, node, local ) {
const handlerName = generator.current.getUniqueName( `${name}Handler` );
const handlerBody = ( declarations.length ? declarations.join( '\n' ) + '\n\n' : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`;
if ( name in generator.events ) {
if ( generator.events.has( name ) ) {
local.init.addBlock( deindent`
var ${handlerName} = ${generator.alias( 'template' )}.events.${name}.call( component, ${local.name}, function ( event ) {
${handlerBody}

@ -1,19 +1,19 @@
import deindent from '../../../../../utils/deindent.js';
export default function getSetter ({ current, name, context, attribute, dependencies, snippet, value }) {
if ( name in current.contexts ) {
if ( current.contexts.has( name ) ) {
const prop = dependencies[0];
const tail = attribute.value.type === 'MemberExpression' ? getTailSnippet( attribute.value ) : '';
return deindent`
var list = this.${context}.${current.listNames[ name ]};
var index = this.${context}.${current.indexNames[ name ]};
var list = this.${context}.${current.listNames.get( name )};
var index = this.${context}.${current.indexNames.get( name )};
list[index]${tail} = ${value};
component._set({ ${prop}: component.get( '${prop}' ) });
`;
}
if ( attribute.value.type === 'MemberExpression' ) {
return deindent`
var ${name} = component.get( '${name}' );
@ -21,7 +21,7 @@ export default function getSetter ({ current, name, context, attribute, dependen
component._set({ ${name}: ${name} });
`;
}
return `component._set({ ${name}: ${value} });`;
}
@ -31,4 +31,4 @@ function getTailSnippet ( node ) {
const start = node.end;
return `[✂${start}-${end}✂]`;
}
}

@ -52,8 +52,8 @@ export default function ssr ( parsed, source, options, names ) {
// create main render() function
generator.push({
contexts: {},
indexes: {},
contexts: new Map(),
indexes: new Map(),
conditions: []
});

@ -45,7 +45,7 @@ export default {
})
.concat( bindings.map( binding => {
const { name, keypath } = flattenReference( binding.value );
const value = name in generator.current.contexts ? keypath : `root.${keypath}`;
const value = generator.current.contexts.has( name ) ? keypath : `root.${keypath}`;
return `${binding.name}: ${value}`;
}))
.join( ', ' );

@ -7,14 +7,14 @@ export default {
// TODO should this be the generator's job? It's duplicated between
// here and the equivalent DOM compiler visitor
const contexts = Object.assign( {}, generator.current.contexts );
contexts[ node.context ] = node.context;
const contexts = new Map( generator.current.contexts );
contexts.set( node.context, node.context );
const indexes = Object.assign( {}, generator.current.indexes );
if ( node.index ) indexes[ node.index ] = node.context;
const indexes = new Map( generator.current.indexes );
if ( node.index ) indexes.set( node.index, node.context );
const contextDependencies = Object.assign( {}, generator.current.contextDependencies );
contextDependencies[ node.context ] = dependencies;
const contextDependencies = new Map( generator.current.contextDependencies );
contextDependencies.set( node.context, dependencies );
generator.push({
contexts,

@ -12,7 +12,7 @@ export default {
return meta[ node.name ].enter( generator, node );
}
if ( node.name in generator.components || node.name === ':Self' ) {
if ( generator.components.has( node.name ) || node.name === ':Self' ) {
Component.enter( generator, node );
return;
}
@ -53,7 +53,7 @@ export default {
return;
}
if ( node.name in generator.components || node.name === ':Self' ) {
if ( generator.components.has( node.name ) || node.name === ':Self' ) {
Component.leave( generator, node );
return;
}

@ -1,14 +1,17 @@
export default function counter ( used ) {
const counts = {};
const counts = new Map();
used.forEach( name => counts[ name ] = 1 );
used.forEach( name => counts.set( name, 1 ) );
return function ( name ) {
if ( name in counts ) {
return `${name}${counts[ name ]++}`;
if ( counts.has( name ) ) {
const count = counts.get( name );
const newName = `${name}${count}`;
counts.set( name, count + 1 );
return newName;
}
counts[ name ] = 1;
counts.set( name, 1 );
return name;
};
}

@ -15,35 +15,34 @@ const metaTags = {
':Window': true
};
const specials = {
script: {
const specials = new Map( [
[ 'script', {
read: readScript,
property: 'js'
},
style: {
} ],
[ 'style', {
read: readStyle,
property: 'css'
}
};
} ]
] );
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowedContents = {
li: [ 'li' ],
dt: [ 'dt', 'dd' ],
dd: [ 'dt', 'dd' ],
p: 'address article aside blockquote div dl fieldset footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav ol p pre section table ul'.split( ' ' ),
rt: [ 'rt', 'rp' ],
rp: [ 'rt', 'rp' ],
optgroup: [ 'optgroup' ],
option: [ 'option', 'optgroup' ],
thead: [ 'tbody', 'tfoot' ],
tbody: [ 'tbody', 'tfoot' ],
tfoot: [ 'tbody' ],
tr: [ 'tr', 'tbody' ],
td: [ 'td', 'th', 'tr' ],
th: [ 'td', 'th', 'tr' ]
};
const disallowedContents = new Map( [
[ 'li', new Set( [ 'li' ] ) ],
[ 'dt', new Set( [ 'dt', 'dd' ] ) ],
[ 'dd', new Set( [ 'dt', 'dd' ] ) ],
[ 'p', new Set( 'address article aside blockquote div dl fieldset footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav ol p pre section table ul'.split( ' ' ) ) ],
[ 'rt', new Set( [ 'rt', 'rp' ] ) ],
[ 'rp', new Set( [ 'rt', 'rp' ] ) ],
[ 'optgroup', new Set( [ 'optgroup' ] ) ],
[ 'option', new Set( [ 'option', 'optgroup' ] ) ],
[ 'thead', new Set( [ 'tbody', 'tfoot' ] ) ],
[ 'tbody', new Set( [ 'tbody', 'tfoot' ] ) ],
[ 'tfoot', new Set( [ 'tbody' ] ) ],
[ 'tr', new Set( [ 'tr', 'tbody' ] ) ],
[ 'td', new Set( [ 'td', 'th', 'tr' ] ) ],
[ 'th', new Set( [ 'td', 'th', 'tr' ] ) ],
] );
function stripWhitespace ( element ) {
if ( element.children.length ) {
@ -127,11 +126,10 @@ export default function tag ( parser ) {
parser.stack.pop();
return null;
} else if ( parent.name in disallowedContents ) {
} else if ( disallowedContents.has( parent.name ) ) {
// can this be a child of the parent element, or does it implicitly
// close it, like `<li>one<li>two`?
const disallowed = disallowedContents[ parent.name ];
if ( ~disallowed.indexOf( name ) ) {
if ( disallowedContents.get( parent.name ).has( name ) ) {
stripWhitespace( parent );
parent.end = start;
@ -151,8 +149,8 @@ export default function tag ( parser ) {
parser.allowWhitespace();
// special cases top-level <script> and <style>
if ( name in specials && parser.stack.length === 1 ) {
const special = specials[ name ];
if ( specials.has( name ) && parser.stack.length === 1 ) {
const special = specials.get( name );
if ( parser[ special.property ] ) {
parser.index = start;
@ -358,4 +356,4 @@ function getShorthandValue ( start, name ) {
name
}
}];
}
}

@ -1,10 +1,7 @@
import checkForDupes from '../utils/checkForDupes.js';
import checkForComputedKeys from '../utils/checkForComputedKeys.js';
const isFunctionExpression = {
FunctionExpression: true,
ArrowFunctionExpression: true
};
const isFunctionExpression = new Set( [ 'FunctionExpression', 'ArrowFunctionExpression' ] );
export default function computed ( validator, prop ) {
if ( prop.value.type !== 'ObjectExpression' ) {
@ -16,7 +13,7 @@ export default function computed ( validator, prop ) {
checkForComputedKeys( validator, prop.value.properties );
prop.value.properties.forEach( computation => {
if ( !isFunctionExpression[ computation.value.type ] ) {
if ( !isFunctionExpression.has( computation.value.type ) ) {
validator.error( `Computed properties can be function expressions or arrow function expressions`, computation.value.start );
return;
}

@ -1,15 +1,11 @@
const disallowed = {
Literal: true,
ObjectExpression: true,
ArrayExpression: true
};
const disallowed = new Set( [ 'Literal', 'ObjectExpression', 'ArrayExpression' ] );
export default function data ( validator, prop ) {
while ( prop.type === 'ParenthesizedExpression' ) prop = prop.expression;
// TODO should we disallow references and expressions as well?
if ( disallowed[ prop.value.type ] ) {
if ( disallowed.has( prop.value.type ) ) {
validator.error( `'data' must be a function`, prop.value.start );
}
}

@ -2,14 +2,7 @@ import checkForDupes from '../utils/checkForDupes.js';
import checkForComputedKeys from '../utils/checkForComputedKeys.js';
import usesThisOrArguments from '../utils/usesThisOrArguments.js';
const builtin = {
set: true,
get: true,
on: true,
fire: true,
observe: true,
teardown: true
};
const builtin = new Set( [ 'set', 'get', 'on', 'fire', 'observe', 'teardown' ] );
export default function methods ( validator, prop ) {
if ( prop.value.type !== 'ObjectExpression' ) {
@ -21,7 +14,7 @@ export default function methods ( validator, prop ) {
checkForComputedKeys( validator, prop.value.properties );
prop.value.properties.forEach( prop => {
if ( builtin[ prop.key.name ] ) {
if ( builtin.has( prop.key.name ) ) {
validator.error( `Cannot overwrite built-in method '${prop.key.name}'` );
}

@ -1,11 +1,11 @@
export default function checkForDupes ( validator, properties ) {
const seen = Object.create( null );
const seen = new Set();
properties.forEach( prop => {
if ( seen[ prop.key.name ] ) {
if ( seen.has( prop.key.name ) ) {
validator.error( `Duplicate property '${prop.key.name}'`, prop.start );
}
seen[ prop.key.name ] = true;
seen.add( prop.key.name );
});
}

Loading…
Cancel
Save