├── examples ├── README.md ├── configs │ ├── nuxt.simple.js │ ├── nuxt.trans.js │ └── nuxt.default.js ├── nuxt.simple.js └── transform.js ├── .travis.yml ├── .gitignore ├── .editorconfig ├── .prettierrc ├── .eslintrc.js ├── script.js ├── plugin ├── operations.js ├── toAst.js ├── utils.js ├── actions.js ├── tree.js └── index.js ├── package.json ├── index.js ├── README.md └── test ├── __snapshots__ └── index.spec.js.snap └── index.spec.js /examples/README.md: -------------------------------------------------------------------------------- 1 | NodeJS scripts examples -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | ._DS* 3 | /node_modules 4 | package-lock.json 5 | yarn-error.log 6 | -------------------------------------------------------------------------------- /examples/configs/nuxt.simple.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mode: 'universal', 3 | css: [], 4 | modules: ['@org/my-nuxt-module'], 5 | build: { 6 | extend(config, ctx) {} 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /examples/configs/nuxt.trans.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mode: 'universal', 3 | head: { 4 | script: [] 5 | }, 6 | modules: [], 7 | css: [], 8 | build: { 9 | extend(config, ctx) {} 10 | }, 11 | delete: { 12 | deleteMeMaybe: [true] 13 | }, 14 | deleteMeMaybe: [true] 15 | }; 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | quote_type = single 12 | curly_bracket_next_line = false 13 | spaces_around_operators = true 14 | indent_brace_style = K&R 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | quote_type = auto 19 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "quoteProps": "as-needed", 8 | "jsxSingleQuote": false, 9 | "trailingComma": "none", 10 | "bracketSpacing": true, 11 | "jsxBracketSameLine": false, 12 | "arrowParens": "avoid", 13 | "requirePragma": false, 14 | "insertPragma": false, 15 | "htmlWhitespaceSensitivity": "css", 16 | "endOfLine": "lf" 17 | } 18 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: false, 5 | node: true 6 | }, 7 | parser: 'babel-eslint', 8 | extends: ['plugin:prettier/recommended'], 9 | plugins: [], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 13 | 'no-undef': 0, 14 | indent: ['error', 2, { SwitchCase: 1 }], 15 | quotes: ['error', 'single'], 16 | semi: ['error', 'always'] 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /examples/nuxt.simple.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const transformConfig = require('../'); 4 | 5 | const code = fs.readFileSync( 6 | path.join(__dirname, 'configs', 'nuxt.simple.js'), 7 | 'utf8' 8 | ); 9 | 10 | const args = { 11 | css: ['path/to/file'], 12 | modules: [['my-module', { config: true }]], 13 | transpile: ['my-other-module'] 14 | }; 15 | 16 | const { code: updated } = transformConfig(code, 'nuxt', args); 17 | 18 | console.log('previous code:\n', code); 19 | 20 | console.log('passed args: ', JSON.stringify(args), '\n'); 21 | console.log('new code:\n', updated); 22 | -------------------------------------------------------------------------------- /examples/configs/nuxt.default.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mode: 'universal', 3 | head: { 4 | title: process.env.npm_package_name || '', 5 | meta: [ 6 | { 7 | charset: 'utf-8' 8 | }, 9 | { 10 | name: 'viewport', 11 | content: 'width=device-width, initial-scale=1' 12 | }, 13 | { 14 | hid: 'description', 15 | name: 'description', 16 | content: process.env.npm_package_description || '' 17 | } 18 | ], 19 | link: [ 20 | { 21 | rel: 'icon', 22 | type: 'image/x-icon', 23 | href: '/favicon.ico' 24 | } 25 | ], 26 | script: [] 27 | }, 28 | loading: { 29 | color: '#fff' 30 | }, 31 | modules: [], 32 | css: [], 33 | plugins: [], 34 | buildModules: [], 35 | build: { 36 | extend(config, ctx) {} 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /examples/transform.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const transformCode = require('../').transform; 4 | 5 | const code = fs.readFileSync( 6 | path.join(__dirname, 'configs', 'nuxt.trans.js'), 7 | 'utf8' 8 | ); 9 | 10 | const transforms = { 11 | 'head:script': { 12 | // create or replace export default { head: { script: [] }} 13 | action: 'create:replace', 14 | value: ['my/script.js'] 15 | }, 16 | 'delete:deleteMeMaybe': { 17 | // delete export default { deleteMe: ... } 18 | action: 'delete' 19 | }, 20 | deleteMeMaybe: { 21 | // delete export default { deleteMe: ... } 22 | action: 'delete' 23 | }, 24 | 'build:transpile': { 25 | // merges export default { babel: { transpile: arrayOrObject } } 26 | action: 'merge:create', 27 | value: ['path/to/file'] 28 | } 29 | }; 30 | 31 | const { code: updated } = transformCode(code, transforms); 32 | 33 | console.log('previous code:\n', code); 34 | 35 | console.log('passed transform args: ', JSON.stringify(transforms), '\n'); 36 | 37 | console.log('new code:\n', updated); 38 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | // Just to test things manually quicker than with Jest... 2 | const transformConfig = require('./'); 3 | 4 | const config = `export default { 5 | foo: ['default'], 6 | foo2: ['default'], 7 | bar: { 8 | baz: ['default'], 9 | baz2: ['default'] 10 | } 11 | };`; 12 | 13 | const transforms = { 14 | 'bar:test': { 15 | action: 'create', 16 | value: ['created'] 17 | }, 18 | 'bar:test2': { 19 | action: 'create', 20 | value: ['created'] 21 | }, 22 | 'bar:baz': { 23 | action: 'delete' 24 | }, 25 | 'bar:baz2': { 26 | action: 'delete' 27 | } 28 | }; 29 | 30 | // console.info(transformConfig.transform(config, transforms).code) 31 | 32 | const { ArrayHelpers } = require('./plugin/utils'); 33 | 34 | const ops1 = ['delete', 'create']; 35 | const ops2 = ['update']; 36 | 37 | // console.log(ArrayHelpers.distinct(ops1, ops2, (op1, op2) => op1 === op2)); 38 | 39 | const config2 = `export default { 40 | config: {}, 41 | buildModules: [{}] 42 | }; 43 | `; 44 | 45 | const transforms2 = { 46 | ignore: { action: 'create:merge', value: ['**/*.stories.js'] } 47 | }; 48 | 49 | console.info(transformConfig.transform(config2, transforms2).code); 50 | -------------------------------------------------------------------------------- /plugin/operations.js: -------------------------------------------------------------------------------- 1 | const SEPARATOR = ':'; 2 | const OPERATIONS = { 3 | create: 'create', 4 | merge: 'merge', 5 | replace: 'replace', 6 | delete: 'delete' 7 | }; 8 | 9 | module.exports = { 10 | ...OPERATIONS, 11 | toString: () => { 12 | return Object.entries(OPERATIONS) 13 | .map(([, v]) => v) 14 | .join(' | '); 15 | }, 16 | toList: (strOperations, value) => { 17 | const operations = strOperations.split(SEPARATOR); 18 | 19 | operations.forEach(op => { 20 | if (!OPERATIONS[op]) { 21 | throw new Error( 22 | `Operation "${op}" does not exist.\nDefined operations: ${OPERATIONS.toString()}` 23 | ); 24 | } 25 | }); 26 | if ( 27 | operations.includes(OPERATIONS.merge) && 28 | operations.includes(OPERATIONS.replace) 29 | ) { 30 | throw new Error( 31 | 'Operations "merge" and "update" cannot coexist in transform\'s "action" property' 32 | ); 33 | } 34 | if ( 35 | operations.includes(OPERATIONS.create) && 36 | operations.includes(OPERATIONS.delete) 37 | ) { 38 | throw new Error( 39 | 'Operations "create" and "delete" cannot coexist in transform\'s "action" property' 40 | ); 41 | } 42 | if (operations.includes(OPERATIONS.merge) && !Array.isArray(value)) { 43 | throw new Error( 44 | 'Operations "merge" expects value to be of type "Array" (tested with Array.isArray)' 45 | ); 46 | } 47 | 48 | return operations; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /plugin/toAst.js: -------------------------------------------------------------------------------- 1 | const babylon = require('@babel/parser'); 2 | 3 | const babelPluginTransformRuntime = require('@babel/plugin-transform-runtime') 4 | .default; 5 | const babelPluginTransformArrowFunction = require('@babel/plugin-transform-arrow-functions') 6 | .default; 7 | 8 | function toAst(t, elem) { 9 | if (elem === null) { 10 | return t.nullLiteral(); 11 | } 12 | if (Array.isArray(elem)) { 13 | return t.arrayExpression(elem.map(e => toAst(t, e))); 14 | } 15 | if (typeof elem === 'object') { 16 | const expression = t.objectExpression( 17 | Object.entries(elem).reduce((acc, [key, value]) => { 18 | if (typeof value !== 'undefined') { 19 | const property = t.objectProperty( 20 | t.stringLiteral(key), 21 | toAst(t, value) 22 | ); 23 | return [...acc, property]; 24 | } 25 | return acc; 26 | }, []) 27 | ); 28 | return expression; 29 | } 30 | switch (typeof elem) { 31 | case 'function': 32 | const ast = babylon.parse(elem.toString(), { 33 | plugins: [ 34 | babelPluginTransformRuntime, 35 | babelPluginTransformArrowFunction 36 | ] 37 | }); 38 | const { params, body } = ast.program.body[0]; 39 | return t.functionExpression(null, params, body); 40 | case 'number': 41 | return t.numericLiteral(elem); 42 | case 'string': 43 | return t.stringLiteral(elem); 44 | case 'boolean': 45 | return t.booleanLiteral(elem); 46 | } 47 | } 48 | 49 | module.exports = toAst; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prismicio/babel-transform-config", 3 | "version": "0.0.6", 4 | "description": "Transform JS config files (Next, Nuxt, Gatsby)", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "eslint --ext .js,.ts .", 8 | "jest": "jest", 9 | "test": "yarn lint && yarn jest" 10 | }, 11 | "keywords": [ 12 | "Babel", 13 | "Babylon", 14 | "AST", 15 | "Next", 16 | "Nuxt", 17 | "Gatsby" 18 | ], 19 | "author": "Hugo Villain", 20 | "contributors": [ 21 | "Arnaud lewis (@arnaudlewis)" 22 | ], 23 | "license": "ISC", 24 | "dependencies": { 25 | "@babel/core": "^7.11.6", 26 | "@babel/plugin-syntax-jsx": "^7.10.4", 27 | "@babel/plugin-transform-arrow-functions": "^7.10.4", 28 | "@babel/plugin-transform-runtime": "^7.11.5", 29 | "@babel/preset-env": "^7.11.5", 30 | "@babel/standalone": "^7.11.6", 31 | "@babel/template": "^7.10.4", 32 | "@babel/traverse": "^7.11.5", 33 | "consola": "^2.15.0" 34 | }, 35 | "devDependencies": { 36 | "jest": "^26.4.2", 37 | "babel-eslint": "^10.1.0", 38 | "eslint": "^7.10.0", 39 | "eslint-config-prettier": "^6.12.0", 40 | "eslint-loader": "^4.0.2", 41 | "eslint-plugin-prettier": "^3.1.4", 42 | "prettier": "^2.1.2" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/prismicio/babel-transform-config.git" 47 | }, 48 | "bugs": { 49 | "url": "https://github.com/prismicio/babel-transform-config/issues" 50 | }, 51 | "homepage": "https://github.com/prismicio/babel-transform-config#readme" 52 | } 53 | -------------------------------------------------------------------------------- /plugin/utils.js: -------------------------------------------------------------------------------- 1 | const ArrayHelpers = { 2 | splitAtLast(array) { 3 | if (!array) return null; 4 | 5 | switch (array.length) { 6 | case 0: 7 | return [[], null]; 8 | case 1: 9 | return [[], array[0]]; 10 | default: 11 | return [array.slice(0, -1), array[array.length - 1]]; 12 | } 13 | }, 14 | 15 | splitAtHead(array) { 16 | if (!array) return null; 17 | 18 | switch (array.length) { 19 | case 0: 20 | return [null, []]; 21 | case 1: 22 | return [array[0], []]; 23 | default: 24 | return [array[0], array.slice(1)]; 25 | } 26 | }, 27 | 28 | combine(array1, array2, mergeFn) { 29 | // FIXME: Behaving really weirdly / not used 30 | const [main, other] = 31 | array1.length > array2.length ? [array2, array1] : [array1, array2]; 32 | 33 | return main 34 | .map((value, index) => mergeFn(value, other[index])) 35 | .concat( 36 | other 37 | .slice(main.length, other.length) 38 | .map(value => mergeFn(undefined, value)) 39 | ); 40 | }, 41 | 42 | flatten(arr) { 43 | return arr.reduce((acc, subArr) => acc.concat(subArr), []); 44 | }, 45 | 46 | distinct(arr1, arr2, predicate) { 47 | return arr1.concat(arr2).reduce((acc, current) => { 48 | for (const item of acc) { 49 | if (predicate(item, current)) { 50 | return acc; 51 | } 52 | } 53 | acc.push(current); 54 | return acc; 55 | }, []); 56 | }, 57 | 58 | diff(array1, array2) { 59 | return array1.filter(function (elm) { 60 | return array2.indexOf(elm) === -1; 61 | }); 62 | } 63 | }; 64 | 65 | module.exports = { 66 | ArrayHelpers 67 | }; 68 | -------------------------------------------------------------------------------- /plugin/actions.js: -------------------------------------------------------------------------------- 1 | const Operations = require('./operations'); 2 | const ArrayHelpers = require('./utils').ArrayHelpers; 3 | const treeModule = require('./tree'); 4 | 5 | const Tree = treeModule.Tree; 6 | const Node = treeModule.Node; 7 | const Root = treeModule.Root; 8 | 9 | function _formatNode(key, value) { 10 | return { 11 | key, 12 | value 13 | }; 14 | } 15 | 16 | function _format(key, value, ops) { 17 | const KeySeparator = ':'; 18 | const nodes = key.split(KeySeparator); 19 | 20 | const [headList, last] = ArrayHelpers.splitAtLast(nodes); 21 | const formattedNodes = headList 22 | .map(k => _formatNode(k, null)) 23 | .concat([_formatNode(last, value)]); 24 | return { 25 | nodes: formattedNodes, 26 | ops 27 | }; 28 | } 29 | 30 | module.exports = { 31 | validate(key, action, value) { 32 | if (!action || !action.length) { 33 | throw new Error( 34 | `Transformation with key "${key}" should possess a non-empty "action" key` 35 | ); 36 | } 37 | if (action.indexOf(Operations.delete) === -1 && value === undefined) { 38 | throw new Error( 39 | `Transformation with key "${key}" should possess a non-empty "value" key` 40 | ); 41 | } 42 | 43 | const ops = Operations.toList(action, value); 44 | 45 | return _format(key, value, ops); 46 | }, 47 | 48 | convertToTree(action) { 49 | function toNodes(entries, ops) /* Node[] */ { 50 | const [head, tail] = ArrayHelpers.splitAtHead(entries); 51 | if (!head) return []; 52 | 53 | return [new Node(head.key, head.value, toNodes(tail, ops), ops)]; 54 | } 55 | 56 | const headNodes = toNodes(action.nodes, action.ops); 57 | 58 | return new Tree(new Root(headNodes)); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /plugin/tree.js: -------------------------------------------------------------------------------- 1 | const ArrayHelpers = require('./utils').ArrayHelpers; 2 | const Operations = require('./operations'); 3 | 4 | class Tree { 5 | constructor(/* Root */ root) { 6 | this.root = root; 7 | } 8 | 9 | combine(/* Tree */ other) { 10 | const mergedNodes = ArrayHelpers.flatten( 11 | other.root.nextNodes.map(otherNode => { 12 | const matchedNode = this.root.nextNodes.find( 13 | ({ key }) => key === otherNode.key 14 | ); 15 | if (matchedNode) return matchedNode.combine(otherNode); 16 | else return otherNode; 17 | }) 18 | ); 19 | 20 | const mergedKeys = mergedNodes.filter(n => n).map(({ key }) => key); 21 | const allNodes = this.root.nextNodes 22 | .filter(n => !mergedKeys.includes(n.key)) 23 | .concat(mergedNodes) 24 | .filter(n => n); 25 | 26 | return new Tree(new Root(allNodes)); 27 | } 28 | } 29 | 30 | class _TreeNode { 31 | constructor(/*Node[] */ nextNodes) { 32 | this.nextNodes = nextNodes; 33 | } 34 | } 35 | 36 | class Root extends _TreeNode { 37 | constructor(/*Node[] */ nextNodes) { 38 | super(nextNodes); 39 | } 40 | } 41 | 42 | class Node extends _TreeNode { 43 | constructor( 44 | /* string */ key, 45 | /* any */ value, 46 | /*Node[] */ nextNodes, 47 | /* Operation[] */ ops 48 | ) { 49 | super(nextNodes); 50 | this.key = key; 51 | this.value = value; 52 | this.ops = ops; 53 | } 54 | 55 | combine(/* Node */ other) /* Node[] */ { 56 | if (this.key === other.key) { 57 | const merged = (() => { 58 | const combinedOps = ArrayHelpers.distinct( 59 | this.ops, 60 | other.ops, 61 | (op1, op2) => op1 === op2 62 | ); 63 | const finalValue = (() => { 64 | if (combinedOps.includes(Operations.delete)) { 65 | return null; 66 | } else { 67 | if (this.value && other.value) { 68 | if (Array.isArray(this.value)) { 69 | return this.value.concat(other.value); 70 | } else { 71 | return Object.assign({}, this.value, other.value); 72 | } 73 | } else { 74 | return this.value || other.value; 75 | } 76 | } 77 | })(); 78 | 79 | return new Node( 80 | this.key, 81 | finalValue, 82 | ArrayHelpers.distinct( 83 | this.nextNodes, 84 | other.nextNodes, 85 | (node1, node2) => node1.key === node2.key 86 | ), 87 | combinedOps 88 | ); 89 | })(); 90 | 91 | return [merged]; 92 | } else { 93 | return [this, other]; 94 | } 95 | } 96 | } 97 | 98 | const Trees = { 99 | empty() { 100 | return new Tree(new Root([])); 101 | } 102 | }; 103 | 104 | module.exports = { 105 | Tree, 106 | Trees, 107 | Root, 108 | Node 109 | }; 110 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const consola = require('consola'); 2 | const babelTransform = require('@babel/standalone').transform; 3 | 4 | const babelTransformConfigPlugin = require('./plugin'); 5 | 6 | const nuxt = { 7 | css(value) { 8 | // arr of strings 9 | return [ 10 | 'css', 11 | { 12 | action: 'create:merge', 13 | value 14 | } 15 | ]; 16 | }, 17 | script(value) { 18 | // arr of objects or strings 19 | return [ 20 | 'head:script', 21 | { 22 | action: 'create:merge', 23 | value 24 | } 25 | ]; 26 | }, 27 | module(value) { 28 | return [ 29 | 'modules', 30 | { 31 | action: 'create:merge', 32 | value: [value] 33 | } 34 | ]; 35 | }, 36 | modules(value) { 37 | return [ 38 | 'modules', 39 | { 40 | action: 'create:merge', 41 | value 42 | } 43 | ]; 44 | }, 45 | transpile(value) { 46 | return [ 47 | 'build:transpile', 48 | { 49 | action: 'create:merge', 50 | value 51 | } 52 | ]; 53 | }, 54 | libraries(value) { 55 | return [ 56 | 'build:transpile', 57 | { 58 | action: 'create:merge', 59 | value 60 | } 61 | ]; 62 | } 63 | }; 64 | const table = { nuxt }; 65 | 66 | function createTransformArgs(framework, args, strict) { 67 | if (!table.hasOwnProperty(framework)) { 68 | throw new Error( 69 | `[transform-configs] ${framework} Framework not supported\nUse babel plugin directly instead` 70 | ); 71 | } 72 | const frameworkTable = table[framework]; 73 | const keysNotFound = []; 74 | const transforms = Object.entries(args).reduce((acc, [k, v]) => { 75 | if (frameworkTable[k]) { 76 | const [key, value] = frameworkTable[k](v); 77 | return { 78 | ...acc, 79 | [key]: value 80 | }; 81 | } 82 | keysNotFound.push(k); 83 | if (!strict) { 84 | return { 85 | ...acc, 86 | [k]: { 87 | action: 'create:merge', 88 | value: v 89 | } 90 | }; 91 | } 92 | return acc; 93 | }, {}); 94 | return { 95 | transforms, 96 | keysNotFound 97 | }; 98 | } 99 | 100 | function transform(code, transforms) { 101 | return babelTransform(code, { 102 | plugins: [[babelTransformConfigPlugin, transforms]] 103 | }); // { code } or Throws error 104 | } 105 | 106 | function handleKeysNotFound(keys) { 107 | keys.forEach(key => { 108 | consola.warn( 109 | `[transform-args] Key "${key}" not recognized.\nDefaulting to default transform` 110 | ); 111 | }); 112 | } 113 | function transformConfig(code, framework, args, strict = true) { 114 | try { 115 | const { transforms, keysNotFound } = createTransformArgs( 116 | framework, 117 | args, 118 | strict 119 | ); 120 | 121 | if (JSON.stringify(transforms) === '{}') { 122 | return consola.error('No transforms performed'); 123 | } 124 | 125 | if (!strict && keysNotFound.length) { 126 | handleKeysNotFound(keysNotFound); 127 | } 128 | 129 | return transform(code, transforms); 130 | } catch (e) { 131 | consola.error(e.message); 132 | } 133 | } 134 | 135 | transformConfig.transform = transform; 136 | transformConfig.plugin = babelTransformConfigPlugin; 137 | 138 | module.exports = transformConfig; 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## babel-transform-config 2 | If you ever wanted to update a Nuxt or Next config file programmatically. 3 | #### Readme: wip 4 | Simplest way to understand what it does: 5 | 6 | ````bash 7 | git clone https://github.com/prismicio/babel-transform-config; 8 | cd babel-transform-config && npm install; 9 | node examples/nuxt.simple.js 10 | ```` 11 | This should display some info 👇 12 | 13 | ##### 1/ previous code: 14 | 15 | The actual `nuxt.config.js` file that was read from file. 16 | Something like: 17 | ```javascript 18 | export default { 19 | css: [], 20 | modules: ['@org/my-nuxt-module'], 21 | build: { 22 | webpack : {} 23 | }, 24 | }; 25 | ```` 26 | 27 | ##### 2/ args passed : 28 | The arguments that were passed to `babel-transform-config`. 29 | Something like: 30 | ```javascript 31 | const args = { 32 | css: ['path/to/file'], 33 | modules: [ 34 | ['my-module', { config: true }] 35 | ], 36 | transpile: ['my-other-module'] 37 | } 38 | // will be used like this: 39 | // transformConfig(code, 'nuxt', args) 40 | ```` 41 | 42 | ##### 3/ the transpiled code : 43 | What you came for: 44 | ```javascript 45 | export default { 46 | css: ["path/to/file"], 47 | modules: ['@org/my-nuxt-module', ["my-module", { 48 | "config": true 49 | }]], 50 | build: { 51 | webpack: {}, 52 | transpile: ["my-other-module"] 53 | } 54 | }; 55 | ```` 56 | 57 | ## Using the module 58 | 59 | This package exports a `transformConfig` function that takes as arguments some code, a framework key, and key-value params that will help the module transform these arguments. 60 | 61 | For example, these arguments: 62 | ````javascript 63 | const args = { 64 | script: ['path/to/script-file.js'] 65 | } 66 | transformConfig(myNuxtConfig, 'nuxt', args) 67 | ```` 68 | 69 | `transformConfig` will try & match your script key and transform your arguments into: 70 | ````javascript 71 | transforms: [{ 72 | 'head:script': { 73 | action: 'create:merge', 74 | value: ['path/to/script-file.js'] 75 | } 76 | ], 77 | ```` 78 | This will help the underlying Babel plugin perform the right actions, based on what it knows of your framework. The complete call: 79 | 80 | ````javascript 81 | const fs = require('fs') 82 | const transformConfig = require('babel-transform-config') 83 | 84 | const code = fs.readFileSync('path/to/config', 'utf8') 85 | const args = { script: ['path/to/script-file.js'] } 86 | 87 | const { code: updatedCode} = transformConfig(code, 'nuxt', args) 88 | 89 | // ⚠️ this is experimental, please log things first 90 | fs.writeFileSync('path/to/config', updatedCode, 'utf8') 91 | 92 | ```` 93 | 94 | ## Direct transform / Babel plugin 95 | 96 | Right now, `transformConfig` only supports Nuxt framexwork. If you want to use things for yourself with another framework, you should use the lower-level transform method: 97 | 98 | ```javascript 99 | const { transform } = require('babel-transform-config') 100 | 101 | const transforms = { 102 | 'head:script': { // create or replace export default { head: { script: [] }} 103 | action: 'create:replace', 104 | value: ['my/script.js'] 105 | }, 106 | 'deleteMe': { // delete export default { deleteMe: ... } 107 | action: 'delete' 108 | }, 109 | 'build:transpile': { // merges export default { babel: { transpile: arrayOrObject } } 110 | action: 'merge', 111 | value: ['path/to/file'] 112 | } 113 | } 114 | const { code: updatedCode } = transform(yourCustomCode, transforms) 115 | 116 | ````` 117 | 118 | 👆 See `examples/transform`. 119 | 120 | 121 | #### Quick note 122 | 123 | This package does not work well with nested elements, especially when object patterns are similar. 124 | 125 | 126 | -------------------------------------------------------------------------------- /plugin/index.js: -------------------------------------------------------------------------------- 1 | const consola = require('consola'); 2 | const Actions = require('./actions'); 3 | const Trees = require('./tree').Trees; 4 | const ArrayHelpers = require('./utils').ArrayHelpers; 5 | const toAst = require('./toAst'); 6 | const Operations = require('./operations'); 7 | 8 | function validateTransforms(transforms) { 9 | return Object.entries(transforms).map(([key, transform]) => { 10 | return Actions.validate(key, transform.action, transform.value); 11 | }); 12 | } 13 | 14 | const nodeVisitor = { 15 | ObjectExpression(path, state) { 16 | const { nodeData: parentData, globalTypes } = state; 17 | const namedParent = path.parent.key && path.parent.key.name; 18 | 19 | const currentData = 20 | namedParent && 21 | parentData && 22 | parentData.nextNodes.find(n => n.key === namedParent); 23 | 24 | if (currentData) { 25 | // detect and create missing nodes 26 | const childrenKeys = path.node.properties.map(node => node.key.name); 27 | const missingKeys = ArrayHelpers.diff( 28 | currentData.nextNodes.map(n => n.key), 29 | childrenKeys 30 | ); 31 | missingKeys.forEach(key => { 32 | const newObjectProperty = globalTypes.ObjectProperty( 33 | globalTypes.identifier(key), 34 | toAst(globalTypes, {}) 35 | ); 36 | 37 | path.node.properties = [...path.node.properties, newObjectProperty]; 38 | }); 39 | // update current node if needed 40 | if ( 41 | currentData.ops.includes(Operations.delete) && 42 | !currentData.value && 43 | !currentData.nextNodes.length 44 | ) { 45 | path.parentPath.remove(); 46 | } else if ( 47 | currentData.value && 48 | currentData.ops.includes(Operations.merge) 49 | ) { 50 | if (path.node.value) { 51 | const { type } = path.node.value; 52 | switch (type) { 53 | case 'ArrayExpression': 54 | const elements = path.node.elements.concat( 55 | toAst(globalTypes, currentData.value).elements 56 | ); 57 | const updatedArray = Object.assign({}, path.node, { elements }); 58 | path.replaceWithMultiple([updatedArray]); 59 | break; 60 | 61 | default: 62 | const properties = path.node.properties.concat( 63 | toAst(globalTypes, currentData.value).properties 64 | ); 65 | const updatedObj = Object.assign({}, path.node, { properties }); 66 | path.replaceWith(updatedObj); 67 | } 68 | } else { 69 | path.replaceWith(toAst(globalTypes, currentData.value)); 70 | } 71 | } else if ( 72 | currentData.value && 73 | (currentData.ops.includes(Operations.replace) || 74 | currentData.ops.includes(Operations.create)) 75 | ) { 76 | path.replaceWith(toAst(globalTypes, currentData.value)); 77 | } 78 | 79 | // keep exploring with a subset of the model based on the current visited node 80 | path.skip(); 81 | path.traverse(nodeVisitor, { nodeData: currentData, globalTypes }); 82 | } else if ( 83 | !namedParent && 84 | path.parent.type === 'ExportDefaultDeclaration' 85 | ) { 86 | // Create missing nodes when at root 87 | const childrenKeys = path.node.properties.map(node => node.key.name); 88 | const missingNodes = parentData.nextNodes.filter( 89 | node => childrenKeys.indexOf(node.key) === -1 90 | ); 91 | 92 | if (missingNodes) { 93 | missingNodes.forEach(nodeData => { 94 | const newObjectProperty = globalTypes.ObjectProperty( 95 | globalTypes.identifier(nodeData.key), 96 | toAst(globalTypes, {}) 97 | ); 98 | 99 | path.node.properties = [...path.node.properties, newObjectProperty]; 100 | }); 101 | } 102 | } 103 | }, 104 | ArrayExpression(path, state) { 105 | const { nodeData: parentData, globalTypes } = state; 106 | const namedParent = path.parent.key && path.parent.key.name; 107 | 108 | const currentData = 109 | namedParent && 110 | parentData && 111 | parentData.nextNodes.find(n => n.key === namedParent); 112 | 113 | // update current node if needed 114 | if (currentData) { 115 | if ( 116 | currentData.ops.includes(Operations.delete) && 117 | !currentData.value && 118 | !currentData.nextNodes.length 119 | ) { 120 | path.parentPath.remove(); 121 | return; 122 | } else if (currentData.value) { 123 | if (currentData.ops.includes(Operations.merge)) { 124 | const elements = path.node.elements.concat( 125 | toAst(globalTypes, currentData.value).elements 126 | ); 127 | const updated = Object.assign({}, path.node, { elements }); 128 | path.replaceWithMultiple([updated]); 129 | } else if ( 130 | currentData.ops.includes(Operations.replace) || 131 | currentData.ops.includes(Operations.create) 132 | ) { 133 | path.replaceWithMultiple([toAst(globalTypes, currentData.value)]); 134 | } 135 | } 136 | 137 | // keep exploring with a subset of the model based on the current visited node 138 | path.skip(); 139 | path.traverse(nodeVisitor, { nodeData: currentData, globalTypes }); 140 | } 141 | } 142 | }; 143 | 144 | module.exports = function ({ types: globalTypes }, transforms) { 145 | const validActions = validateTransforms(transforms); 146 | const data = validActions 147 | .map(Actions.convertToTree) 148 | .reduce((accTree, actionTree) => { 149 | return accTree.combine(actionTree); 150 | }, Trees.empty()); 151 | 152 | return { 153 | name: 'babel-plugin-transform-config', 154 | visitor: { 155 | ExportDefaultDeclaration(path) { 156 | path.traverse(nodeVisitor, { nodeData: data.root, globalTypes }); 157 | } 158 | } 159 | }; 160 | }; 161 | -------------------------------------------------------------------------------- /test/__snapshots__/index.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`transformConfig.transform creates array 1`] = ` 4 | "export default { 5 | foo: ['default'], 6 | foo2: ['default'], 7 | bar: { 8 | baz: ['default'], 9 | baz2: ['default'] 10 | }, 11 | qux: [{}], 12 | test: [\\"created\\"] 13 | };" 14 | `; 15 | 16 | exports[`transformConfig.transform creates array in object 1`] = ` 17 | "export default { 18 | foo: ['default'], 19 | foo2: ['default'], 20 | bar: { 21 | baz: ['default'], 22 | baz2: ['default'], 23 | nested: [\\"created\\"] 24 | }, 25 | qux: [{}] 26 | };" 27 | `; 28 | 29 | exports[`transformConfig.transform creates multiple arrays 1`] = ` 30 | "export default { 31 | foo: ['default'], 32 | foo2: ['default'], 33 | bar: { 34 | baz: ['default'], 35 | baz2: ['default'] 36 | }, 37 | qux: [{}], 38 | test: [\\"created\\"], 39 | test2: [\\"created2\\"] 40 | };" 41 | `; 42 | 43 | exports[`transformConfig.transform creates multiple arrays in object 1`] = ` 44 | "export default { 45 | foo: ['default'], 46 | foo2: ['default'], 47 | bar: { 48 | baz: ['default'], 49 | baz2: ['default'], 50 | nested: [\\"created\\"], 51 | nested2: [\\"created2\\"], 52 | nested3: [\\"created3\\"] 53 | }, 54 | qux: [{}] 55 | };" 56 | `; 57 | 58 | exports[`transformConfig.transform creates nested array 1`] = ` 59 | "export default { 60 | foo: ['default'], 61 | foo2: ['default'], 62 | bar: { 63 | baz: ['default'], 64 | baz2: ['default'] 65 | }, 66 | qux: [{}], 67 | test: { 68 | nested: [\\"created\\"] 69 | } 70 | };" 71 | `; 72 | 73 | exports[`transformConfig.transform creates nested multiple arrays 1`] = ` 74 | "export default { 75 | foo: ['default'], 76 | foo2: ['default'], 77 | bar: { 78 | baz: ['default'], 79 | baz2: ['default'] 80 | }, 81 | qux: [{}], 82 | test: { 83 | nested: [\\"created\\"], 84 | nested2: [\\"created2\\"], 85 | nested3: [\\"created3\\"] 86 | } 87 | };" 88 | `; 89 | 90 | exports[`transformConfig.transform creates/merges array 1`] = ` 91 | Array [ 92 | "export default { 93 | foo: ['default', \\"created/merged\\"], 94 | foo2: ['default'], 95 | bar: { 96 | baz: ['default'], 97 | baz2: ['default'] 98 | }, 99 | qux: [{}] 100 | };", 101 | "export default { 102 | foo: ['default'], 103 | foo2: ['default'], 104 | bar: { 105 | baz: ['default'], 106 | baz2: ['default'] 107 | }, 108 | qux: [{}], 109 | test: [\\"created/merged\\"] 110 | };", 111 | ] 112 | `; 113 | 114 | exports[`transformConfig.transform creates/merges array in object 1`] = ` 115 | Array [ 116 | "export default { 117 | foo: ['default'], 118 | foo2: ['default'], 119 | bar: { 120 | baz: ['default', \\"created/merged\\"], 121 | baz2: ['default'] 122 | }, 123 | qux: [{}] 124 | };", 125 | "export default { 126 | foo: ['default'], 127 | foo2: ['default'], 128 | bar: { 129 | baz: ['default'], 130 | baz2: ['default'], 131 | nested: [\\"created/merged\\"] 132 | }, 133 | qux: [{}] 134 | };", 135 | ] 136 | `; 137 | 138 | exports[`transformConfig.transform creates/merges nested array 1`] = ` 139 | "export default { 140 | foo: ['default'], 141 | foo2: ['default'], 142 | bar: { 143 | baz: ['default'], 144 | baz2: ['default'] 145 | }, 146 | qux: [{}], 147 | test: { 148 | nested: [\\"created/merged\\"] 149 | } 150 | };" 151 | `; 152 | 153 | exports[`transformConfig.transform creates/replaces array 1`] = ` 154 | Array [ 155 | "export default { 156 | foo: [\\"created/replaced\\"], 157 | foo2: ['default'], 158 | bar: { 159 | baz: ['default'], 160 | baz2: ['default'] 161 | }, 162 | qux: [{}] 163 | };", 164 | "export default { 165 | foo: ['default'], 166 | foo2: ['default'], 167 | bar: { 168 | baz: ['default'], 169 | baz2: ['default'] 170 | }, 171 | qux: [{}], 172 | test: [\\"created/replaced\\"] 173 | };", 174 | ] 175 | `; 176 | 177 | exports[`transformConfig.transform creates/replaces array in object 1`] = ` 178 | Array [ 179 | "export default { 180 | foo: ['default'], 181 | foo2: ['default'], 182 | bar: { 183 | baz: [\\"created/replaced\\"], 184 | baz2: ['default'] 185 | }, 186 | qux: [{}] 187 | };", 188 | "export default { 189 | foo: ['default'], 190 | foo2: ['default'], 191 | bar: { 192 | baz: ['default'], 193 | baz2: ['default'], 194 | nested: [\\"created/replaced\\"] 195 | }, 196 | qux: [{}] 197 | };", 198 | ] 199 | `; 200 | 201 | exports[`transformConfig.transform creates/replaces nested array 1`] = ` 202 | "export default { 203 | foo: ['default'], 204 | foo2: ['default'], 205 | bar: { 206 | baz: ['default'], 207 | baz2: ['default'] 208 | }, 209 | qux: [{}], 210 | test: { 211 | nested: [\\"created/replaced\\"] 212 | } 213 | };" 214 | `; 215 | 216 | exports[`transformConfig.transform deletes array 1`] = ` 217 | "export default { 218 | foo2: ['default'], 219 | bar: { 220 | baz: ['default'], 221 | baz2: ['default'] 222 | }, 223 | qux: [{}] 224 | };" 225 | `; 226 | 227 | exports[`transformConfig.transform deletes array in object 1`] = ` 228 | "export default { 229 | foo: ['default'], 230 | foo2: ['default'], 231 | bar: { 232 | baz2: ['default'] 233 | }, 234 | qux: [{}] 235 | };" 236 | `; 237 | 238 | exports[`transformConfig.transform deletes multiple arrays 1`] = ` 239 | "export default { 240 | bar: { 241 | baz: ['default'], 242 | baz2: ['default'] 243 | }, 244 | qux: [{}] 245 | };" 246 | `; 247 | 248 | exports[`transformConfig.transform deletes multiple arrays in object 1`] = ` 249 | "export default { 250 | foo: ['default'], 251 | foo2: ['default'], 252 | bar: {}, 253 | qux: [{}] 254 | };" 255 | `; 256 | 257 | exports[`transformConfig.transform deletes object 1`] = ` 258 | "export default { 259 | foo: ['default'], 260 | foo2: ['default'], 261 | qux: [{}] 262 | };" 263 | `; 264 | 265 | exports[`transformConfig.transform merges array 1`] = ` 266 | "export default { 267 | foo: ['default', \\"merged\\"], 268 | foo2: ['default'], 269 | bar: { 270 | baz: ['default'], 271 | baz2: ['default'] 272 | }, 273 | qux: [{}] 274 | };" 275 | `; 276 | 277 | exports[`transformConfig.transform merges array in object 1`] = ` 278 | "export default { 279 | foo: ['default'], 280 | foo2: ['default'], 281 | bar: { 282 | baz: ['default', \\"merged\\"], 283 | baz2: ['default'] 284 | }, 285 | qux: [{}] 286 | };" 287 | `; 288 | 289 | exports[`transformConfig.transform merges multiple arrays 1`] = ` 290 | "export default { 291 | foo: ['default', \\"merged\\"], 292 | foo2: ['default', \\"merged2\\"], 293 | bar: { 294 | baz: ['default'], 295 | baz2: ['default'] 296 | }, 297 | qux: [{}] 298 | };" 299 | `; 300 | 301 | exports[`transformConfig.transform merges multiple arrays in object 1`] = ` 302 | "export default { 303 | foo: ['default'], 304 | foo2: ['default'], 305 | bar: { 306 | baz: ['default', \\"merged\\"], 307 | baz2: ['default', \\"merged2\\"] 308 | }, 309 | qux: [{}] 310 | };" 311 | `; 312 | 313 | exports[`transformConfig.transform replaces array 1`] = ` 314 | "export default { 315 | foo: [\\"replaced\\"], 316 | foo2: ['default'], 317 | bar: { 318 | baz: ['default'], 319 | baz2: ['default'] 320 | }, 321 | qux: [{}] 322 | };" 323 | `; 324 | 325 | exports[`transformConfig.transform replaces array in object 1`] = ` 326 | "export default { 327 | foo: ['default'], 328 | foo2: ['default'], 329 | bar: { 330 | baz: [\\"replaced\\"], 331 | baz2: ['default'] 332 | }, 333 | qux: [{}] 334 | };" 335 | `; 336 | 337 | exports[`transformConfig.transform replaces multiple arrays 1`] = ` 338 | "export default { 339 | foo: [\\"replaced\\"], 340 | foo2: [\\"replaced2\\"], 341 | bar: { 342 | baz: ['default'], 343 | baz2: ['default'] 344 | }, 345 | qux: [{}] 346 | };" 347 | `; 348 | 349 | exports[`transformConfig.transform replaces multiple arrays in object 1`] = ` 350 | "export default { 351 | foo: ['default'], 352 | foo2: ['default'], 353 | bar: { 354 | baz: [\\"replaced\\"], 355 | baz2: [\\"replaced2\\"] 356 | }, 357 | qux: [{}] 358 | };" 359 | `; 360 | -------------------------------------------------------------------------------- /test/index.spec.js: -------------------------------------------------------------------------------- 1 | const transformConfig = require('../'); 2 | const consola = require('consola'); 3 | 4 | describe('transformConfig.transform', () => { 5 | const config = `export default { 6 | foo: ['default'], 7 | foo2: ['default'], 8 | bar: { 9 | baz: ['default'], 10 | baz2: ['default'] 11 | }, 12 | qux: [{}] 13 | };`; 14 | 15 | /** 16 | * Creates 17 | */ 18 | it('creates array', () => { 19 | const transforms = { 20 | test: { 21 | action: 'create', 22 | value: ['created'] 23 | } 24 | }; 25 | const transformed = transformConfig.transform(config, transforms); 26 | expect(transformed.code).toMatchSnapshot(); 27 | }); 28 | it('creates multiple arrays', () => { 29 | const transforms = { 30 | test: { 31 | action: 'create', 32 | value: ['created'] 33 | }, 34 | test2: { 35 | action: 'create', 36 | value: ['created2'] 37 | } 38 | }; 39 | const transformed = transformConfig.transform(config, transforms); 40 | expect(transformed.code).toMatchSnapshot(); 41 | }); 42 | it('creates array in object', () => { 43 | const transforms = { 44 | 'bar:nested': { 45 | action: 'create', 46 | value: ['created'] 47 | } 48 | }; 49 | const transformed = transformConfig.transform(config, transforms); 50 | expect(transformed.code).toMatchSnapshot(); 51 | }); 52 | it('creates multiple arrays in object', () => { 53 | const transforms = { 54 | 'bar:nested': { 55 | action: 'create', 56 | value: ['created'] 57 | }, 58 | 'bar:nested2': { 59 | action: 'create', 60 | value: ['created2'] 61 | }, 62 | 'bar:nested3': { 63 | action: 'create', 64 | value: ['created3'] 65 | } 66 | }; 67 | const transformed = transformConfig.transform(config, transforms); 68 | expect(transformed.code).toMatchSnapshot(); 69 | }); 70 | it('creates nested array', () => { 71 | const transforms = { 72 | 'test:nested': { 73 | action: 'create', 74 | value: ['created'] 75 | } 76 | }; 77 | const transformed = transformConfig.transform(config, transforms); 78 | expect(transformed.code).toMatchSnapshot(); 79 | }); 80 | it('creates nested multiple arrays', () => { 81 | const transforms = { 82 | 'test:nested': { 83 | action: 'create', 84 | value: ['created'] 85 | }, 86 | 'test:nested2': { 87 | action: 'create', 88 | value: ['created2'] 89 | }, 90 | 'test:nested3': { 91 | action: 'create', 92 | value: ['created3'] 93 | } 94 | }; 95 | const transformed = transformConfig.transform(config, transforms); 96 | expect(transformed.code).toMatchSnapshot(); 97 | }); 98 | 99 | /** 100 | * Replaces 101 | */ 102 | it('replaces array', () => { 103 | const transforms = { 104 | foo: { 105 | action: 'replace', 106 | value: ['replaced'] 107 | } 108 | }; 109 | const transformed = transformConfig.transform(config, transforms); 110 | expect(transformed.code).toMatchSnapshot(); 111 | }); 112 | it('replaces multiple arrays', () => { 113 | const transforms = { 114 | foo: { 115 | action: 'replace', 116 | value: ['replaced'] 117 | }, 118 | foo2: { 119 | action: 'replace', 120 | value: ['replaced2'] 121 | } 122 | }; 123 | const transformed = transformConfig.transform(config, transforms); 124 | expect(transformed.code).toMatchSnapshot(); 125 | }); 126 | it('replaces array in object', () => { 127 | const transforms = { 128 | 'bar:baz': { 129 | action: 'replace', 130 | value: ['replaced'] 131 | } 132 | }; 133 | const transformed = transformConfig.transform(config, transforms); 134 | expect(transformed.code).toMatchSnapshot(); 135 | }); 136 | it('replaces multiple arrays in object', () => { 137 | const transforms = { 138 | 'bar:baz': { 139 | action: 'replace', 140 | value: ['replaced'] 141 | }, 142 | 'bar:baz2': { 143 | action: 'replace', 144 | value: ['replaced2'] 145 | } 146 | }; 147 | const transformed = transformConfig.transform(config, transforms); 148 | expect(transformed.code).toMatchSnapshot(); 149 | }); 150 | 151 | /** 152 | * Merges 153 | */ 154 | it('merges array', () => { 155 | const transforms = { 156 | foo: { 157 | action: 'merge', 158 | value: ['merged'] 159 | } 160 | }; 161 | const transformed = transformConfig.transform(config, transforms); 162 | expect(transformed.code).toMatchSnapshot(); 163 | }); 164 | it('merges multiple arrays', () => { 165 | const transforms = { 166 | foo: { 167 | action: 'merge', 168 | value: ['merged'] 169 | }, 170 | foo2: { 171 | action: 'merge', 172 | value: ['merged2'] 173 | } 174 | }; 175 | const transformed = transformConfig.transform(config, transforms); 176 | expect(transformed.code).toMatchSnapshot(); 177 | }); 178 | it('merges array in object', () => { 179 | const transforms = { 180 | 'bar:baz': { 181 | action: 'merge', 182 | value: ['merged'] 183 | } 184 | }; 185 | const transformed = transformConfig.transform(config, transforms); 186 | expect(transformed.code).toMatchSnapshot(); 187 | }); 188 | it('merges multiple arrays in object', () => { 189 | const transforms = { 190 | 'bar:baz': { 191 | action: 'merge', 192 | value: ['merged'] 193 | }, 194 | 'bar:baz2': { 195 | action: 'merge', 196 | value: ['merged2'] 197 | } 198 | }; 199 | const transformed = transformConfig.transform(config, transforms); 200 | expect(transformed.code).toMatchSnapshot(); 201 | }); 202 | 203 | /** 204 | * Deletes 205 | */ 206 | it('deletes array', () => { 207 | const transforms = { 208 | foo: { 209 | action: 'delete' 210 | } 211 | }; 212 | const transformed = transformConfig.transform(config, transforms); 213 | expect(transformed.code).toMatchSnapshot(); 214 | }); 215 | it('deletes multiple arrays', () => { 216 | const transforms = { 217 | foo: { 218 | action: 'delete' 219 | }, 220 | foo2: { 221 | action: 'delete' 222 | } 223 | }; 224 | const transformed = transformConfig.transform(config, transforms); 225 | expect(transformed.code).toMatchSnapshot(); 226 | }); 227 | it('deletes array in object', () => { 228 | const transforms = { 229 | 'bar:baz': { 230 | action: 'delete' 231 | } 232 | }; 233 | const transformed = transformConfig.transform(config, transforms); 234 | expect(transformed.code).toMatchSnapshot(); 235 | }); 236 | it('deletes multiple arrays in object', () => { 237 | const transforms = { 238 | 'bar:baz': { 239 | action: 'delete' 240 | }, 241 | 'bar:baz2': { 242 | action: 'delete' 243 | } 244 | }; 245 | const transformed = transformConfig.transform(config, transforms); 246 | expect(transformed.code).toMatchSnapshot(); 247 | }); 248 | it('deletes object', () => { 249 | const transforms = { 250 | bar: { 251 | action: 'delete' 252 | } 253 | }; 254 | const transformed = transformConfig.transform(config, transforms); 255 | expect(transformed.code).toMatchSnapshot(); 256 | }); 257 | 258 | /** 259 | * Creates/Replaces 260 | */ 261 | it('creates/replaces array', () => { 262 | const transformsArray = [ 263 | { 264 | foo: { 265 | action: 'create:replace', 266 | value: ['created/replaced'] 267 | } 268 | }, 269 | { 270 | test: { 271 | action: 'create:replace', 272 | value: ['created/replaced'] 273 | } 274 | } 275 | ]; 276 | const transformed = transformsArray.map(transforms => 277 | transformConfig.transform(config, transforms) 278 | ); 279 | expect(transformed.map(t => t.code)).toMatchSnapshot(); 280 | }); 281 | it('creates/replaces array in object', () => { 282 | const transformsArray = [ 283 | { 284 | 'bar:baz': { 285 | action: 'create:replace', 286 | value: ['created/replaced'] 287 | } 288 | }, 289 | { 290 | 'bar:nested': { 291 | action: 'create:replace', 292 | value: ['created/replaced'] 293 | } 294 | } 295 | ]; 296 | const transformed = transformsArray.map(transforms => 297 | transformConfig.transform(config, transforms) 298 | ); 299 | expect(transformed.map(t => t.code)).toMatchSnapshot(); 300 | }); 301 | it('creates/replaces nested array', () => { 302 | const transforms = { 303 | 'test:nested': { 304 | action: 'create:replace', 305 | value: ['created/replaced'] 306 | } 307 | }; 308 | const transformed = transformConfig.transform(config, transforms); 309 | expect(transformed.code).toMatchSnapshot(); 310 | }); 311 | 312 | /** 313 | * Creates/Merges 314 | */ 315 | it('creates/merges array', () => { 316 | const transformsArray = [ 317 | { 318 | foo: { 319 | action: 'create:merge', 320 | value: ['created/merged'] 321 | } 322 | }, 323 | { 324 | test: { 325 | action: 'create:merge', 326 | value: ['created/merged'] 327 | } 328 | } 329 | ]; 330 | const transformed = transformsArray.map(transforms => 331 | transformConfig.transform(config, transforms) 332 | ); 333 | expect(transformed.map(t => t.code)).toMatchSnapshot(); 334 | }); 335 | it('creates/merges array in object', () => { 336 | const transformsArray = [ 337 | { 338 | 'bar:baz': { 339 | action: 'create:merge', 340 | value: ['created/merged'] 341 | } 342 | }, 343 | { 344 | 'bar:nested': { 345 | action: 'create:merge', 346 | value: ['created/merged'] 347 | } 348 | } 349 | ]; 350 | const transformed = transformsArray.map(transforms => 351 | transformConfig.transform(config, transforms) 352 | ); 353 | expect(transformed.map(t => t.code)).toMatchSnapshot(); 354 | }); 355 | it('creates/merges nested array', () => { 356 | const transforms = { 357 | 'test:nested': { 358 | action: 'create:merge', 359 | value: ['created/merged'] 360 | } 361 | }; 362 | const transformed = transformConfig.transform(config, transforms); 363 | expect(transformed.code).toMatchSnapshot(); 364 | }); 365 | }); 366 | 367 | describe('transformConfig', () => { 368 | it('should call consola.error when no transforms are made', () => { 369 | consola.mockTypes(typeName => typeName === 'error' && jest.fn()); 370 | 371 | const result = transformConfig('', 'nuxt', {}); 372 | 373 | expect(consola.error).toBeCalledWith('No transforms performed'); 374 | }); 375 | 376 | it('should call consola.error when no transforms are made', () => { 377 | consola.mockTypes(typeName => typeName === 'error' && jest.fn()); 378 | const framework = 'foo'; 379 | const message = `[transform-configs] ${framework} Framework not supported\nUse babel plugin directly instead`; 380 | 381 | const result = transformConfig('', framework, {}); 382 | 383 | expect(consola.error).toBeCalledWith(message); 384 | }); 385 | 386 | it('should call consola.error when no transforms are made', () => { 387 | consola.mockTypes(typeName => typeName === 'error' && jest.fn()); 388 | const framework = '__proto__'; 389 | const message = `[transform-configs] ${framework} Framework not supported\nUse babel plugin directly instead`; 390 | 391 | const result = transformConfig('', framework, {}); 392 | 393 | expect(consola.error).toBeCalledWith(message); 394 | }); 395 | }); 396 | --------------------------------------------------------------------------------