diff --git a/src/generators/Generator.js b/src/generators/Generator.js index d6056930e2..1193af9e42 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -4,6 +4,7 @@ import isReference from '../utils/isReference.js'; import flattenReference from '../utils/flattenReference.js'; import globalWhitelist from '../utils/globalWhitelist.js'; import reservedNames from '../utils/reservedNames.js'; +import { removeNode } from '../utils/removeNode.js'; import getIntro from './shared/utils/getIntro.js'; import getOutro from './shared/utils/getOutro.js'; import processCss from './shared/processCss.js'; @@ -268,28 +269,25 @@ export default class Generator { if ( js ) { this.addSourcemapLocations( js.content ); + const body = js.content.body.slice(); // slice, because we're going to be mutating the original // imports need to be hoisted out of the IIFE - for ( let i = 0; i < js.content.body.length; i += 1 ) { - const node = js.content.body[i]; + for ( let i = 0; i < body.length; i += 1 ) { + const node = body[i]; if ( node.type === 'ImportDeclaration' ) { - let a = node.start; - let b = node.end; - while ( /[ \t]/.test( source[ a - 1 ] ) ) a -= 1; - while ( source[b] === '\n' ) b += 1; - + removeNode( this.code, js.content, node ); imports.push( node ); - this.code.remove( a, b ); + node.specifiers.forEach( specifier => { this.importedNames.add( specifier.local.name ); }); } } - defaultExport = js.content.body.find( node => node.type === 'ExportDefaultDeclaration' ); + defaultExport = body.find( node => node.type === 'ExportDefaultDeclaration' ); if ( defaultExport ) { - const finalNode = js.content.body[ js.content.body.length - 1 ]; + const finalNode = body[ body.length - 1 ]; if ( defaultExport === finalNode ) { // export is last property, we can just return it this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `return ` ); diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 5bfb472e86..7ba3df9b6e 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -2,7 +2,7 @@ import deindent from '../../utils/deindent.js'; import getBuilders from './utils/getBuilders.js'; import CodeBuilder from '../../utils/CodeBuilder.js'; import namespaces from '../../utils/namespaces.js'; -import removeObjectKey from '../../utils/removeObjectKey.js'; +import { removeObjectKey } from '../../utils/removeNode.js'; import visitors from './visitors/index.js'; import Generator from '../Generator.js'; import * as shared from '../../shared/index.js'; @@ -175,7 +175,7 @@ export default function dom ( parsed, source, options ) { const ns = templateProperties.namespace.value.value; namespace = namespaces[ ns ] || ns; - removeObjectKey( generator, defaultExport.declaration, 'namespace' ); + removeObjectKey( generator.code, defaultExport.declaration, 'namespace' ); } if ( templateProperties.components ) { @@ -192,11 +192,11 @@ export default function dom ( parsed, source, options ) { if ( hasNonImportedComponent ) { // remove the specific components that were imported, as we'll refer to them directly Array.from( generator.importedComponents.keys() ).forEach( key => { - removeObjectKey( generator, templateProperties.components.value, key ); + removeObjectKey( generator.code, templateProperties.components.value, key ); }); } else { // remove the entire components portion of the export - removeObjectKey( generator, defaultExport.declaration, 'components' ); + removeObjectKey( generator.code, defaultExport.declaration, 'components' ); } } diff --git a/src/utils/removeNode.js b/src/utils/removeNode.js new file mode 100644 index 0000000000..aecec33455 --- /dev/null +++ b/src/utils/removeNode.js @@ -0,0 +1,55 @@ +const keys = { + ObjectExpression: 'properties', + Program: 'body' +}; + +const offsets = { + ObjectExpression: [ 1, -1 ], + Program: [ 0, 0 ] +}; + +export function removeNode ( code, parent, node ) { + const key = keys[ parent.type ]; + const offset = offsets[ parent.type ]; + if ( !key || !offset ) throw new Error( `not implemented: ${parent.type}` ); + + const list = parent[ key ]; + const i = list.indexOf( node ); + if ( i === -1 ) throw new Error( 'node not in list' ); + + let a; + let b; + + if ( list.length === 1 ) { + // remove everything, leave {} + a = parent.start + offset[0]; + b = parent.end + offset[1]; + } else if ( i === 0 ) { + // remove everything before second node, including comments + a = parent.start + offset[0]; + while ( /\s/.test( code.original[a] ) ) a += 1; + + b = list[i].end; + while ( /[\s,]/.test( code.original[b] ) ) b += 1; + } else { + // remove the end of the previous node to the end of this one + a = list[ i - 1 ].end; + b = node.end; + } + + code.remove( a, b ); + list.splice( i, 1 ); + return; +} + +export function removeObjectKey ( code, node, key ) { + if ( node.type !== 'ObjectExpression' ) return; + + let i = node.properties.length; + while ( i-- ) { + const property = node.properties[i]; + if ( property.key.type === 'Identifier' && property.key.name === key ) { + removeNode( code, node, property ); + } + } +} diff --git a/src/utils/removeObjectKey.js b/src/utils/removeObjectKey.js deleted file mode 100644 index 6611dffa40..0000000000 --- a/src/utils/removeObjectKey.js +++ /dev/null @@ -1,33 +0,0 @@ -export default function removeObjectKey ( generator, node, key ) { - if ( node.type !== 'ObjectExpression' ) return; - - let i = node.properties.length; - while ( i-- ) { - const property = node.properties[i]; - if ( property.key.type === 'Identifier' && property.key.name === key ) { - let a; - let b; - - if ( node.properties.length === 1 ) { - // remove everything, leave {} - a = node.start + 1; - b = node.end - 1; - } else if ( i === 0 ) { - // remove everything before second property, including comments - a = node.start + 1; - while ( /\s/.test( generator.code.original[a] ) ) a += 1; - - b = node.properties[i].end; - while ( /[\s,]/.test( generator.code.original[b] ) ) b += 1; - } else { - // remove the end of the previous property to the end of this one - a = node.properties[ i - 1 ].end; - b = property.end; - } - - generator.code.remove( a, b ); - node.properties.splice( i, 1 ); - return; - } - } -}