Skip to content

Instantly share code, notes, and snippets.

@markogresak
Created November 21, 2017 16:10
Show Gist options
  • Save markogresak/cb243d96c703cf86423c2bb2a6ff03f3 to your computer and use it in GitHub Desktop.
Save markogresak/cb243d96c703cf86423c2bb2a6ff03f3 to your computer and use it in GitHub Desktop.
/* eslint-disable no-console */
// "babel-core": "^6.24.1",
// "glob": "^7.1.2",
// "lodash": "^4.17.4",
// "babel-plugin-syntax-dynamic-import": "^6.18.0",
// "babel-plugin-transform-class-properties": "^6.24.1",
// "babel-plugin-syntax-decorators": "^6.13.0",
// "babel-preset-es2015": "^6.24.1",
// "babel-preset-react": "^6.24.1",
// "babel-preset-stage-0": "^6.24.1",
const {transformFile} = require('babel-core');
const path = require('path');
const fs = require('fs');
const glob = require('glob');
const _ = require('lodash');
const outFile = './text-nodes.txt';
fs.truncateSync(outFile);
const syntaxDynamicImport = require('babel-plugin-syntax-dynamic-import');
const transformClassProperties = require('babel-plugin-transform-class-properties');
const syntaxDecorators = require('babel-plugin-syntax-decorators');
const es2015 = require('babel-preset-es2015');
const react = require('babel-preset-react');
const stage0 = require('babel-preset-stage-0');
const babelTransformOpts = {
babelrc: false,
plugins: [
syntaxDynamicImport,
transformClassProperties,
syntaxDecorators,
],
presets: [
es2015,
react,
stage0,
],
};
const translatableTextRe = /\w/;
function serializeArguments(astObj) {
const children = _.get(astObj, 'arguments', []).slice(2);
const locData = {
start: `${_.get(astObj, 'loc.start.line')}:${_.get(astObj, 'loc.start.column')}`,
end: `${_.get(astObj, 'loc.end.line')}:${_.get(astObj, 'loc.end.column')}`,
};
return _.compact(_.map(children, c => {
const type = _.get(c, 'type');
if (type === 'StringLiteral') {
const val = _.get(c, 'value');
if (translatableTextRe.test(val)) {
return {
...locData,
text: val,
};
}
}
if (type === 'Identifier') {
return {
...locData,
variable: _.get(c, 'name'),
};
}
return null;
}));
}
function getNextPaths(astObj, pathsToProcess = [], currentPath = []) {
return _.keys(astObj)
.filter(k => astObj[k] && typeof astObj[k] === 'object')
.map(p => [...currentPath, p])
.filter(p => !pathsToProcess.includes(p) && !p.includes('_shadowedFunctionLiteral'));
}
function getTextNodes(filePath) {
return new Promise((resolve, reject) => {
console.time(`process ${filePath}`);
transformFile(filePath, babelTransformOpts, (err, {ast}) => {
if (err) {
reject(err);
return;
}
const astBody = ast.program.body;
const pathsToProcess = getNextPaths(astBody);
const textNodes = [];
while (pathsToProcess.length > 0) {
const currentPath = pathsToProcess.shift();
const astObj = _.get(astBody, currentPath);
if (astObj && typeof astObj === 'object') {
if (_.get(astObj, 'callee.property.name') === 'createElement') {
textNodes.push(serializeArguments(astObj));
}
pathsToProcess.push(...getNextPaths(astObj, pathsToProcess, currentPath));
}
}
console.timeEnd(`process ${filePath}`);
resolve({
filePath,
textNodes: _.flatten(textNodes),
});
});
});
}
function printFileTextNodes({filePath, textNodes = []} = {}) {
textNodes.forEach(({start, text, variable}) => {
const nodeInfo = text ? `${text.replace(/[\s\n]+/g, ' ')}` : `{${variable}}`;
const outText = `${filePath}:${start}: ${nodeInfo}`;
console.log(outText);
fs.appendFileSync(outFile, `${outText}\n`);
});
}
console.time('process all');
const processFilePromises = glob.sync(path.resolve(__dirname, './src/js/components/**/*.{js,jsx}'))
.filter(f => !f.match(/CKEditor/))
.map(getTextNodes);
Promise.all(processFilePromises)
.then(dataArr => {
console.log('\n\n');
dataArr.forEach(printFileTextNodes);
})
.catch(console.error.bind(console))
.then(() => {
console.log('\n');
console.timeEnd('process all');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment