Socket
Socket
Sign inDemoInstall

@prismicio/babel-transform-config

Package Overview
Dependencies
9
Maintainers
14
Versions
4
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.5 to 0.0.6-alpha.ea631c8

plugin/actions.js

73

index.js

@@ -52,33 +52,27 @@ const consola = require('consola')

if (!frameworkTable) {
return consola.error(`[transform-configs] ${framework} Framework not supported\nUse babel plugin directly instead`)
throw new Error(`[transform-configs] ${framework} Framework not supported\nUse babel plugin directly instead`)
}
try {
const transforms = Object.entries(args).reduce((acc, [k, v]) => {
if (frameworkTable[k]) {
const [key, value] = frameworkTable[k](v)
return {
...acc,
[key]: value
}
const transforms = Object.entries(args).reduce((acc, [k, v]) => {
if (frameworkTable[k]) {
const [key, value] = frameworkTable[k](v)
return {
...acc,
[key]: value
}
keysNotFound.push(k)
if (!strict) {
return {
...acc,
[k]: {
action: "create:merge",
value: v
}
}
keysNotFound.push(k)
if (!strict) {
return {
...acc,
[k]: {
action: "create:merge",
value: v
}
}
return acc
}, {})
return {
transforms,
keysNotFound
}
} catch(e) {
return {
reason: e
}
return acc
}, {})
return {
transforms,
keysNotFound
}

@@ -104,15 +98,18 @@ }

function transformConfig(code, framework, args, strict = true) {
const {
transforms,
keysNotFound,
reason,
} = createTransformArgs(framework, args, strict)
try {
const {
transforms,
keysNotFound,
} = createTransformArgs(framework, args, strict)
if (!transforms) {
return consola.error(reason)
if (!transforms) {
return consola.error(reason)
}
if (!strict && keysNotFound.length) {
handleKeysNotFound(keysNotFound);
}
return transform(code, transforms)
} catch(e) {
consola.error(e.message);
}
if (!strict && keysNotFound.length) {
handleKeysNotFound(keysNotFound);
}
return transform(code, transforms)
}

@@ -123,2 +120,2 @@

module.exports = transformConfig
module.exports = transformConfig
{
"name": "@prismicio/babel-transform-config",
"version": "0.0.5",
"version": "0.0.6-alpha.ea631c8",
"description": "Transform JS config files (Next, Nuxt, Gatsby)",

@@ -18,2 +18,5 @@ "main": "index.js",

"author": "Hugo Villain",
"contributors": [
"Arnaud lewis (@arnaudlewis)"
],
"license": "ISC",

@@ -20,0 +23,0 @@ "dependencies": {

@@ -1,164 +0,114 @@

const consola = require('consola')
const toAst = require('./toAst')
const consola = require('consola');
const Actions = require('./actions');
const Trees = require('./tree').Trees;
const ArrayHelpers = require('./utils').ArrayHelpers;
const toAst = require('./toAst');
const Operations = require('./operations');
const {
dedupeStringLiterals,
testNodeValue,
buildSubjacentPaths
} = require('./utils')
const OPERATIONS = ['create', 'merge', 'replace', 'delete']
function mergePaths(parentKeys, nodeName) {
return `${parentKeys}${parentKeys.length ? ':' : ''}${nodeName}`
}
function validateAction(transform) {
const operations = transform.action.split(':')
operations.forEach((operation) => {
if (!OPERATIONS.includes(operation)) {
throw new Error(`Operation "${operation}" does not exist.\nDefined operations: ${OPERATIONS}`)
}
})
if (operations.includes('merge') && operations.includes('replace')) {
throw new Error('Operations "merge" and "update" cannot coexist in transform\'s "action" property')
}
if (operations.includes('create') && operations.includes('delete')) {
throw new Error('Operations "create" and "delete" cannot coexist in transform\'s "action" property')
}
if (operations.includes('merge') && !Array.isArray(transform.value)) {
throw new Error('Operations "merge" expects value to be of type "Array" (tested with Array.isArray)')
}
}
function validateTransforms(transforms) {
Object.entries(transforms).forEach(([key, transform]) => {
if (!transform.action || !transform.action.length) {
throw new Error(`Transformation with key "${key}" should possess a non-empty "action" key`)
}
if (transform.action.indexOf('delete') === -1 && transform.value === undefined) {
throw new Error(`Transformation with key "${key}" should possess a non-empty "value" key`)
}
validateAction(transform)
return Object.entries(transforms).map(([key, transform]) => {
return Actions.validate(key, transform.action, transform.value)
})
}
module.exports = function({ types: t }, transforms) {
const status = {}
const nodeVisitor = {
ObjectExpression(path, state) {
const { nodeData: parentData, globalTypes } = state;
const namedParent = path.parent.key && path.parent.key.name;
validateTransforms(transforms)
Object.keys(transforms).forEach((key) => status[key] = false)
const currentData = namedParent && parentData && parentData.nextNodes.find(n => n.key === namedParent);
if(currentData) {
// detect and create missing nodes
const childrenKeys = path.node.properties.map(node => node.key.name);
const missingKeys = ArrayHelpers.diff(currentData.nextNodes.map(n => n.key), childrenKeys);
if(missingKeys.length) {
missingKeys.forEach(key => {
const newObjectProperty = globalTypes.ObjectProperty(
globalTypes.identifier(key),
toAst(globalTypes, {})
);
const expressionVisitor = {
ObjectExpression(path, { isRoot, objectKeysPath, createKey, value }) {
path.node.properties = [
...path.node.properties,
newObjectProperty
];
});
}
// update current node if needed
if(currentData.ops.includes(Operations.delete && !currentData.value) && !currentData.nextNodes.length) {
path.remove();
} else if(currentData.value && currentData.ops.includes(Operations.merge)) {
if(path.node.value) {
const { type } = path.node.value;
switch(type) {
case 'ArrayExpression':
const elements = path.node.elements.concat(toAst(globalTypes, currentData.value).elements);
const updated = Object.assign({}, path.node, { elements });
path.replaceWithMultiple([
updated
]);
break;
const fullPathToBuild = mergePaths(objectKeysPath, createKey)
const currentParentKey = path.parent.key ? path.parent.key.name : ''
const currentPathToBuild = mergePaths(currentParentKey, createKey)
if (currentPathToBuild === fullPathToBuild) {
if (
path.parent.declaration
&& path.parent.declaration.properties
&& path.parent.declaration.properties.find(e => e.key.name === createKey)
) {
return
default:
const properties = path.node.properties.concat(toAst(globalTypes, currentData.value).properties);
const updated = Object.assign({}, path.node, { properties });
path.replaceWith(updated);
}
} else {
path.replaceWith(toAst(globalTypes, currentData.value));
}
} else if(currentData.value && (currentData.ops.includes(Operations.replace) || currentData.ops.includes(Operations.create))) {
path.replaceWith(toAst(globalTypes, currentData.value));
}
// Make sure you create root key
// at exportDefault level to prevent writing value evrywhere
if (isRoot && (!path.parentPath.node.key || path.parentPath.node.key.loc)) {
return
}
const newObjectProperty = t.ObjectProperty(
t.identifier(createKey),
toAst(t, value)
)
path.node.properties = [
...path.node.properties,
newObjectProperty
]
}
// keep exploring with a subset of the model based on the current visited node
path.skip();
path.traverse(nodeVisitor, { nodeData: currentData, globalTypes })
}
}
const objectPropVisitor = {
ObjectProperty(path, { parentKeys = '' } =  {}) {
const currentPath = mergePaths(parentKeys, path.node.key.name)
const transform = transforms[currentPath]
},
ArrayExpression(path, state) {
const { nodeData: parentData, globalTypes } = state;
const namedParent = path.parent.key && path.parent.key.name;
if (transform && !status[currentPath]) {
status[currentPath] = true
const operations = transform.action.split(':')
if (operations.includes('delete')) {
return path.remove()
}
const { type } = path.node.value
const elemExists = testNodeValue(t, path);
(function handleWrite() {
if ((!elemExists && operations.includes('create')) || operations.includes('replace')) {
path.node.value = toAst(t, transform.value)
}
else if (operations.includes('merge')) {
const accessor = type === 'ArrayExpression' ? 'elements' : 'properties'
const elems = [
...path.node.value[accessor],
...toAst(t, transform.value)[accessor]
];
path.node.value[accessor] = dedupeStringLiterals(elems)
}
})();
const currentData = namedParent && parentData && parentData.nextNodes.find(n => n.key === namedParent);
// update current node if needed
if(currentData) {
if(currentData.ops.includes(Operations.delete && !currentData.value) && !currentData.nextNodes.length) {
path.remove();
} else if(currentData.value && currentData.ops.includes(Operations.merge)) {
const elements = path.node.elements.concat(toAst(globalTypes, currentData.value).elements);
const updated = Object.assign({}, path.node, { elements });
path.replaceWithMultiple([
updated
]);
} else if(currentData.value && (currentData.ops.includes(Operations.replace) || currentData.ops.includes(Operations.create))) {
path.replaceWithMultiple([
toAst(globalTypes, currentData.value)
]);
}
if (path.node.value && (path.node.value.properties || path.node.value.elements)) {
return path.traverse(objectPropVisitor, {
parentKeys: currentPath
})
}
// keep exploring with a subset of the model based on the current visited node
path.skip();
path.traverse(nodeVisitor, { nodeData: currentData, globalTypes });
}
}
}
module.exports = function({ types: globalTypes }, transforms) {
const validActions = validateTransforms(transforms);
const data = validActions
.map(Actions.convertToTree)
.reduce((accTree, actionTree) => {
return accTree.combine(actionTree)
}, Trees.empty());
return {
name: 'babel-plugin-transform-config',
visitor: {
Program(path) {
const exportPath = path.get('body')
.find((path) => path.isExportDefaultDeclaration()
&& path.node.declaration
&& path.node.declaration.type === 'ObjectExpression'
)
if (!exportPath) {
return consola.error('Could not find default exported object. Maybe your config file returns a function?')
}
exportPath.traverse(objectPropVisitor)
Object.entries(status).forEach(([key, value]) => {
if (value === false && transforms[key].action.indexOf('create') !== -1) {
const subPaths = key.split(':')
const subPathsToCreate = buildSubjacentPaths(subPaths).slice(0, -1);
subPathsToCreate.forEach((p, i) => {
exportPath.traverse(expressionVisitor, {
objectKeysPath: p.slice(0, -1).join(':'),
createKey: p.pop(),
value: {},
isRoot: i === 0
})
})
exportPath.traverse(expressionVisitor, {
objectKeysPath: key.split(':').slice(0, -1).join(':'),
createKey: key.split(':').pop(),
value: transforms[key].value
})
}
}, [])
},
ExportDefaultDeclaration(path) {
path.traverse(nodeVisitor, { nodeData: data.root, globalTypes });
}
}
}
};
};
}

@@ -1,40 +0,48 @@

function buildSubjacentPaths(arr, store = [], len = 0) {
if (len >= arr.length) {
return store
}
store = [...store, arr.slice(0, len + 1)]
return buildSubjacentPaths(arr, store, len + 1)
}
const ArrayHelpers = {
splitAtLast(array) {
if(!array) return null;
function dedupeStringLiterals(elements) {
const set = new Set()
return elements.filter(e => {
if (e.type !== 'StringLiteral') {
return true
switch(array.length) {
case 0: return [[], null];
case 1: return [[], array[0]];
default: return [array.slice(0, -1), array[array.length - 1]]
}
const duplicate = set.has(e.value)
set.add(e.value)
return !duplicate
})
}
},
/** There probably is a better way */
function testNodeValue(t, path) {
const { type } = path.node.value
if (type === 'ArrayExpression') {
return !!path.node.value.elements.length
splitAtHead(array) {
if(!array) return null;
switch(array.length) {
case 0: return [null, []];
case 1: return [array[0], []];
default: return [array[0], array.slice(1)]
}
},
combine(array1, array2, mergeFn) {
const [main, other] = array1.length > array2.length ? [array2, array1] : [array1, array2];
return main
.map((value, index) => mergeFn(value, other[index]))
.concat(other.slice(main.length, other.length).map(value => mergeFn(undefined, value)))
},
flatten(arr) {
return arr.reduce((acc, subArr) => acc.concat(subArr), []);
},
distinct(arr1, arr2, predicate) {
this.flatten(
this.combine(arr1, arr2, (item1, item2) => predicate(item1, item2) ? [item1] : [item1, item2])
);
},
diff(array1, array2) {
return array1.filter(function(elm) {
return array2.indexOf(elm) === -1;
})
}
if (type === 'ObjectExpression') {
return !!path.node.value.properties.length
}
if (type === 'NullLiteral') {
return false
}
return true
}
module.exports = {
buildSubjacentPaths,
dedupeStringLiterals,
testNodeValue
}
ArrayHelpers
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc