UNPKG

@gitborlando/utils

Version:

JavaScript/TypeScript 实用工具集合

315 lines (307 loc) 11.5 kB
// 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 };