UNPKG

@knighttower/utility

Version:

UtilityJs is a utility library that provides a collection of utility functions for various tasks. The library is designed to be easy to use and covers the most common use cases.

232 lines (208 loc) 8.56 kB
#!/usr/bin/env node Object.defineProperty(exports, '__esModule', { value: true }); const fs = require('fs'); const path = require('path'); const glob = require('glob'); const helper = require('../dist/cjs/powerHelper.cjs'); const utils = require('../dist/cjs/Utility.cjs'); const { getFlagValue } = require('./NodeHelpers.cjs'); const workingDir = process.cwd(); /** * Reads a file and returns the names of the exported modules. * @param {string} filePath * @returns {Object} Object containing arrays of named exports and the default export */ function getExports(filePath) { // get the whole file content const content = fs.readFileSync(filePath, 'utf-8'); // Example matches: export const myVar, export function myFunc, export class MyClass // Example matches: export myVar, export myFunc const matchSingleExps = content.match(/export\s+(const|let|var|function|class)\s+(\w+)|export\s+(\w+)/g) || []; // Example matches: export default class MyClass, export default function myFunc, const matchDefClasses = content.match(/export\s+default\s+(class|function)\s*(\b(?!(\{|\())\w+\b)/) || []; // Example matches: export default Name, Name as default const matchDefSingles = content.match( /export\s+default\s+(\b(?!(\{|\(|(class|function)))\w+\b)|(?<=\{[^}]*)\w+\s+as\s+default(?=[^}]*\})/ ) || []; // Example matches: export { myVar, myFunc } const matchAliasesExps = content.match(/export\s*{([^}]+)}/g) || []; //Example matches: module.exports = { myVar, myFunc } const matchModuleExports = helper.getMatchInBetween( content, /module\.exports\s*={/g, '}', true ); const matchModuleExports2 = helper.getMatchInBetween( content, /module\.exports\./g, /(=|;)/, true ); const matchModuleExports3 = (content.match(/module\.exports\s*=\s*(\w+)/g) || []).map( (module) => helper.cleanStr(module, 'module.exports', '=') ); //Example matches: modules.myModule = any const matchExports = (content.match(/modules\.(\w+)\s*=/g) || []).map((module) => helper.cleanStr(module, 'modules.', '=') ); const matchExports2 = (content.match(/(?!(\.))exports\.(\w+)\s*=/g) || []).map((module) => helper.cleanStr(module, 'exports.', '=') ); // Storages const singleExports = []; const defaultExport = utils.emptyOrValue( helper.cleanStr( matchDefClasses[0] || matchDefSingles[0] || '', 'export', 'default', 'function', 'class', /\bas\b/ ) ); const aliasExports = []; let namedExports = []; // ========================================= // --> Process the arrays to clean and pick the export // -------------------------- // Handle single exports [...matchSingleExps, ...matchExports, ...matchExports2].forEach((exp) => { const parts = helper.cleanStr(exp, 'export').match(/\b\w+\b/g); if (parts.length === 1) { singleExports.push(parts[0]); } else if (parts.length === 2) { singleExports.push(parts[1]); } }); // Handle aliases [ ...matchAliasesExps, ...matchModuleExports, ...matchModuleExports2, ...matchModuleExports3, ].forEach((aliasLine) => { helper // cleanup and create an array of aliases .getChunks(helper.cleanStr(aliasLine, 'export', '{', '}')) // exclude default export .filter((chunk) => chunk && !chunk.includes('default')) // iterate to pick the correct alias; .forEach((chunk) => { if (chunk.includes(' as ')) { const alias = helper.getChunks(chunk, ' as '); if (alias[1]) { aliasExports.push(alias[1]); } } else { aliasExports.push(chunk); } }); }); // Merge all named exports and filter namedExports = [...aliasExports, ...singleExports].filter( (name) => name !== 'default' && name !== defaultExport ); return { named: Array.from(new Set(namedExports)), // Remove duplicates default: defaultExport, }; } /** * Generates the content for the index.js file. * @param {Object} allExports - An object containing information about all exports * @returns {string} - The content for the index.js file */ function getEsmContent(allExports) { let imports = ''; let exports = []; for (const [filePath, { named, default: defaultExport }] of Object.entries(allExports)) { const moduleName = path.basename(filePath).replace(/\.js|\.mjs/, ''); const relativePath = path.relative(workingDir, filePath).replace(/\\/g, '/'); const commentSingle = `// Single Modules and Aliases from: ${moduleName}\n`; const commentDefault = `// Default Module from: ${moduleName}\n`; if (named.length > 0) { const namedModules = named.join(', '); imports += commentSingle; imports += `import { ${namedModules} } from './${relativePath}';\n`; exports.push(named); } if (defaultExport) { imports += commentDefault; imports += `import ${defaultExport} from './${relativePath}';\n`; exports.push(defaultExport); } } exports = exports.flat().join(',\n'); return `${imports}\n export { \n ${exports} \n };`; } /** * Generate index content for CommonJS modules. * @param {Object} allExports - An object containing information about all exports. * @return {string} - The generated index content. */ function getCommonJsContent(allExports) { let imports = ''; let exports = []; for (const [filePath, { named, default: defaultExport }] of Object.entries(allExports)) { const moduleName = path.basename(filePath).replace(/\.js|\.cjs/, ''); const relativePath = path.relative(workingDir, filePath).replace(/\\/g, '/'); const commentSingle = `// Single Modules and Aliases from: ${moduleName}\n`; const commentDefault = `// Default Module from: ${moduleName}\n`; if (named.length > 0) { const namedModules = named.join(', '); imports += commentSingle; imports += `const { ${namedModules} } = require('./${relativePath}');\n`; exports.push(named); } if (defaultExport) { imports += commentDefault; imports += `const ${defaultExport} = require('./${relativePath}');\n`; exports.push(defaultExport); } } exports = exports.flat().join(',\n'); return `${imports}\n module.exports = { \n ${exports} \n };`; } /** * Main function to generate the index.js file. * @flags * -dir: The directory to search for modules. Defaults to './src'. * -type: The type of module to generate. Defaults to 'js'. Options: 'js', 'esm', 'cjs'. * -file: A single file to generate an index for. Defaults to false. * -out: The name of the output file. Defaults to 'index.js'. * @returns {void} */ (function generateIndex() { const dir = getFlagValue('dir') ?? './src'; let type = getFlagValue('type') ?? 'js'; type = ['js', 'esm', 'cjs'].includes(type) ? type : 'js'; const ext = type === 'esm' ? 'js' : type; const singleFile = getFlagValue('file') ?? false; const out = getFlagValue('out') ? helper.cleanStr(getFlagValue('out'), '.js', '.mjs', '.cjs', '.ts') : null; const destination = out ? `${out}.${ext}` : `${workingDir}/index.${ext}`; // Synchronously fetch all file paths within a esmDir and its subdirectories // that have a .js or .mjs extension const processFiles = () => { const filePaths = !singleFile ? glob.sync(`${dir}/**/*.{js,mjs,cjs}`) : glob.sync(`${singleFile}`); const allExports = {}; filePaths.forEach((filePath) => { if (!path.basename(filePath).includes('index')) { allExports[filePath] = getExports(filePath); } }); const indexContent = type === 'cjs' ? getCommonJsContent(allExports) : getEsmContent(allExports); fs.writeFileSync(destination, indexContent); console.log(' Generated In:--->', destination); console.log('index generated'); }; processFiles(); })();