UNPKG

okam-build

Version:

The build tool for Okam develop framework

280 lines (248 loc) 7.28 kB
/** * @file Transform helper * @author sparklewhy@gmail.com */ 'use strict'; const { getBaseId, getFrameworkExtendId, normalizeInternalBehavior } = require('../../../framework'); const LEADING_COMMENT_TYPE = 'leadingComments'; const TRAILING_COMMENT_TYPE = 'trailingComments'; /** * Convert the plain object node to javascript object * * @inner * @param {Object} node the plain object node * @param {Object} path the node path * @param {Object} t the babel type definition * @return {Object} */ function getPlainObjectNodeValue(node, path, t) { let result; if (t.isObjectExpression(node)) { result = {}; let props = node.properties || []; for (let i = 0, len = props.length; i < len; i++) { let subNode = props[i]; let keyNode = subNode.key; let key; if (t.isLiteral(keyNode)) { key = keyNode.value; } else if (t.isIdentifier(keyNode)) { key = keyNode.name; } if (!key) { continue; } result[key] = getPlainObjectNodeValue(subNode.value, path, t); } } else if (t.isArrayExpression(node)) { result = []; node.elements.forEach(item => { result.push(getPlainObjectNodeValue(item, path, t)); }); } else if (t.isNullLiteral(node)) { result = null; } else if (t.isLiteral(node)) { result = node.value; } else { throw path.buildCodeFrameError('only constant is supported'); } return result; } /** * Create require variable declaration statement * * @param {string} varName the variable name * @param {string} requireId the required id * @param {Object} t the babel type definition * @return {Object} */ exports.createRequireVarDeclaration = function (varName, requireId, t) { return t.variableDeclaration( 'var', [t.variableDeclarator( t.identifier(varName), t.callExpression( t.identifier('require'), [t.stringLiteral(requireId)] ) )] ); }; /** * Create import declaration statement * * @param {string|Array.<string>} varName the variable name to export * @param {string} requireId the required id * @param {Object} t the babel type definition * @return {Object} */ exports.createImportDeclaration = function (varName, requireId, t) { let importSpecs = []; if (Array.isArray(varName)) { varName.forEach(item => { importSpecs.push(t.importSpecifier( t.identifier(item), t.identifier(item) )); }); } else if (varName) { importSpecs = [t.importDefaultSpecifier( t.identifier(varName) )]; } return t.importDeclaration( importSpecs, t.stringLiteral(requireId) ); }; /** * Create AST node by the given value * * @inner * @param {*} value the value to create * @param {Object} t the babel type definition * @return {?Object} */ function createNode(value, t) { if (t.isIdentifier(value)) { return value; } if (Array.isArray(value)) { let elements = []; value.forEach(item => { let node = createNode(item, t); node && elements.push(node); }); return t.arrayExpression(elements); } if (Object.prototype.toString.call(value) === '[object Object]') { let props = []; Object.keys(value).forEach(k => { let node = createNode(value[k], t); if (node) { props.push(t.objectProperty( t.identifier(`'${k}'`), node )); } }); return t.objectExpression(props); } if (value == null) { return t.nullLiteral(); } let valueType = typeof value; switch (valueType) { case 'boolean': return t.booleanLiteral(value); case 'string': return t.stringLiteral(value); case 'number': return t.numericLiteral(value); } } /** * Create simple plain object expression * * @param {Object} simpleObj the plain object * @param {Object} t the babel type definition * @return {Object} */ exports.createSimpleObjectExpression = function (simpleObj, t) { return createNode(simpleObj, t); }; exports.getBaseId = getBaseId; exports.getFrameworkExtendId = getFrameworkExtendId; exports.normalizeInternalBehavior = normalizeInternalBehavior; /** * Remove node comments * * @param {Object} t the babel type definition * @param {Object} path the node path * @param {string} type the comment type */ function removeComments(t, path, type) { let commentPaths = path.get(type); if (!commentPaths || !commentPaths.length) { return; } let isLeadingType = type === LEADING_COMMENT_TYPE; if (isLeadingType) { let parentPath = path.parentPath; let isParentProgram = parentPath && t.isProgram(parentPath.node); // move leading comments to program if (isParentProgram) { parentPath.addComments( 'leading', commentPaths.map(item => item.node) ); } } commentPaths.forEach(item => item.remove()); } exports.removeComments = removeComments; /** * Remove node * * @param {Object} t the babel type definition * @param {Object} path the node path to remove * @param {Object} commentsRemoveOpts the node comment remove options * @param {boolean=} commentsRemoveOpts.head whether remove leading comments, * by default true if the parent of the removed node is program root node * and the leading comments will be moved to the program root node. * @param {boolean=} commentsRemoveOpts.tail whether remove tailing comments, * by default false */ exports.removeNode = function (t, path, commentsRemoveOpts = {}) { let {head, tail} = commentsRemoveOpts; if (head == null || head) { removeComments(t, path, LEADING_COMMENT_TYPE); } if (tail) { removeComments(t, path, TRAILING_COMMENT_TYPE); } path.remove(); }; /** * Convert ast plain object node to javascript plain object * * @param {Object} the ast node to convert * @param {Object} path the node path * @param {Object} t the babel type definition * @return {Object} */ exports.getPlainObjectNodeValue = getPlainObjectNodeValue; /** * Check whether the given variable name is defined in its scope * * @param {Object} path the variable used path * @param {string} varName the variable name * @return {boolean} */ exports.isVariableDefined = function (path, varName) { return path.scope.hasBinding(varName); }; /** * Generate code * * @param {Object} ast the code ast to generate * @param {Object} options the generation options * @param {boolean=} usingBabel6 whether using babel 6 * @return {string} */ exports.generateCode = function (ast, options, usingBabel6) { let generate = usingBabel6 ? require('babel-generator').default : require('@babel/generator').default; return generate(ast, options); };