Last active
June 12, 2020 22:19
-
-
Save ZempTime/e3241a66eac8f10228f484b3d6ee4820 to your computer and use it in GitHub Desktop.
Chameleon Conversion Script - place in root, then run with default vscode node launcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require("fs"); | |
const path = require("path"); | |
/** | |
for each package | |
Convert src/* kebab-case to ClassCase | |
Look inside, remove any customElements.define usage | |
for each camelCase name not containing style or .d.ts or Index.js - | |
write a kebab-cased export that defines custom element | |
for each camelCase name not containing Index.js | |
export in root-level index.js | |
update test imports to refer to newly written customElement definitions | |
*/ | |
const convert = async (packageDir) => { | |
const packages = await fs.readdirSync(packageDir); | |
const conversions = Promise.all( | |
packages.map((name) => convertPackage(packageDir, name)) | |
); | |
await conversions; | |
console.log("converted"); | |
}; | |
const convertPackage = async (packageDir, packageName) => { | |
const srcPath = path.join(packageDir, packageName, "src"); | |
if (!fs.existsSync(srcPath)) { | |
return; | |
} | |
// convert to CamelCase | |
const kebabs = fs.readdirSync(srcPath); | |
await convertDirToCamelCase(srcPath, kebabs); | |
const filenames = fs.readdirSync(srcPath); | |
// remove CustomElements definitions | |
await removeCustomElementDeclarations(srcPath, filenames); | |
// for each camelCase name not containing style or .d.ts - | |
// export in index.js | |
// create customElements def at root level | |
const customElementClasses = filenames | |
.filter((name) => !name.includes("Style")) | |
.filter((name) => !name.includes("Index")) | |
.filter((name) => !name.includes(".d.ts")); | |
await writeCustomElementImports(srcPath, customElementClasses); | |
const exportableClassFiles = filenames | |
.filter((name) => !name.includes(".d.ts")) | |
.filter((name) => !name.includes("Index")); | |
await writeClassExports(srcPath, exportableClassFiles); | |
// update test imports to pull in from customElements.define imports | |
// replaces ../src with import from relevant packages/${package}/index.js | |
await updateTestImports(srcPath, exportableClassFiles, customElementClasses); | |
}; | |
const convertDirToCamelCase = async (dirPath, kebabs) => { | |
const renames = kebabs.map(async (kebabedName) => { | |
const newName = toCamelCase(kebabedName); | |
const oldPath = path.join(dirPath, kebabedName); | |
const newPath = path.join(dirPath, newName); | |
// console.log(`renaming ${oldPath} to ${newPath}`); | |
fs.renameSync(oldPath, newPath); | |
}); | |
await Promise.all(renames); | |
}; | |
// https://stackoverflow.com/questions/57556471/convert-kebab-case-to-camelcase-javascript | |
const toCamelCase = (str) => { | |
let arr = str.split("-"); | |
let capital = arr.map((item, index) => | |
index ? item.charAt(0).toUpperCase() + item.slice(1).toLowerCase() : item | |
); | |
// ^-- change here. | |
let capitalString = capital.join(""); | |
return capitalString.replace(/^\w/, (c) => c.toUpperCase()); | |
}; | |
const removeCustomElementDeclarations = async (dirPath, filenames) => { | |
const removals = filenames.map(async (filename) => { | |
const filepath = path.join(dirPath, filename); | |
await fs.readFile(filepath, "utf8", (err, data) => { | |
if (err) throw err; | |
const filteredFile = data | |
.split("\n") | |
.filter((line) => !line.includes("window.customElements")) | |
.join("\n"); | |
fs.writeFileSync(filepath, filteredFile, "utf8"); | |
}); | |
}); | |
await Promise.all(removals); | |
}; | |
// https://github.com/30-seconds/30-seconds-of-code/blob/master/snippets/toKebabCase.md | |
const toKebabCase = (str) => | |
str && | |
str | |
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g) | |
.map((x) => x.toLowerCase()) | |
.join("-"); | |
const writeCustomElementImports = async (srcPath, filenames) => { | |
const packagePath = `${srcPath}`.replace("/src", ""); | |
const customElementDefinitionsToWrite = filenames.map(async (camelName) => { | |
const className = path.basename(camelName).split(".")[0]; | |
const kebabName = toKebabCase(className); | |
const code = `import { ${className} } from './src/${camelName}'; | |
customElements.define('${kebabName}', ${className});`; | |
const customElementDefinitionPath = path.join(packagePath, kebabName); | |
fs.writeFileSync(`${customElementDefinitionPath}.js`, code, "utf8"); | |
}); | |
await Promise.all(customElementDefinitionsToWrite); | |
}; | |
const writeClassExports = async (srcPath, filenames) => { | |
const packagePath = `${srcPath}`.replace("/src", ""); | |
const code = filenames | |
.map((filename) => { | |
const className = path.basename(filename).split(".")[0]; | |
return `export { ${className} } from "./src/${className}.js";`; | |
}) | |
.join("\n"); | |
const indexPath = path.join(packagePath, "index.js"); | |
fs.writeFileSync(indexPath, code, "utf8"); | |
}; | |
const updateTestImports = async ( | |
srcPath, | |
classesToImport, | |
customElementsToImport | |
) => { | |
const packagePath = `${srcPath}`.replace("/src", ""); | |
const testPath = path.join(packagePath, "__tests__"); | |
const testFiles = fs.readdirSync(testPath); | |
const updates = testFiles.map(async (filename) => { | |
const filepath = path.join(testPath, filename); | |
await fs.readFile(filepath, "utf8", (err, data) => { | |
if (err) throw err; | |
const classNames = classesToImport.map((filename) => { | |
const withoutJs = `${filename}`.replace(".js", ""); | |
return withoutJs; | |
}); | |
const localClassImports = `import {${classNames.join( | |
", " | |
)}} from "../index.js\n`; | |
const customElementClasses = customElementsToImport.map((filename) => { | |
const withoutJs = `${filename}`.replace(".js", ""); | |
return withoutJs; | |
}); | |
const customElementDefinitionImports = customElementClasses | |
.map((camelName) => { | |
return `import "../${toKebabCase(camelName)}.js";\n`; | |
}) | |
.join(""); | |
const withoutPreviousImports = data | |
.split("\n") | |
.filter((line) => !line.includes("../src")) | |
.join("\n"); | |
const updatedTestFile = [ | |
localClassImports, | |
customElementDefinitionImports, | |
withoutPreviousImports, | |
].join(""); | |
debugger; | |
fs.writeFileSync(filepath, updatedTestFile, "utf8"); | |
}); | |
}); | |
await Promise.all(updates); | |
}; | |
convert("./packages"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment