@gitborlando/utils
Version:
JavaScript/TypeScript 实用工具集合
315 lines (307 loc) • 11.5 kB
JavaScript
// node_modules/.pnpm/camelcase@8.0.0/node_modules/camelcase/index.js
var UPPERCASE = /[\p{Lu}]/u;
var LOWERCASE = /[\p{Ll}]/u;
var LEADING_CAPITAL = /^[\p{Lu}](?![\p{Lu}])/gu;
var IDENTIFIER = /([\p{Alpha}\p{N}_]|$)/u;
var SEPARATORS = /[_.\- ]+/;
var LEADING_SEPARATORS = new RegExp("^" + SEPARATORS.source);
var SEPARATORS_AND_IDENTIFIER = new RegExp(SEPARATORS.source + IDENTIFIER.source, "gu");
var NUMBERS_AND_IDENTIFIER = new RegExp("\\d+" + IDENTIFIER.source, "gu");
var preserveCamelCase = (string, toLowerCase, toUpperCase, preserveConsecutiveUppercase2) => {
let isLastCharLower = false;
let isLastCharUpper = false;
let isLastLastCharUpper = false;
let isLastLastCharPreserved = false;
for (let index = 0; index < string.length; index++) {
const character = string[index];
isLastLastCharPreserved = index > 2 ? string[index - 3] === "-" : true;
if (isLastCharLower && UPPERCASE.test(character)) {
string = string.slice(0, index) + "-" + string.slice(index);
isLastCharLower = false;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = true;
index++;
} else if (isLastCharUpper && isLastLastCharUpper && LOWERCASE.test(character) && (!isLastLastCharPreserved || preserveConsecutiveUppercase2)) {
string = string.slice(0, index - 1) + "-" + string.slice(index - 1);
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = false;
isLastCharLower = true;
} else {
isLastCharLower = toLowerCase(character) === character && toUpperCase(character) !== character;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = toUpperCase(character) === character && toLowerCase(character) !== character;
}
}
return string;
};
var preserveConsecutiveUppercase = (input, toLowerCase) => {
LEADING_CAPITAL.lastIndex = 0;
return input.replaceAll(LEADING_CAPITAL, (match) => toLowerCase(match));
};
var postProcess = (input, toUpperCase) => {
SEPARATORS_AND_IDENTIFIER.lastIndex = 0;
NUMBERS_AND_IDENTIFIER.lastIndex = 0;
return input.replaceAll(NUMBERS_AND_IDENTIFIER, (match, pattern, offset) => ["_", "-"].includes(input.charAt(offset + match.length)) ? match : toUpperCase(match)).replaceAll(SEPARATORS_AND_IDENTIFIER, (_, identifier) => toUpperCase(identifier));
};
function camelCase(input, options2) {
if (!(typeof input === "string" || Array.isArray(input))) {
throw new TypeError("Expected the input to be `string | string[]`");
}
options2 = {
pascalCase: false,
preserveConsecutiveUppercase: false,
...options2
};
if (Array.isArray(input)) {
input = input.map((x) => x.trim()).filter((x) => x.length).join("-");
} else {
input = input.trim();
}
if (input.length === 0) {
return "";
}
const toLowerCase = options2.locale === false ? (string) => string.toLowerCase() : (string) => string.toLocaleLowerCase(options2.locale);
const toUpperCase = options2.locale === false ? (string) => string.toUpperCase() : (string) => string.toLocaleUpperCase(options2.locale);
if (input.length === 1) {
if (SEPARATORS.test(input)) {
return "";
}
return options2.pascalCase ? toUpperCase(input) : toLowerCase(input);
}
const hasUpperCase = input !== toLowerCase(input);
if (hasUpperCase) {
input = preserveCamelCase(input, toLowerCase, toUpperCase, options2.preserveConsecutiveUppercase);
}
input = input.replace(LEADING_SEPARATORS, "");
input = options2.preserveConsecutiveUppercase ? preserveConsecutiveUppercase(input, toLowerCase) : toLowerCase(input);
if (options2.pascalCase) {
input = toUpperCase(input.charAt(0)) + input.slice(1);
}
return postProcess(input, toUpperCase);
}
// src/script/gen-assets.ts
import fs from "fs";
import path from "path";
var options = {
sourceDir: "",
outputFile: "",
watch: false
};
function getAllFiles(dir, files = []) {
const entries = fs.readdirSync(dir);
for (const entry of entries) {
const fullPath = path.join(dir, entry);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
getAllFiles(fullPath, files);
} else {
files.push(fullPath);
}
}
return files;
}
function pathToObject(filePath) {
const relativePath = path.relative(options.sourceDir, filePath);
const parts = relativePath.split(path.sep);
const fileName = path.basename(parts[parts.length - 1]);
const ext = path.extname(fileName);
const nameWithoutExt = path.basename(fileName, ext);
const camelCase2 = camelCase(nameWithoutExt);
const pathParts = [...parts.slice(0, -1), nameWithoutExt];
const importVarName = camelCase(pathParts.join("-"));
const importPath = "./" + relativePath.replace(/\\/g, "/");
return {
parts: parts.slice(0, -1),
key: camelCase2,
importVarName,
importPath,
originalPath: filePath
};
}
function buildNestedObject(files) {
const result = {};
const imports = [];
for (const file of files) {
const { parts, key, importVarName, importPath } = pathToObject(file);
let current = result;
imports.push({ importVarName, importPath });
for (const part of parts) {
const camelPart = part.replace(
/-([a-z])/g,
(match, letter) => letter.toUpperCase()
);
if (!current[camelPart]) {
current[camelPart] = {};
}
current = current[camelPart];
}
current[key] = importVarName;
}
return { result, imports };
}
function generateTypeScriptCode(obj, indent = 2) {
const spaces = " ".repeat(indent);
let code = "";
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "string") {
code += `${spaces}"${key}": ${value},
`;
} else {
code += `${spaces}"${key}": {
`;
code += generateTypeScriptCode(value, indent + 2);
code += `${spaces}},
`;
}
}
return code;
}
function generateImportStatements(imports) {
return imports.map(
({ importVarName, importPath }) => `import ${importVarName} from '${importPath}';`
).join("\n");
}
function ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
function generateAssetsFile() {
console.log("\u5F00\u59CB\u751F\u6210\u8D44\u6E90\u8DEF\u5F84\u5E38\u91CF...");
const allFiles = getAllFiles(options.sourceDir).filter(
(file) => path.resolve(file) !== path.resolve(options.outputFile)
);
console.log(`\u627E\u5230 ${allFiles.length} \u4E2A\u6587\u4EF6`);
if (allFiles.length === 0) {
console.log("\u6CA1\u6709\u627E\u5230\u8D44\u6E90\u6587\u4EF6");
return;
}
const { result: assetsObject, imports } = buildNestedObject(allFiles);
const importStatements = generateImportStatements(imports);
const tsCode = `// \u81EA\u52A8\u751F\u6210\u7684\u9759\u6001\u8D44\u6E90\u8DEF\u5F84\u5E38\u91CF
${importStatements}
export const Assets = {
${generateTypeScriptCode(assetsObject)}
} as const;
`;
ensureDir(path.dirname(options.outputFile));
fs.writeFileSync(options.outputFile, tsCode, "utf8");
console.log(`\u2705 \u5DF2\u751F\u6210: ${options.outputFile}`);
console.log(`\u5305\u542B ${allFiles.length} \u4E2A\u8D44\u6E90\u8DEF\u5F84`);
}
function watchFiles() {
console.log("\u5F00\u59CB\u76D1\u542C\u6587\u4EF6\u53D8\u5316...");
console.log(`\u76D1\u542C\u76EE\u5F55: ${options.sourceDir}`);
console.log("\u6309 Ctrl+C \u505C\u6B62\u76D1\u542C\n");
const watcher = fs.watch(
options.sourceDir,
{ recursive: true },
(eventType, filename) => {
if (!filename) return;
const outFileName = path.basename(options.outputFile);
if (filename === outFileName) return;
console.log(`
\u68C0\u6D4B\u5230\u6587\u4EF6\u53D8\u5316: ${eventType} - ${filename}`);
if (eventType === "change" || eventType === "rename" || eventType === "unlink") {
setTimeout(() => {
console.log("\u91CD\u65B0\u751F\u6210\u8D44\u6E90\u5E38\u91CF\u6587\u4EF6...");
generateAssetsFile();
}, 100);
}
}
);
watcher.on("error", (error) => {
console.error("\u76D1\u542C\u9519\u8BEF:", error);
});
return watcher;
}
function generateAssets(_options) {
Object.assign(options, _options);
console.log(options.sourceDir, options.outputFile);
if (options.watch) {
const watcher = watchFiles();
process.on("SIGINT", () => {
console.log("\n\u505C\u6B62\u76D1\u542C...");
watcher.close();
process.exit(0);
});
}
generateAssetsFile();
}
// src/script/gen-comp.ts
import { existsSync, mkdirSync, writeFileSync } from "fs";
// node_modules/.pnpm/just-kebab-case@4.2.0/node_modules/just-kebab-case/index.mjs
var stringKebabCase = kebabCase;
var wordSeparators = /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]+/;
var capital_plus_lower = /[A-ZÀ-Ý\u00C0-\u00D6\u00D9-\u00DD][a-zà-ÿ]/g;
var capitals = /[A-ZÀ-Ý\u00C0-\u00D6\u00D9-\u00DD]+/g;
function kebabCase(str) {
str = str.replace(capital_plus_lower, function(match) {
return " " + (match[0].toLowerCase() || match[0]) + match[1];
});
str = str.replace(capitals, function(match) {
return " " + match.toLowerCase();
});
return str.trim().split(wordSeparators).join("-").replace(/^-/, "").replace(/-\s*$/, "");
}
// src/script/gen-comp.ts
import { join, resolve } from "path";
function generateComponent(options2 = {}) {
options2.tsxTemplate || (options2.tsxTemplate = defaultComponentTemplate);
options2.lessTemplate || (options2.lessTemplate = defaultLessTemplate);
options2.kebabCaseName ?? (options2.kebabCaseName = true);
const parentDir = process.argv[2] || process.cwd();
const inputName = pascalCase(process.argv[3]);
const prefix = pascalCase(process.argv[4] || "");
const componentName = prefix ? `${prefix}${inputName}` : inputName;
const fileName = options2.kebabCaseName ? stringKebabCase(inputName) : inputName;
const componentDir = resolve(parentDir, fileName);
if (existsSync(componentDir)) {
console.error(`\u274C \u9519\u8BEF: \u7EC4\u4EF6\u6587\u4EF6\u5939 "${fileName}" \u5DF2\u5B58\u5728`);
process.exit(1);
}
try {
mkdirSync(componentDir, { recursive: true });
console.log(`\u{1F4C1} \u521B\u5EFA\u6587\u4EF6\u5939: ${componentDir}`);
} catch (error) {
console.error("\u274C \u521B\u5EFA\u6587\u4EF6\u5939\u5931\u8D25:");
process.exit(1);
}
const tsxPath = join(componentDir, `index.tsx`);
try {
writeFileSync(tsxPath, options2.tsxTemplate(componentName).trim(), "utf8");
console.log(`\u{1F4C4} \u521B\u5EFA\u6587\u4EF6: ${tsxPath}`);
} catch (error) {
console.error("\u274C \u521B\u5EFA TSX \u6587\u4EF6\u5931\u8D25:");
process.exit(1);
}
const lessPath = join(componentDir, `index.less`);
try {
writeFileSync(lessPath, options2.lessTemplate(componentName).trim(), "utf8");
console.log(`\u{1F3A8} \u521B\u5EFA\u6587\u4EF6: ${lessPath}`);
} catch (error) {
console.error("\u274C \u521B\u5EFA LESS \u6587\u4EF6\u5931\u8D25:");
process.exit(1);
}
console.log("\n\u2705 \u7EC4\u4EF6\u521B\u5EFA\u6210\u529F!");
}
var pascalCase = (name) => {
return camelCase(name, { pascalCase: true });
};
var defaultComponentTemplate = (name) => {
return `import { FC } from 'react'
import './index.less'
interface ${name}Props {}
export const ${name}: FC<${name}Props> = observer(({}) => {
return (
<G className='${stringKebabCase(name)}'></G>
)
})`;
};
var defaultLessTemplate = (name) => {
return `.${stringKebabCase(name)} {}`;
};
export {
generateAssets,
generateComponent
};