module.exports = function injectImportsAndOptions (source, imports, injections) { imports = imports instanceof Set ? Array.from(imports) : imports injections = injections instanceof Set ? Array.from(injections) : injections const hasImports = imports && imports.length > 0 const hasInjections = injections && injections.length > 0 if (!hasImports && !hasInjections) { return source } const recast = require('recast') const ast = recast.parse(source) if (hasImports) { const toImport = i => recast.parse(`${i}\n`).program.body[0] const importDeclarations = [] let lastImportIndex = -1 recast.types.visit(ast, { visitImportDeclaration ({ node }) { lastImportIndex = ast.program.body.findIndex(n => n === node) importDeclarations.push(node) return false } }) // avoid blank line after the previous import delete ast.program.body[lastImportIndex].loc const nonDuplicates = i => { return !importDeclarations.some(node => { const result = node.source.raw === i.source.raw && node.specifiers.length === i.specifiers.length return result && node.specifiers.every((item, index) => { return i.specifiers[index].local.name === item.local.name }) }) } const newImports = imports.map(toImport).filter(nonDuplicates) ast.program.body.splice(lastImportIndex + 1, 0, ...newImports) } if (hasInjections) { const toProperty = i => { return recast.parse(`({${i}})`).program.body[0].expression.properties } recast.types.visit(ast, { visitNewExpression ({ node }) { if (node.callee.name === 'Vue') { const options = node.arguments[0] if (options && options.type === 'ObjectExpression') { const nonDuplicates = i => { return !options.properties.slice(0, -1).some(p => { return p.key.name === i[0].key.name && recast.print(p.value).code === recast.print(i[0].value).code }) } // inject at index length - 1 as it's usually the render fn options.properties = [ ...options.properties.slice(0, -1), ...([].concat(...injections.map(toProperty).filter(nonDuplicates))), ...options.properties.slice(-1) ] } } return false } }) } return recast.print(ast).code }