From 2ac3eed1a8e66a2eb5615dd2664887859f148c32 Mon Sep 17 00:00:00 2001 From: Nazmus Sayad <87106526+NazmusSayad@users.noreply.github.com> Date: Fri, 27 Sep 2024 19:15:38 +0600 Subject: [PATCH] update method optimized for optimal reliablity --- package-lock.json | 4 +-- package.json | 4 +-- src/__lab__/index.ts | 2 +- src/scripts/generateOutput.ts | 19 ++++------- src/scripts/getNodeCode.ts | 4 +-- src/scripts/makeOutputFile.ts | 11 +++--- src/scripts/utils.ts | 7 ++++ src/updateImports/helpers.ts | 33 ++++++++++++++++++ src/updateImports/index.ts | 59 +++++++++++--------------------- src/updateImports/node.ts | 51 ++++++++++++++++++++-------- src/updateImports/types.t.ts | 1 - src/updateImports/utils.ts | 63 ----------------------------------- 12 files changed, 116 insertions(+), 142 deletions(-) create mode 100644 src/scripts/utils.ts create mode 100644 src/updateImports/helpers.ts delete mode 100644 src/updateImports/utils.ts diff --git a/package-lock.json b/package-lock.json index c45b715..7ac2089 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npmize", - "version": "1.1.6", + "version": "1.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npmize", - "version": "1.1.6", + "version": "1.1.7", "license": "ISC", "dependencies": { "@babel/parser": "^7.25.6", diff --git a/package.json b/package.json index 9a9e173..7fa3500 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "npmize", - "version": "1.1.7", + "version": "1.1.8", "description": "Let's create an npm package without worrying about anything.", "bin": "./dist/index.js", "scripts": { @@ -8,7 +8,7 @@ "build": "node ./build.cjs", "tsc": "tsc --noEmit --watch", "lab": "run ./src/__lab__/index.ts", - "lab-js": "node --watch ./dist/__lab__/index.js" + "lab-js": "node --watch --watch ./dist/__lab__/index.js" }, "dependencies": { "@babel/parser": "^7.25.6", diff --git a/src/__lab__/index.ts b/src/__lab__/index.ts index c1c5c2e..ef259f5 100644 --- a/src/__lab__/index.ts +++ b/src/__lab__/index.ts @@ -5,5 +5,5 @@ import '../main' // app.start(['init', TEST_TARGET]) // app.start(['dev', TEST_TARGET, '--node']) -app.start(['build', TEST_TARGET]) +app.start(['build', TEST_TARGET, '--node']) // app.start(['build', TEST_TARGET, '--worker']) diff --git a/src/scripts/generateOutput.ts b/src/scripts/generateOutput.ts index 90d720a..d4eff60 100644 --- a/src/scripts/generateOutput.ts +++ b/src/scripts/generateOutput.ts @@ -1,4 +1,3 @@ -import path from 'path' import getNodeCode from './getNodeCode' import updateImports from '../updateImports' import { MakeOutputOptions } from './makeOutputFile' @@ -8,7 +7,7 @@ export default async function ( fileContent: string, options: MakeOutputOptions ) { - const [tempFilePath, newFileContent] = await updateImports( + const updatedContent = await updateImports( options.tempOutDir, filePath, fileContent, @@ -17,15 +16,9 @@ export default async function ( options.tsConfig?.paths ) - const newFilePath = path.join( - options.finalOutDir, - path.relative(options.tempOutDir, tempFilePath) - ) - - const output = - options.pushNodeCode && options.moduleType === 'cjs' - ? getNodeCode(newFilePath, newFileContent) + newFileContent - : newFileContent - - return [newFilePath, output] as const + return options.pushNodeCode && + options.moduleType === 'mjs' && + filePath.endsWith('.js') + ? getNodeCode(updatedContent) + updatedContent + : updatedContent } diff --git a/src/scripts/getNodeCode.ts b/src/scripts/getNodeCode.ts index 022611b..a0377e4 100644 --- a/src/scripts/getNodeCode.ts +++ b/src/scripts/getNodeCode.ts @@ -1,9 +1,7 @@ const varName = '_____VGhpcyBuYW1lIGlzIHVzZWQgdG8gZW5hYmxlIF9fZGlybmFtZSBhbmQgX19maWxlbmFtZSDwn5iK_____' -export default (filePath: string, fileContent: string) => { - if (filePath.endsWith('ts')) return '' - +export default function (fileContent: string) { const isFilenameExist = fileContent.includes('__filename') const isDirnameExist = fileContent.includes('__dirname') if (!isFilenameExist && !isDirnameExist) return '' diff --git a/src/scripts/makeOutputFile.ts b/src/scripts/makeOutputFile.ts index 3830a18..1318184 100644 --- a/src/scripts/makeOutputFile.ts +++ b/src/scripts/makeOutputFile.ts @@ -3,6 +3,7 @@ import path from 'path' import { Worker } from 'worker_threads' import { autoCreateDir } from '../utils/fs' import generateOutput from './generateOutput' +import { getNewFilePath } from './utils' export type MakeOutputOptions = { useWorker: boolean @@ -19,10 +20,12 @@ export type MakeOutputOptions = { export default async function (filePath: string, options: MakeOutputOptions) { const fileContent = fs.readFileSync(filePath, 'utf-8') const generator = options.useWorker ? generateOutputWorker : generateOutput - const [newFilePath, newFileContent] = await generator( - filePath, - fileContent, - options + const newFileContent = await generator(filePath, fileContent, options) + + const relativeFilePath = path.relative(options.tempOutDir, filePath) + const newFilePath = getNewFilePath( + path.join(options.finalOutDir, relativeFilePath), + options.moduleType ) autoCreateDir(path.dirname(newFilePath)) diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts new file mode 100644 index 0000000..7e4b9b7 --- /dev/null +++ b/src/scripts/utils.ts @@ -0,0 +1,7 @@ +export function getNewFilePath(filePath: string, type: 'cjs' | 'mjs') { + const prefix = type[0] + + return filePath.replace(/\.(js|ts)$/, (match) => { + return match.replace(/(js|ts)/i, (type) => prefix + type) + }) +} diff --git a/src/updateImports/helpers.ts b/src/updateImports/helpers.ts new file mode 100644 index 0000000..b103977 --- /dev/null +++ b/src/updateImports/helpers.ts @@ -0,0 +1,33 @@ +import * as fs from 'fs' +import { NodeType } from './types.t' + +export function getUpdatedData(fileData: any, found: NodeType[], cb: any) { + const newEntries: NodeType[] = [ + { start: 0, end: 0, value: '', filename: '' }, + ...found.sort((a, b) => a.start - b.start), + ] + + const chunks = newEntries.map((node, i, arr) => { + const nextNode = arr[i + 1] + const nodeEnd = node.end + const nextNodeEnd = nextNode ? nextNode.start : Infinity + const str = fileData.slice(nodeEnd, nextNodeEnd) + + if (!nextNode) return str + return [str, `"${cb(nextNode) ?? nextNode.value}"`] + }) + + return chunks.flat().join('') +} + +export function resolveJsFilePath(target: string) { + function isExists(target: string) { + if (fs.existsSync(target) && fs.statSync(target).isFile()) return target + } + + return ( + isExists(target) || + isExists(target + '.js') || + isExists(target + '/index.js') + ) +} diff --git a/src/updateImports/index.ts b/src/updateImports/index.ts index 23d85e0..dbf80b1 100644 --- a/src/updateImports/index.ts +++ b/src/updateImports/index.ts @@ -1,11 +1,9 @@ import path from 'path' -import * as utils from './utils' import { NodeType } from './types.t' import * as babel from '@babel/parser' -import { Worker } from 'worker_threads' -import { Statement } from '@babel/types' import { getImports, getRequires } from './node' import { resolveImportPath } from '../scripts/tsconfig' +import { getUpdatedData, resolveJsFilePath } from './helpers' export default async function ( cwd: string, @@ -15,26 +13,26 @@ export default async function ( tsconfigBaseUrl: string | undefined, tsconfigPaths: Record | undefined ) { - const ext = '.' + moduleType - const fileDirPath = path.dirname(filePath) - + const newExt = '.' + moduleType + const isModuleJs = filePath.endsWith('.ts') || moduleType === 'mjs' const parsedBody = babel.parse(compiledText, { sourceType: 'module', plugins: ['typescript'], sourceFilename: filePath, }).program.body - const isModuleJs = filePath.endsWith('.ts') || moduleType === 'mjs' const foundImportPaths = isModuleJs ? getImports(parsedBody) : getRequires(parsedBody) function updateRelativeImports(node: NodeType) { - const shortPath = node.value.replace(/\.js$/i, '') - const fullPath = path.join(fileDirPath, node.value) + const fileDir = path.dirname(filePath) + const resolvedPath = resolveJsFilePath(path.join(fileDir, node.value)) + if (!resolvedPath) return - const isExists = utils.isFileExists(fullPath) - return isExists ? shortPath + ext : shortPath + '/index' + ext + const noExtPath = resolvedPath.replace(/\.\w+$/i, newExt) + const relativePath = path.relative(fileDir, noExtPath).replace(/\\/g, '/') + return relativePath.startsWith('.') ? relativePath : './' + relativePath } function updateResolvedPath(baseUrl: string, resolvedPath: string) { @@ -49,7 +47,7 @@ export default async function ( ) const shortestPathWithExt = - path.dirname(shortPath) + '/' + path.parse(shortPath).name + ext + path.dirname(shortPath) + '/' + path.parse(shortPath).name + newExt const posixSortPathWithExt = path .normalize(shortestPathWithExt) @@ -59,35 +57,18 @@ export default async function ( return './' + posixSortPathWithExt } - const updatedData = utils.getUpdatedData( - compiledText, - foundImportPaths, - (node: NodeType) => { - if (node.value.startsWith('.')) { - return updateRelativeImports(node) - } - - if (!tsconfigBaseUrl || !tsconfigPaths) return - const resolvedPath = resolveImportPath( - tsconfigBaseUrl, - node.value, - tsconfigPaths - ) - - return resolvedPath && updateResolvedPath(tsconfigBaseUrl, resolvedPath) + return getUpdatedData(compiledText, foundImportPaths, (node: NodeType) => { + if (node.value.startsWith('.')) { + return updateRelativeImports(node) } - ) - const newFilePath = utils.getNewFilePath(filePath, moduleType) - return [newFilePath, updatedData] as const -} + if (!tsconfigBaseUrl || !tsconfigPaths) return + const resolvedPath = resolveImportPath( + tsconfigBaseUrl, + node.value, + tsconfigPaths + ) -function getRequiredStatements(type: 'import' | 'require', body: Statement[]) { - return new Promise((resolve) => { - const worker = new Worker(path.join(__dirname, './nodeWorker.js')) - worker.postMessage({ type, body }) - worker.on('message', (message) => { - resolve(message) - }) + return resolvedPath && updateResolvedPath(tsconfigBaseUrl, resolvedPath) }) } diff --git a/src/updateImports/node.ts b/src/updateImports/node.ts index a8fb208..93a3efb 100644 --- a/src/updateImports/node.ts +++ b/src/updateImports/node.ts @@ -1,28 +1,51 @@ +import { NodeType } from './types.t' import { Statement } from '@babel/types' -import { findNestedItems, isOkString, parseString } from './utils' -const TSImportType = (parsed: Statement[]) => { - return findNestedItems(parsed, 'type', 'TSImportType') +function parseString(str: any): NodeType { + return { + start: str.start, + end: str.end, + value: str.value, + filename: str.loc.filename, + } +} + +const isOkString = (node: any) => { + return node && node.type === 'StringLiteral' +} + +function findNestedItems(entireObj: Statement[], valToFind: unknown) { + const foundObj: any[] = [] + JSON.stringify(entireObj, (_, nestedValue) => { + const found = nestedValue && nestedValue.type === valToFind + found && foundObj.push(nestedValue) + return nestedValue + }) + return foundObj +} + +function TSImportType(parsed: Statement[]) { + return findNestedItems(parsed, 'TSImportType') .filter((node) => isOkString(node.argument)) .map((node) => parseString(node.argument)) } -const ImportDeclaration_ExportNamedDeclaration_ExportAllDeclaration = ( +function ImportDeclaration_ExportNamedDeclaration_ExportAllDeclaration( parsed: Statement[] -) => { +) { return [ - findNestedItems(parsed, 'type', 'ImportDeclaration'), - findNestedItems(parsed, 'type', 'ExportDeclaration'), - findNestedItems(parsed, 'type', 'ExportNamedDeclaration'), - findNestedItems(parsed, 'type', 'ExportAllDeclaration'), + findNestedItems(parsed, 'ImportDeclaration'), + findNestedItems(parsed, 'ExportDeclaration'), + findNestedItems(parsed, 'ExportNamedDeclaration'), + findNestedItems(parsed, 'ExportAllDeclaration'), ] .flat() .filter((node) => isOkString(node.source)) .map((node) => parseString(node.source)) } -const CallExpressionImport = (parsed: Statement[]) => { - return findNestedItems(parsed, 'type', 'CallExpression') +function CallExpressionImport(parsed: Statement[]) { + return findNestedItems(parsed, 'CallExpression') .filter( (node) => node && @@ -33,8 +56,8 @@ const CallExpressionImport = (parsed: Statement[]) => { .map((node) => parseString(node.arguments[0])) } -const CallExpressionRequire = (parsed: Statement[]) => { - return findNestedItems(parsed, 'type', 'CallExpression') +function CallExpressionRequire(parsed: Statement[]) { + return findNestedItems(parsed, 'CallExpression') .filter( (node) => node && @@ -48,8 +71,8 @@ const CallExpressionRequire = (parsed: Statement[]) => { export function getImports(parsed: Statement[]) { return [ - ...CallExpressionImport(parsed), ...TSImportType(parsed), + ...CallExpressionImport(parsed), ...ImportDeclaration_ExportNamedDeclaration_ExportAllDeclaration(parsed), ] } diff --git a/src/updateImports/types.t.ts b/src/updateImports/types.t.ts index 6a8c7f5..bfd8f9b 100644 --- a/src/updateImports/types.t.ts +++ b/src/updateImports/types.t.ts @@ -2,6 +2,5 @@ export type NodeType = { start: number end: number value: string - rawValue: string filename: string } diff --git a/src/updateImports/utils.ts b/src/updateImports/utils.ts deleted file mode 100644 index 8d833b1..0000000 --- a/src/updateImports/utils.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as fs from 'fs' -import { NodeType } from './types.t' - -export const getUpdatedData = (fileData: any, found: any[], cb: any) => { - const newEntries = [ - { start: 0, end: 0, value: '', rawValue: '', filename: '' }, - ...found.sort((a, b) => a.start - b.start), - ] - - const chunks = newEntries.map((node, i, arr) => { - const nextNode = arr[i + 1] - const nodeEnd = node.end - const nextNodeEnd = nextNode ? nextNode.start : Infinity - const str = fileData.slice(nodeEnd, nextNodeEnd) - - if (!nextNode) return str - return [str, `"${cb(nextNode) ?? nextNode.value}"`] - }) - - return chunks.flat().join('') -} - -export const isOkString = (node: any) => { - return node && node.type === 'StringLiteral' -} - -export const parseString = (str: any): NodeType => ({ - start: str.start, - end: str.end, - value: str.value, - rawValue: str.extra.raw, - filename: str.loc.filename, -}) - -export const isFileExists = ( target: string) => { - return ( - (fs.existsSync(target) && fs.statSync(target).isFile()) || - (fs.existsSync(target + '.js') && fs.statSync(target + '.js').isFile()) || - (fs.existsSync(target + '.ts') && fs.statSync(target + '.ts').isFile()) - ) -} - -export function getNewFilePath(filePath: string, type: 'cjs' | 'mjs') { - const prefix = type[0] - - return filePath.replace(/\.(js|ts)$/, (match) => { - return match.replace(/(js|ts)/i, (type) => prefix + type) - }) -} - -export const findNestedItems = ( - entireObj: any, - keyToFind: string, - valToFind: unknown -) => { - const foundObj: any[] = [] - JSON.stringify(entireObj, (_, nestedValue) => { - const found = nestedValue && nestedValue[keyToFind] === valToFind - found && foundObj.push(nestedValue) - return nestedValue - }) - return foundObj -}