From adc833929d89177929de32c5286263e1e57ccf58 Mon Sep 17 00:00:00 2001 From: Zorin Date: Mon, 21 Mar 2022 00:32:22 +0800 Subject: [PATCH] chore: utils --- src/core/utils.ts | 98 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/src/core/utils.ts b/src/core/utils.ts index b49e6c1..4c5a1d3 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -1,8 +1,12 @@ import fg from 'fast-glob'; -import { dirname, join } from 'path'; +import { existsSync, readFileSync } from 'fs'; +import { resolveModule } from 'local-pkg'; +import { dirname, extname, join } from 'path'; import { Alias, AliasOptions } from 'vite'; import { IImport } from './ast'; +type Pkg = Partial>; + /** * Source: https://github.com/rollup/plugins/blob/master/packages/alias/src/index.ts */ @@ -14,16 +18,63 @@ export function matches(pattern: string | RegExp, importee: string) { if (importee === pattern) return true; const importeeStartsWithKey = importee.indexOf(pattern) === 0; - const importeeHasSlashAfterKey = importee.substring(pattern.length)[0] === '/'; + const importeeHasSlashAfterKey = importee.slice(pattern.length)[0] === '/'; return importeeStartsWithKey && importeeHasSlashAfterKey; } +// https://github.com/antfu/local-pkg/blob/main/index.mjs +function searchPackageJSON(dir: string): string | undefined { + let packageJsonPath; + while (true) { + if (!dir) return; + const newDir = dirname(dir); + if (newDir === dir) return; + // eslint-disable-next-line no-param-reassign + dir = newDir; + packageJsonPath = join(dir, 'package.json'); + if (existsSync(packageJsonPath)) break; + } + + return packageJsonPath; +} + export function resolvePath(path: string, from: string, aliases: ((AliasOptions | undefined) & Alias[]) | undefined) { const matchedEntry = aliases?.find((entry) => matches(entry.find, path)); + // Path which is using aliases. e.g. '~/types' if (matchedEntry) return path.replace(matchedEntry.find, matchedEntry.replacement); - return join(dirname(from), path); + const resolved_path = resolveModule(path); + + // Not a module. e.g. '../types' + if (!resolved_path) { + return join(dirname(from), path); + } + + // Result is a typescript file. e.g. 'vue/macros-global.d.ts' + if (extname(resolved_path) === 'ts') { + return resolved_path; + } + // Not a typescript file, find declaration file + // The only situation is that the types are imported from the main entry. e.g. 'vue' -> 'vue/dist/vue.d.ts' + else { + const packageJsonPath = searchPackageJSON(resolved_path); + + if (!packageJsonPath) { + return; + } + + const { types, typings } = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as Pkg; + + let result: string | undefined; + + try { + // @ts-ignore + result = join(dirname(packageJsonPath), types || typings); + } catch {} + + return result; + } } export async function resolveModulePath( @@ -31,15 +82,17 @@ export async function resolveModulePath( from: string, aliases: ((AliasOptions | undefined) & Alias[]) | undefined, ) { - const maybePath = resolvePath(path, from, aliases); - const files = await fg( - [ - `${maybePath.replace(/\\/g, '/')}`, - `${maybePath.replace(/\\/g, '/')}*.+(ts|d.ts)`, - `${maybePath.replace(/\\/g, '/')}*/index.+(ts|d.ts)`, - ], - { onlyFiles: true }, - ); + const maybePath = resolvePath(path, from, aliases)?.replace(/\\/g, '/'); + + if (!maybePath) { + return null; + } + + // console.log('MaybePath', maybePath.replace(/\\/g, '/')); + + const files = await fg([`${maybePath}`, `${maybePath}*.+(ts|d.ts)`, `${maybePath}*/index.+(ts|d.ts)`], { + onlyFiles: true, + }); if (files.length > 0) return files[0]; @@ -58,9 +111,9 @@ export function groupImports(imports: IImport[]) { }, {}); } -export function intersect(a: Array, b: Array) { +export function intersect(a: Array, b: Array) { const setB = new Set(b); - return [...new Set(a)].filter((x) => setB.has(x)); + return [...new Set(a)].filter((x) => setB.has(x)) as R[]; } export interface Replacement { @@ -71,20 +124,21 @@ export interface Replacement { /** * Replace all items at specified indexes while keeping indexes relative during replacements. + * TODO: Still needs to be improved */ -export function replaceAtIndexes(source: string, replacements: Replacement[]) { +export function replaceAtIndexes(source: string, replacements: Replacement[]): string { + let result = source; let offset = 0; for (const node of replacements) { if (node.empty) { - // eslint-disable-next-line no-param-reassign - source = source.slice(0, node.start + offset) + source.slice(node.end + offset); + result = result.slice(0, node.start + offset) + result.slice(node.end + offset); offset -= node.end - node.start; } } - return source; + return result; } export function getInterfaceCode(source: string): string | false { @@ -110,3 +164,11 @@ export function mergeInterfaceCode(source: string): string | false { return result; } + +/** + * Remove '\n' in the end of file + * TODO: Still needs to be improved + */ +export function removeAdditionalEscapeChar(source: string): string { + return source.slice(0, source.length - 1); +}