Skip to content

Instantly share code, notes, and snippets.

@albertojg
Created December 9, 2016 07:04
Show Gist options
  • Save albertojg/8a8772f779ed9c7b8d54b758f18041c5 to your computer and use it in GitHub Desktop.
Save albertojg/8a8772f779ed9c7b8d54b758f18041c5 to your computer and use it in GitHub Desktop.
Transform import statement
const fs = require('fs');
const args = process.argv.slice(2);
const options = args
.reduce((result, arg) => {
const splittedArg = arg.split('=');
const key = splittedArg[0].replace('--', '');
const value = splittedArg[1];
result[key] = value;
return result;
}, {});
const commonComponents = require(options.commonComponentsPath);
const components = require(options.componentsPath);
const componentLibrary = require(options.componentLibraryPath);
const mapping = {
components: Object.assign({}, commonComponents, components),
'component-library': componentLibrary
};
// write mapping to file
const outputFilePath = options.outputFilePath;
fs.appendFileSync(outputFilePath, JSON.stringify(mapping));
const fs = require('fs');
function getComponentNamePathMapping(node) {
// extract the component source path
const sourcePath = node.value && node.value.source && node.value.source.rawValue;
if (!sourcePath) {
console.warn('Unable to find source path of node! Problematic node: ', node);
return;
}
// extract the component name
const nodeSpecifier = node.value && node.value.specifiers && node.value.specifiers[0];
const name = nodeSpecifier && nodeSpecifier.exported && nodeSpecifier.exported.name;
// skip if name is wildcard
if (name === '*') {
console.log('Skipping node due to wildcard import name!');
return;
}
return {sourcePath, name};
}
module.exports = function(file, api, options) {
const jscodeshift = api.jscodeshift;
// options
const prefixPath = options.prefixPath;
const outputFilePath = options.outputFilePath;
const mapping = {};
// parse source to abstract syntax tree
const ast = jscodeshift(file.source);
ast.find(jscodeshift.ExportNamedDeclaration)
.forEach((node) => {
const component = getComponentNamePathMapping(node);
if (component) {
const componentName = component.name;
const sourcePath = component.sourcePath.replace(/^\./, prefixPath);
mapping[componentName] = sourcePath;
}
});
// write mapping to file
fs.appendFileSync(outputFilePath, JSON.stringify(mapping));
// return un-modified code
return ast.toSource();
};
{
"name": "update-import-statement",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"update-import": "jscodeshift -v 2 -t transform-import.js",
"generate-path-mapper": "jscodeshift -v 2 -t generate-path-mapper.js",
"combine-path-mappers": "node combine-path-mappers"
},
"author": "albertojg",
"license": "UNLICENSED",
"dependencies": {
"jscodeshift": "^0.3.30"
}
}
#!/bin/bash
root=$1;
TEMP_DIRECTORY="./.path-mapper";
ORIGINAL_COMPONENTS_PATH="$root/components";
ORIGINAL_COMMON_COMPONENTS_PATH="$root/components/Common";
ORIGINAL_COMPONENT_LIBRARY_PATH="$root/component-library";
COMPONENTS_MAPPER_PATH="$TEMP_DIRECTORY/components.json";
COMMON_COMPONENTS_MAPPER_PATH="$TEMP_DIRECTORY/commonComponents.json";
COMPONENT_LIBRARY_MAPPER_PATH="$TEMP_DIRECTORY/componentLibrary.json";
IMPORT_FILE_PATH_MAPPER="$TEMP_DIRECTORY/path-mapper.json";
# re-initialize temp directory if exists
if [ -d $TEMP_DIRECTORY ]; then
rm -r $TEMP_DIRECTORY;
fi
mkdir -p $TEMP_DIRECTORY;
# transform index file to path dictionary
npm run generate-path-mapper -- \
"$ORIGINAL_COMPONENTS_PATH/index.js" \
--prefixPath="components" \
--outputFilePath=$COMPONENTS_MAPPER_PATH;
npm run generate-path-mapper -- \
"$ORIGINAL_COMMON_COMPONENTS_PATH/index.js" \
--prefixPath="components/Common" \
--outputFilePath=$COMMON_COMPONENTS_MAPPER_PATH;
npm run generate-path-mapper -- \
"$ORIGINAL_COMPONENT_LIBRARY_PATH/index.js" \
--prefixPath="component-library" \
--outputFilePath=$COMPONENT_LIBRARY_MAPPER_PATH;
# combine the list of path dictionary to a single dictionary path
npm run combine-path-mappers -- \
--commonComponentsPath=$COMMON_COMPONENTS_MAPPER_PATH \
--componentsPath=$COMPONENTS_MAPPER_PATH \
--componentLibraryPath=$COMPONENT_LIBRARY_MAPPER_PATH \
--outputFilePath=$IMPORT_FILE_PATH_MAPPER;
# transform the import
npm run update-import -- \
$root \
--pathMapper=$IMPORT_FILE_PATH_MAPPER;
# clean up temp directory
rm -r $TEMP_DIRECTORY;
function getNodeSourceRawValue(node) {
return node.value.source.rawValue;
}
function filterImportDeclaration(node) {
const sourceRawValue = getNodeSourceRawValue(node);
// filter to only replace import statement from 'components' or 'component-library'
return sourceRawValue === 'components' || sourceRawValue === 'component-library';
}
function updateImportComponents(jscodeshift, node, pathMapper) {
const sourceRawValue = getNodeSourceRawValue(node);
const modifiedNodeSpecifiers = [];
const nodeSpecifiers = node.value && node.value.specifiers;
nodeSpecifiers.forEach((specifier) => {
const importedComponentName = specifier.imported.name;
const componentPath = pathMapper[sourceRawValue][importedComponentName];
const localComponentName = specifier.local.name;
modifiedNodeSpecifiers.push(
`import ${localComponentName} from '${componentPath}';`
);
});
jscodeshift(node)
.replaceWith(modifiedNodeSpecifiers);
}
module.exports = function(file, api, options) {
const jscodeshift = api.jscodeshift;
const pathMapper = require(options.pathMapper);
// parse source to abstract syntax tree
const ast = jscodeshift(file.source);
// 1. search for import node
// 2. filter the nodes to only those that are importing from components or component-library
// 3. update the import statement
ast.find(jscodeshift.ImportDeclaration)
.filter(filterImportDeclaration)
.forEach((node) => updateImportComponents(jscodeshift, node, pathMapper));
return ast.toSource();
};
@albertojg
Copy link
Author

You just need to put them into the same directory.

npm i
./run.sh <path_to_your_code_src>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment