|
|
@@ -0,0 +1,126 @@ |
|
|
import jscodeshift from "jscodeshift"; |
|
|
import fs from "fs"; |
|
|
import path from "path"; |
|
|
|
|
|
const projectDirectory = "my/project/root/directory"; |
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
// util functions |
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
/** |
|
|
* Walks through a directory tree and creates a list of every component file path |
|
|
* note: all React components end in `.jsx` in this codebase |
|
|
*/ |
|
|
function walkSync(dir, filelist = []) { |
|
|
const files = fs.readdirSync(dir); |
|
|
files.forEach((file: any) => { |
|
|
if (fs.statSync(`${dir}/${file}`).isDirectory()) { |
|
|
filelist = walkSync(`${dir}/${file}`, filelist); |
|
|
} else if (path.extname(file) === ".jsx") filelist.push(`${dir}/${file}`); |
|
|
}); |
|
|
|
|
|
return filelist; |
|
|
} |
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
// Example 1: |
|
|
// Create a list of form components using and not using form UI components |
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// list of form components in codebase |
|
|
const formComponentsFilePaths = walkSync(projectDirectory) |
|
|
.filter(filepath => new RegExp(".*Form\.jsx$").test(filepath, "g")); |
|
|
|
|
|
const formsUsingFormUI = []; |
|
|
const formsNotUsingFormUI = []; |
|
|
|
|
|
formComponentsFilePaths.forEach(filepath => { |
|
|
try { |
|
|
const fileSource = fs.readFileSync(filepath, "utf8"); |
|
|
const tree = jscodeshift.withParser("javascript")(fileSource); |
|
|
|
|
|
// look at the files imports and determine if any form components are imported |
|
|
// note: this approach assumes all imports are absolute |
|
|
|
|
|
let usesFormUIComponents = false; |
|
|
|
|
|
tree |
|
|
.find(jscodeshift.ImportDeclaration) |
|
|
.find(jscodeshift.Literal) |
|
|
.forEach(importPathNode => { |
|
|
const importPath = importPathNode.value.value; |
|
|
|
|
|
if (formUIComponentImportPaths.has(importPath)) { |
|
|
usesFormUIComponents = true; |
|
|
} |
|
|
}); |
|
|
|
|
|
if (usesFormUIComponents) { |
|
|
formsUsingFormUI.push(filepath); |
|
|
} else { |
|
|
formsNotUsingFormUI.push(filepath); |
|
|
} |
|
|
} catch(error) { |
|
|
throw new Error(error); |
|
|
} |
|
|
}); |
|
|
|
|
|
const stats1 = { |
|
|
formsUsingFormUI, |
|
|
formsNotUsingFormUI, |
|
|
usagePercentage: formsUsingFormUI.length / (formsUsingFormUI.length + formsNotUsingFormUI.length), |
|
|
}; |
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
// Example 2: |
|
|
// Find and list all instances of text literals so teams can go and update |
|
|
// them to use i18n |
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
const textLiteralLineNumbersByFile = { |
|
|
/* componentPath : list of line numbers, */ |
|
|
}; |
|
|
|
|
|
const componentFilePaths = walkSync(projectDirectory); |
|
|
|
|
|
componentFilePaths.forEach(filepath => { |
|
|
try { |
|
|
const fileSource = fs.readFileSync(filepath, "utf8"); |
|
|
|
|
|
// an AST representation of your source code |
|
|
const tree = jscodeshift.withParser("javascript")(fileSource); |
|
|
|
|
|
// record the line numbers of any text literals within React nodes. |
|
|
// note: this approach only considers text literals passed as children and |
|
|
// not text literals passed as props or by other means |
|
|
|
|
|
const textLiteralLineNumbers = []; |
|
|
|
|
|
tree |
|
|
.find(jscodeshift.JSXElement) |
|
|
.forEach(jsxElement => { |
|
|
|
|
|
let textLiteralChildren = jsxElement.value.children |
|
|
.filter(node => node.type === "JSXText") |
|
|
.filter(node => !new RegExp("^\\s+$").test(node.value, "g")); |
|
|
|
|
|
textLiteralChildren.forEach(node => { |
|
|
textLiteralLineNumbers.push(node.loc.start.line); |
|
|
}); |
|
|
}); |
|
|
|
|
|
textLiteralLineNumbersByFile[filepath] = textLiteralLineNumbers; |
|
|
} catch (error) { |
|
|
console.error(error); |
|
|
} |
|
|
}); |
|
|
|
|
|
const stats2 = { |
|
|
filesWithTextLiterals: textLiteralLineNumbersByFile |
|
|
.entries() |
|
|
.filter(([_filepath, lineNumbers]) => lineNumbers.length !== 0), |
|
|
}; |