From 1b5e278ea8f2520c9241b075f771197663dfb4b5 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Mon, 23 Dec 2024 07:28:50 +0900 Subject: [PATCH] feat: cache all source files and set up unique IDs for later dedup purposes --- .../package-files/jsconfig-json-file.ts | 19 ++--- .../package-files/json-source-file.ts | 25 +------ .../package-files/package-json-file.ts | 22 +----- .../check-parser/package-files/resolver.ts | 72 +++++++++++++++---- .../check-parser/package-files/source-file.ts | 23 +++--- .../package-files/tsconfig-json-file.ts | 22 +----- 6 files changed, 82 insertions(+), 101 deletions(-) diff --git a/packages/cli/src/services/check-parser/package-files/jsconfig-json-file.ts b/packages/cli/src/services/check-parser/package-files/jsconfig-json-file.ts index d4982c71..95b7b49b 100644 --- a/packages/cli/src/services/check-parser/package-files/jsconfig-json-file.ts +++ b/packages/cli/src/services/check-parser/package-files/jsconfig-json-file.ts @@ -1,6 +1,6 @@ import path from 'node:path' -import { TSConfigFile, Options, Schema } from './tsconfig-json-file' +import { TSConfigFile, Schema } from './tsconfig-json-file' import { JsonSourceFile } from './json-source-file' /** @@ -14,6 +14,9 @@ import { JsonSourceFile } from './json-source-file' export class JSConfigFile extends TSConfigFile { static FILENAME = 'jsconfig.json' + static #id = 0 + readonly id = ++JSConfigFile.#id + static filePath (dirPath: string) { return path.join(dirPath, JSConfigFile.FILENAME) } @@ -21,18 +24,4 @@ export class JSConfigFile extends TSConfigFile { static loadFromJsonSourceFile (jsonFile: JsonSourceFile): JSConfigFile | undefined { return new JSConfigFile(jsonFile) } - - static loadFromFilePath (filePath: string, options?: Options): JSConfigFile | undefined { - const { jsonSourceFileLoader } = { - jsonSourceFileLoader: JsonSourceFile.loadFromFilePath, - ...options, - } - - const jsonFile = jsonSourceFileLoader(filePath) - if (jsonFile === undefined) { - return - } - - return new JSConfigFile(jsonFile) - } } diff --git a/packages/cli/src/services/check-parser/package-files/json-source-file.ts b/packages/cli/src/services/check-parser/package-files/json-source-file.ts index 51444133..6dd5a350 100644 --- a/packages/cli/src/services/check-parser/package-files/json-source-file.ts +++ b/packages/cli/src/services/check-parser/package-files/json-source-file.ts @@ -1,11 +1,9 @@ import { SourceFile } from './source-file' -import type { LoadFile } from './loader' - -export type Options = { - sourceFileLoader?: LoadFile, -} export class JsonSourceFile { + static #id = 0 + readonly id = ++JsonSourceFile.#id + sourceFile: SourceFile data: Schema @@ -26,21 +24,4 @@ export class JsonSourceFile { } catch (err: any) { } } - - static loadFromFilePath ( - filePath: string, - options?: Options, - ): JsonSourceFile | undefined { - const { sourceFileLoader } = { - sourceFileLoader: SourceFile.loadFromFilePath, - ...options, - } - - const sourceFile = sourceFileLoader(filePath) - if (sourceFile === undefined) { - return - } - - return JsonSourceFile.loadFromSourceFile(sourceFile) - } } diff --git a/packages/cli/src/services/check-parser/package-files/package-json-file.ts b/packages/cli/src/services/check-parser/package-files/package-json-file.ts index 24e694d7..e039ff5d 100644 --- a/packages/cli/src/services/check-parser/package-files/package-json-file.ts +++ b/packages/cli/src/services/check-parser/package-files/package-json-file.ts @@ -1,7 +1,6 @@ import path from 'node:path' import { JsonSourceFile } from './json-source-file' -import type { LoadFile } from './loader' type ExportCondition = 'node-addons' | 'node' | 'import' | 'require' | 'module-sync' | 'default' @@ -11,13 +10,12 @@ type Schema = { exports?: string | string[] | Record | Record> } -export type Options = { - jsonSourceFileLoader?: LoadFile>, -} - export class PackageJsonFile { static FILENAME = 'package.json' + static #id = 0 + readonly id = ++PackageJsonFile.#id + jsonFile: JsonSourceFile basePath: string mainPaths: string[] @@ -41,20 +39,6 @@ export class PackageJsonFile { return new PackageJsonFile(jsonFile) } - static loadFromFilePath (filePath: string, options?: Options): PackageJsonFile | undefined { - const { jsonSourceFileLoader } = { - jsonSourceFileLoader: JsonSourceFile.loadFromFilePath, - ...options, - } - - const jsonFile = jsonSourceFileLoader(filePath) - if (jsonFile === undefined) { - return - } - - return new PackageJsonFile(jsonFile) - } - static filePath (dirPath: string) { return path.join(dirPath, PackageJsonFile.FILENAME) } diff --git a/packages/cli/src/services/check-parser/package-files/resolver.ts b/packages/cli/src/services/check-parser/package-files/resolver.ts index a6a02236..418a7d39 100644 --- a/packages/cli/src/services/check-parser/package-files/resolver.ts +++ b/packages/cli/src/services/check-parser/package-files/resolver.ts @@ -7,12 +7,56 @@ import { PackageJsonFile } from './package-json-file' import { TSConfigFile } from './tsconfig-json-file' import { JSConfigFile } from './jsconfig-json-file' import { isLocalPath, PathResult } from './paths' -import { FileLoader } from './loader' +import { FileLoader, LoadFile } from './loader' +import { JsonSourceFile } from './json-source-file' class PackageFilesCache { - packageJsonCache = new FileLoader(PackageJsonFile.loadFromFilePath) - tsconfigJsonCache = new FileLoader(TSConfigFile.loadFromFilePath) - jsconfigJsonCache = new FileLoader(JSConfigFile.loadFromFilePath) + #sourceFileCache = new FileLoader(SourceFile.loadFromFilePath) + + #jsonFileLoader (load: (jsonFile: JsonSourceFile) => T | undefined): LoadFile { + return filePath => { + const sourceFile = this.#sourceFileCache.load(filePath) + if (sourceFile === undefined) { + return + } + + const jsonFile = JsonSourceFile.loadFromSourceFile(sourceFile) + if (jsonFile === undefined) { + return + } + + return load(jsonFile) + } + } + + #packageJsonCache = new FileLoader(this.#jsonFileLoader(PackageJsonFile.loadFromJsonSourceFile)) + #tsconfigJsonCache = new FileLoader(this.#jsonFileLoader(TSConfigFile.loadFromJsonSourceFile)) + #jsconfigJsonCache = new FileLoader(this.#jsonFileLoader(JSConfigFile.loadFromJsonSourceFile)) + + sourceFile (filePath: string, suffixes?: string[]) { + for (const suffix of ['', ...suffixes ?? []]) { + const suffixFilePath = filePath + suffix + + const sourceFile = this.#sourceFileCache.load(suffixFilePath) + if (sourceFile === undefined) { + continue + } + + return sourceFile + } + } + + packageJson (filePath: string) { + return this.#packageJsonCache.load(filePath) + } + + tsconfigJson (filePath: string) { + return this.#tsconfigJsonCache.load(filePath) + } + + jsconfigJson (filePath: string) { + return this.#jsconfigJsonCache.load(filePath) + } } class PackageFiles { @@ -22,15 +66,15 @@ class PackageFiles { satisfyFromDirPath (dirPath: string, cache: PackageFilesCache): boolean { if (this.packageJson === undefined) { - this.packageJson = cache.packageJsonCache.load(PackageJsonFile.filePath(dirPath)) + this.packageJson = cache.packageJson(PackageJsonFile.filePath(dirPath)) } if (this.tsconfigJson === undefined && this.jsconfigJson === undefined) { - this.tsconfigJson = cache.tsconfigJsonCache.load(TSConfigFile.filePath(dirPath)) + this.tsconfigJson = cache.tsconfigJson(TSConfigFile.filePath(dirPath)) } if (this.jsconfigJson === undefined && this.tsconfigJson === undefined) { - this.jsconfigJson = cache.jsconfigJsonCache.load(JSConfigFile.filePath(dirPath)) + this.jsconfigJson = cache.jsconfigJson(JSConfigFile.filePath(dirPath)) } return this.satisfied @@ -143,7 +187,7 @@ export class PackageFilesResolver { private resolveSourceFile (sourceFile: SourceFile): SourceFile[] { if (sourceFile.meta.basename === PackageJsonFile.FILENAME) { - const packageJson = this.cache.packageJsonCache.load(sourceFile.meta.filePath) + const packageJson = this.cache.packageJson(sourceFile.meta.filePath) if (packageJson === undefined) { // This should never happen unless the package.json is invalid or // something. @@ -166,7 +210,7 @@ export class PackageFilesResolver { const candidatePaths = configJson.collectLookupPaths(mainPath) for (const candidatePath of candidatePaths) { - const mainSourceFile = SourceFile.loadFromFilePath(candidatePath) + const mainSourceFile = this.cache.sourceFile(candidatePath) if (mainSourceFile === undefined) { continue } @@ -177,7 +221,7 @@ export class PackageFilesResolver { } } - const mainSourceFile = SourceFile.loadFromFilePath(mainPath) + const mainSourceFile = this.cache.sourceFile(mainPath) if (mainSourceFile === undefined) { continue } @@ -211,7 +255,7 @@ export class PackageFilesResolver { for (const importPath of dependencies) { if (isLocalPath(importPath)) { const relativeDepPath = path.resolve(dirname, importPath) - const sourceFile = SourceFile.loadFromFilePath(relativeDepPath, suffixes) + const sourceFile = this.cache.sourceFile(relativeDepPath, suffixes) if (sourceFile !== undefined) { const resolvedFiles = this.resolveSourceFile(sourceFile) let found = false @@ -245,7 +289,7 @@ export class PackageFilesResolver { let found = false for (const { source, target } of resolvedPaths) { const relativePath = path.resolve(configJson.basePath, target.path) - const sourceFile = SourceFile.loadFromFilePath(relativePath, suffixes) + const sourceFile = this.cache.sourceFile(relativePath, suffixes) if (sourceFile !== undefined) { const resolvedFiles = this.resolveSourceFile(sourceFile) for (const resolvedFile of resolvedFiles) { @@ -282,7 +326,7 @@ export class PackageFilesResolver { if (configJson.baseUrl !== undefined) { const relativePath = path.resolve(configJson.basePath, configJson.baseUrl, importPath) - const sourceFile = SourceFile.loadFromFilePath(relativePath, suffixes) + const sourceFile = this.cache.sourceFile(relativePath, suffixes) if (sourceFile !== undefined) { const resolvedFiles = this.resolveSourceFile(sourceFile) let found = false @@ -312,7 +356,7 @@ export class PackageFilesResolver { if (packageJson !== undefined) { if (packageJson.supportsPackageRelativePaths()) { const relativePath = path.resolve(packageJson.basePath, importPath) - const sourceFile = SourceFile.loadFromFilePath(relativePath, suffixes) + const sourceFile = this.cache.sourceFile(relativePath, suffixes) if (sourceFile !== undefined) { const resolvedFiles = this.resolveSourceFile(sourceFile) let found = false diff --git a/packages/cli/src/services/check-parser/package-files/source-file.ts b/packages/cli/src/services/check-parser/package-files/source-file.ts index 1d3f6df8..d04bce2d 100644 --- a/packages/cli/src/services/check-parser/package-files/source-file.ts +++ b/packages/cli/src/services/check-parser/package-files/source-file.ts @@ -22,6 +22,9 @@ export class FileMeta { } export class SourceFile { + static #id = 0 + readonly id = ++SourceFile.#id + contents: string meta: FileMeta @@ -30,20 +33,16 @@ export class SourceFile { this.contents = contents } - static loadFromFilePath (filePath: string, suffixes?: string[]): SourceFile | undefined { - for (const suffix of ['', ...suffixes ?? []]) { - try { - const suffixFilePath = filePath + suffix - - const contents = fs.readFileSync(suffixFilePath, { - encoding: 'utf8', - }) + static loadFromFilePath (filePath: string): SourceFile | undefined { + try { + const contents = fs.readFileSync(filePath, { + encoding: 'utf8', + }) - const meta = FileMeta.fromFilePath(suffixFilePath) + const meta = FileMeta.fromFilePath(filePath) - return new SourceFile(meta, contents) - } catch (err: any) { - } + return new SourceFile(meta, contents) + } catch (err: any) { } } } diff --git a/packages/cli/src/services/check-parser/package-files/tsconfig-json-file.ts b/packages/cli/src/services/check-parser/package-files/tsconfig-json-file.ts index e709d73e..d8f9ec71 100644 --- a/packages/cli/src/services/check-parser/package-files/tsconfig-json-file.ts +++ b/packages/cli/src/services/check-parser/package-files/tsconfig-json-file.ts @@ -3,7 +3,6 @@ import path from 'node:path' import { SourceFile } from './source-file' import { JsonSourceFile } from './json-source-file' import { PathResolver, ResolveResult } from './paths' -import type { LoadFile } from './loader' type Module = 'none' | 'commonjs' | 'amd' | 'system' | 'es6' | 'es2015' | 'es2020' | @@ -61,10 +60,6 @@ export interface Schema { compilerOptions?: CompilerOptions } -export type Options = { - jsonSourceFileLoader?: LoadFile>, -} - type JSExtension = '.js' | '.mjs' | '.cjs' const JSExtensions: JSExtension[] = ['.js', '.mjs', '.cjs'] @@ -85,6 +80,9 @@ const extensionMappings: JSExtensionMappings = { export class TSConfigFile { static FILENAME = 'tsconfig.json' + static #id = 0 + readonly id = ++TSConfigFile.#id + jsonFile: JsonSourceFile basePath: string moduleResolution: string @@ -116,20 +114,6 @@ export class TSConfigFile { return new TSConfigFile(jsonFile) } - static loadFromFilePath (filePath: string, options?: Options): TSConfigFile | undefined { - const { jsonSourceFileLoader } = { - jsonSourceFileLoader: JsonSourceFile.loadFromFilePath, - ...options, - } - - const jsonFile = jsonSourceFileLoader(filePath) - if (jsonFile === undefined) { - return - } - - return new TSConfigFile(jsonFile) - } - static filePath (dirPath: string) { return path.join(dirPath, TSConfigFile.FILENAME) }