Skip to content

Commit

Permalink
refactor: decompose fix.ts
Browse files Browse the repository at this point in the history
closes #146
  • Loading branch information
antongolub committed Dec 29, 2023
1 parent 4289326 commit 161eb10
Show file tree
Hide file tree
Showing 14 changed files with 1,207 additions and 1,069 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
"tslib": "^2.6.2"
},
"devDependencies": {
"@types/fs-extra": "^11.0.2",
"@qiwi/npm-run-all": "^4.1.7",
"@types/fs-extra": "^11.0.2",
"@types/jest": "^29.5.5",
"@types/node": "^20.6.2",
"@types/semver": "^7.5.2",
Expand Down
137 changes: 137 additions & 0 deletions src/main/ts/finder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { dirname, join, resolve } from 'node:path'
import { asArray, globby, readJson, resolveTsConfig } from './util'
import { Options as GlobbyOptions } from 'globby'

export const getTsconfigTargets = (
tsconfig: string | string[],
cwd: string,
): string[] =>
asArray(tsconfig).reduce<string[]>((targets, file) => {
const tsconfigJson = resolveTsConfig(resolve(cwd, file))
const outDir = tsconfigJson?.compilerOptions?.outDir
const module = tsconfigJson?.compilerOptions?.module.toLowerCase?.()

if (outDir && module.startsWith('es')) {
targets.push(outDir)
} else {
console.warn('tsconfig should declare `outDir` and `module` type es6 or above')
}

return targets
}, [])

export const getPatterns = (sources: string[], targets: string[]): string[] =>
sources.length > 0
? sources.map((src) => src.includes('*') ? src : `${src}/**/*.{ts,tsx}`)
: targets.map((target) => target.includes('*') ? target : `${target}/**/*.{js,d.ts}`)

export const getLocalModules = (sources: string[], targets: string[], cwd: string) => globby(
getPatterns(sources, targets),
{
cwd,
onlyFiles: true,
absolute: true,
} as GlobbyOptions)

export const getExternalModules = async (cwd: string): Promise<{cjsModules: string[], esmModules: string[], allPackages: string[] }> => {
const {names, files: esmModules} = await getExternalEsmModules(cwd)
const cjsModules = await globby(
[
'!node_modules/.cache',
'!node_modules/.bin',
'!node_modules/**/node_modules',
...names.map(m => `!node_modules/${m}`),
'node_modules/**/*.(m|c)?js',
],
{
cwd,
onlyFiles: true,
absolute: true,
} as GlobbyOptions,
)

return {
cjsModules,
esmModules,
allPackages: names,
}
}

// https://nodejs.org/api/packages.html
// https://webpack.js.org/guides/package-exports/
type Entry = string | string[] | Record<string, string | string[] | Record<string, string | string[]>>

const getExportsEntries = (exports: string | Entry): [string, string[]][] => {
const entries: [string, Entry][] = Object.entries(exports)
const parseConditional = (e: Entry): string[] => typeof e === 'string' ? [e] : Object.values(e).map(parseConditional).flat(2)

// has subpaths
if (typeof exports !== 'string' && Object.keys(exports).some((k) => k.startsWith('.'))) {
return entries.map(([k, v]) => [k, parseConditional(v)])
}

return [['.', parseConditional(exports)]]
}

const getExternalEsmModules = (cwd: string): Promise<{ names: string[], files: string[] }> =>
globby(['node_modules/*/package.json', 'node_modules/@*/*/package.json'], {
cwd,
onlyFiles: true,
absolute: true,
} as GlobbyOptions).then(async (files: string[]) =>
(await Promise.all(files
.map(async (f: string): Promise<{ name?: string, files?: string[] }> => {
const {name, exports} = await readJson(f)

if (!exports) {
return {name}
}

const _dir = dirname(f)
const exportsEntries = getExportsEntries(exports)

return {
name,
files: (await Promise.all(exportsEntries.map(([key, values]) =>

Promise.all(values.map(async(value) =>
(await globby(value, {cwd: _dir, onlyFiles: true, absolute: false}))
.map(file => join(file)
.replace(
resolvePrefix('.', value),
resolvePrefix(name, key)))
)

)))).flat(2)
}

}))).reduce<{ names: string[], files: string[] }>((m, {name, files: _files}) => {
if (name) {
m.names.push(name)
}

if (_files) {
m.files.push(..._files)
}

return m
}, {names: [], files: []}),
)

const resolvePrefix = (prefix: string, pattern?: string): string => {
if (!pattern) {
return prefix
}

let _pattern = pattern

if (_pattern.includes('*')) {
_pattern = _pattern.slice(0, _pattern.indexOf('*'))

if (_pattern.includes('/')) {
_pattern = _pattern.slice(0, _pattern.lastIndexOf('/'))
}
}

return join(prefix, _pattern)
}
Loading

0 comments on commit 161eb10

Please sign in to comment.