@travetto/manifest
Advanced tools
Comparing version 3.4.0 to 4.0.0-rc.0
@@ -1,2 +0,2 @@ | ||
/// <reference path="./src/typings.d.ts" /> | ||
/// <reference path="./src/global.d.ts" /> | ||
@@ -7,3 +7,3 @@ export * from './src/path'; | ||
export * from './src/manifest-index'; | ||
export * from './src/root-index'; | ||
export * from './src/runtime'; | ||
export * from './src/package'; | ||
@@ -10,0 +10,0 @@ export * from './src/util'; |
@@ -8,5 +8,5 @@ // @ts-check | ||
*/ | ||
import fs from 'fs/promises'; | ||
import path from 'path'; | ||
import { createRequire } from 'module'; | ||
import fs from 'node:fs/promises'; | ||
import path from 'node:path'; | ||
import { createRequire } from 'node:module'; | ||
@@ -63,3 +63,3 @@ /** @type {Record<string, Workspace>} */ const WS_ROOT = {}; | ||
if ( | ||
(pkg && (!!pkg.workspaces || !!pkg.travetto?.isolated)) || // if we have a monorepo root, or we are isolated | ||
(pkg && (!!pkg.workspaces || !!pkg.travetto?.build?.isolated)) || // if we have a monorepo root, or we are isolated | ||
await fs.stat(path.resolve(folder, '.git')).catch(() => { }) // we made it to the source repo root | ||
@@ -78,5 +78,7 @@ ) { | ||
...pkg, | ||
name: pkg.name ?? 'untitled', | ||
type: pkg.type, | ||
manager: await fs.stat(path.resolve(pkg.path, 'yarn.lock')).catch(() => { }) ? 'yarn' : 'npm', | ||
resolve: createRequire(`${pkg.path}/node_modules`).resolve.bind(null), | ||
mono: !!pkg.workspaces || (!pkg.travetto?.isolated && !!prevPkg) // Workspaces or nested projects | ||
mono: !!pkg.workspaces || (!pkg.travetto?.build?.isolated && !!prevPkg) // Workspaces or nested projects | ||
}; | ||
@@ -90,14 +92,11 @@ } | ||
async function $getCompilerUrl(ws) { | ||
let out = ws.travetto?.compilerUrl; | ||
if (!out) { | ||
const file = path.resolve(ws.path, ws.travetto?.toolFolder ?? TOOL_FOLDER, 'compiler.url'); | ||
// eslint-disable-next-line no-bitwise | ||
const port = (Math.abs([...file].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000; | ||
out = `http://localhost:${port}`; | ||
try { await fs.stat(file); } catch { | ||
await fs.mkdir(path.dirname(file), { recursive: true }); | ||
await fs.writeFile(file, out, 'utf8'); | ||
} | ||
const file = path.resolve(ws.path, TOOL_FOLDER, 'build.compilerUrl'); | ||
// eslint-disable-next-line no-bitwise | ||
const port = (Math.abs([...file].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000; | ||
const out = `http://localhost:${port}`; | ||
try { await fs.stat(file); } catch { | ||
await fs.mkdir(path.dirname(file), { recursive: true }); | ||
await fs.writeFile(file, out, 'utf8'); | ||
} | ||
return out.replace('localhost', '127.0.0.1'); | ||
return out; | ||
} | ||
@@ -114,3 +113,3 @@ | ||
mod = process.env.TRV_MODULE; | ||
if (/[.](t|j)s$/.test(mod)) { // Rewrite from file to module | ||
if (/[.](t|j)sx?$/.test(mod)) { // Rewrite from file to module | ||
process.env.TRV_MODULE = mod = await $findPackage(path.dirname(mod)) | ||
@@ -144,24 +143,26 @@ .then(v => v.name, () => ''); | ||
const workspace = await $resolveWorkspace(folder); | ||
const mod = await $resolveModule(workspace, folder); | ||
const build = workspace.travetto?.build ?? {}; | ||
const [mod, framework, compilerUrl] = await Promise.all([ | ||
$resolveModule(workspace, folder), | ||
$readPackage(workspace.resolve('@travetto/manifest/package.json')), | ||
$getCompilerUrl(workspace), | ||
]); | ||
return { | ||
workspacePath: workspace.path, | ||
monoRepo: workspace.mono, | ||
packageManager: workspace.manager, | ||
moduleType: workspace.type ?? 'commonjs', | ||
outputFolder: workspace.travetto?.outputFolder ?? OUTPUT_FOLDER, | ||
toolFolder: workspace.travetto?.toolFolder ?? TOOL_FOLDER, | ||
compilerFolder: workspace.travetto?.compilerFolder ?? COMPILER_FOLDER, | ||
compilerUrl, | ||
frameworkVersion: framework?.version ?? '1.0.0', | ||
mainModule: mod.name ?? 'untitled', | ||
mainFolder: mod.path === workspace.path ? '' : mod.path.replace(`${workspace.path}/`, ''), | ||
version: mod.version, | ||
description: mod.description | ||
workspace: { | ||
name: workspace.name, | ||
path: workspace.path, | ||
mono: workspace.mono, | ||
manager: workspace.manager, | ||
type: workspace.type ?? 'commonjs' | ||
}, | ||
build: { | ||
compilerFolder: build.compilerFolder ?? COMPILER_FOLDER, | ||
compilerUrl: build.compilerUrl ?? await $getCompilerUrl(workspace), | ||
compilerModuleFolder: path.dirname(workspace.resolve('@travetto/compiler/package.json')).replace(`${workspace.path}/`, ''), | ||
outputFolder: build.outputFolder ?? OUTPUT_FOLDER, | ||
}, | ||
main: { | ||
name: mod.name ?? 'untitled', | ||
folder: mod.path === workspace.path ? '' : mod.path.replace(`${workspace.path}/`, ''), | ||
version: mod.version, | ||
description: mod.description | ||
} | ||
}; | ||
} |
{ | ||
"name": "@travetto/manifest", | ||
"version": "3.4.0", | ||
"version": "4.0.0-rc.0", | ||
"description": "Support for project indexing, manifesting, along with file watching", | ||
@@ -35,3 +35,5 @@ "keywords": [ | ||
"displayName": "Manifest", | ||
"docBaseUrl": "https://github.com/travetto/travetto/tree/main" | ||
"doc": { | ||
"baseUrl": "https://github.com/travetto/travetto/tree/main" | ||
} | ||
}, | ||
@@ -38,0 +40,0 @@ "publishConfig": { |
@@ -38,3 +38,3 @@ <!-- This file was generated by @travetto/doc and should not be modified directly --> | ||
`Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts#L11) using the `getFunctionMetadata` method. | ||
`Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RuntimeIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/runtime.ts#L11) using the `getFunctionMetadata` method. | ||
@@ -54,6 +54,6 @@ **Code: Test Class** | ||
const tslib_1 = require("tslib"); | ||
const Ⲑ_root_index_1 = tslib_1.__importStar(require("@travetto/manifest/src/root-index.js")); | ||
const Ⲑ_runtime_1 = tslib_1.__importStar(require("@travetto/manifest/src/runtime.js")); | ||
var ᚕf = "@travetto/manifest/doc/test-class.js"; | ||
class TestClass { | ||
static Ⲑinit = Ⲑ_root_index_1.RootIndex.registerFunction(TestClass, ᚕf, 197152026, { doStuff: { hash: 51337554 } }, false, false); | ||
static Ⲑinit = Ⲑ_runtime_1.RuntimeIndex.registerFunction(TestClass, ᚕf, 197152026, { doStuff: { hash: 51337554 } }, false, false); | ||
async doStuff() { } | ||
@@ -97,15 +97,21 @@ } | ||
"generated": 1868155200000, | ||
"workspacePath": "<generated>", | ||
"monoRepo": true, | ||
"packageManager": "npm", | ||
"moduleType": "commonjs", | ||
"outputFolder": ".trv/output", | ||
"toolFolder": ".trv/tool", | ||
"compilerFolder": ".trv/compiler", | ||
"compilerUrl": "http://127.0.0.1:26803", | ||
"frameworkVersion": "x.x.x", | ||
"mainModule": "@travetto/manifest", | ||
"mainFolder": "module/manifest", | ||
"version": "x.x.x", | ||
"description": "Support for project indexing, manifesting, along with file watching", | ||
"workspace": { | ||
"name": "@travetto/mono-repo", | ||
"path": "<generated>", | ||
"mono": true, | ||
"manager": "npm", | ||
"type": "commonjs" | ||
}, | ||
"build": { | ||
"compilerFolder": ".trv/compiler", | ||
"compilerUrl": "http://127.0.0.1:26803", | ||
"compilerModuleFolder": "module/compiler", | ||
"outputFolder": ".trv/output" | ||
}, | ||
"main": { | ||
"name": "@travetto/manifest", | ||
"folder": "module/manifest", | ||
"version": "x.x.x", | ||
"description": "Support for project indexing, manifesting, along with file watching" | ||
}, | ||
"modules": { | ||
@@ -142,3 +148,3 @@ "@travetto/manifest": { | ||
[ "test/path.ts", "ts", 1868155200000, "test" ], | ||
[ "test/root-index.ts", "ts", 1868155200000, "test" ] | ||
[ "test/runtime.ts", "ts", 1868155200000, "test" ] | ||
], | ||
@@ -155,2 +161,3 @@ "test/fixtures": [ | ||
[ "src/file.ts", "ts", 1868155200000 ], | ||
[ "src/global.d.ts", "typings", 1868155200000 ], | ||
[ "src/manifest-index.ts", "ts", 1868155200000 ], | ||
@@ -160,5 +167,4 @@ [ "src/module.ts", "ts", 1868155200000 ], | ||
[ "src/path.ts", "ts", 1868155200000 ], | ||
[ "src/root-index.ts", "ts", 1868155200000 ], | ||
[ "src/runtime.ts", "ts", 1868155200000 ], | ||
[ "src/types.ts", "ts", 1868155200000 ], | ||
[ "src/typings.d.ts", "typings", 1868155200000 ], | ||
[ "src/util.ts", "ts", 1868155200000 ] | ||
@@ -165,0 +171,0 @@ ], |
@@ -12,3 +12,3 @@ import { | ||
type DeltaModule = ManifestModuleCore & { files: Record<string, ManifestModuleFile> }; | ||
export type DeltaEvent = { file: string, type: DeltaEventType, module: string }; | ||
export type DeltaEvent = { file: string, type: DeltaEventType, module: string, sourceFile: string }; | ||
@@ -34,5 +34,5 @@ const VALID_SOURCE_FOLDERS = new Set<ManifestModuleFolderType>(['bin', 'src', 'test', 'support', '$index', '$package', 'doc']); | ||
const add = (file: string, type: DeltaEvent['type']): unknown => | ||
out.push({ file, module: left.name, type }); | ||
out.push({ file, module: left.name, type, sourceFile: path.resolve(ctx.workspace.path, left.sourceFolder, file) }); | ||
const root = `${ctx.workspacePath}/${ctx.outputFolder}/${left.outputFolder}`; | ||
const root = path.resolve(ctx.workspace.path, ctx.build.outputFolder, left.outputFolder); | ||
const right = new Set( | ||
@@ -93,3 +93,3 @@ (await ManifestModuleUtil.scanFolder(root, left.main)) | ||
*/ | ||
static async produceDelta(ctx: ManifestContext, manifest: ManifestRoot): Promise<DeltaEvent[]> { | ||
static async produceDelta(manifest: ManifestRoot): Promise<DeltaEvent[]> { | ||
const deltaLeft = Object.fromEntries( | ||
@@ -101,3 +101,3 @@ Object.values(manifest.modules) | ||
const out: DeltaEvent[] = []; | ||
const outputFolder = path.resolve(ctx.workspacePath, ctx.outputFolder); | ||
const outputFolder = path.resolve(manifest.workspace.path, manifest.build.outputFolder); | ||
@@ -104,0 +104,0 @@ for (const lMod of Object.values(deltaLeft)) { |
import { PackageUtil } from './package'; | ||
import { path } from './path'; | ||
import { ManifestContext, ManifestModuleRole, PackageVisitor, PackageVisitReq, Package } from './types'; | ||
import { ManifestContext, ManifestModuleRole, PackageVisitor, PackageVisitReq, Package, ManifestDepCore } from './types'; | ||
export type ModuleDep = { | ||
export type ModuleDep = ManifestDepCore & { | ||
pkg: Package; | ||
version: string; | ||
name: string; | ||
main?: boolean; | ||
mainSource?: boolean; | ||
local?: boolean; | ||
internal?: boolean; | ||
mainLike?: boolean; | ||
sourcePath: string; | ||
@@ -17,3 +12,2 @@ childSet: Set<string>; | ||
roleSet: Set<ManifestModuleRole>; | ||
prod: boolean; | ||
topLevel?: boolean; | ||
@@ -27,29 +21,17 @@ }; | ||
/** | ||
* Get main patterns for detecting if a module should be treated as main | ||
*/ | ||
static getMainPatterns(mainModule: string, mergeModules: string[]): RegExp[] { | ||
const groups: Record<string, string[]> = { [mainModule]: [] }; | ||
for (const el of mergeModules) { | ||
if (el.includes('/')) { | ||
const [grp, sub] = el.split('/'); | ||
(groups[`${grp}/`] ??= []).push(sub); | ||
} else { | ||
(groups[el] ??= []); | ||
} | ||
} | ||
return Object.entries(groups) | ||
.map(([root, subs]) => subs.length ? `${root}(${subs.join('|')})` : root) | ||
.map(x => new RegExp(`^${x.replace(/[*]/g, '.*?')}$`)); | ||
} | ||
constructor(public ctx: ManifestContext) { | ||
this.#mainSourcePath = path.resolve(this.ctx.workspacePath, this.ctx.mainFolder); | ||
this.#mainSourcePath = path.resolve(this.ctx.workspace.path, this.ctx.main.folder); | ||
} | ||
#mainPatterns: RegExp[] = []; | ||
#mainLikeModules = new Set<string>(); | ||
#mainSourcePath: string; | ||
/** | ||
* Main source path for searching | ||
*/ | ||
get rootPath(): string { | ||
return this.#mainSourcePath; | ||
} | ||
/** | ||
* Initialize visitor, and provide global dependencies | ||
@@ -59,7 +41,8 @@ */ | ||
const pkg = PackageUtil.readPackage(req.sourcePath); | ||
const workspacePkg = PackageUtil.readPackage(this.ctx.workspacePath); | ||
const workspacePkg = PackageUtil.readPackage(this.ctx.workspace.path); | ||
const workspaceModules = pkg.workspaces?.length ? (await PackageUtil.resolveWorkspaces(this.ctx, req.sourcePath)) : []; | ||
this.#mainPatterns = ModuleDependencyVisitor.getMainPatterns(pkg.name, [ | ||
...pkg.travetto?.mainSource ?? [], | ||
this.#mainLikeModules = new Set([ | ||
pkg.name, | ||
...Object.entries(pkg.travetto?.build?.withModules ?? []).filter(x => x[1] === 'main').map(x => x[0]), | ||
// Add workspace folders, for tests and docs | ||
@@ -69,3 +52,3 @@ ...workspaceModules.map(x => x.name) | ||
const globals = (workspacePkg.travetto?.globalModules ?? []) | ||
const globals = Object.keys(workspacePkg.travetto?.build?.withModules ?? []) | ||
.map(name => PackageUtil.packageReq<ModuleDep>(PackageUtil.resolvePackagePath(name), name in (workspacePkg.dependencies ?? {}), true)); | ||
@@ -94,9 +77,9 @@ | ||
const { name, version } = pkg; | ||
const main = name === this.ctx.mainModule; | ||
const mainSource = main || this.#mainPatterns.some(x => x.test(name)); | ||
const main = name === this.ctx.main.name; | ||
const mainLike = main || this.#mainLikeModules.has(name); | ||
const internal = pkg.private === true; | ||
const local = internal || mainSource || !sourcePath.includes('node_modules'); | ||
const local = internal || mainLike || !sourcePath.includes('node_modules'); | ||
const dep = { | ||
name, version, sourcePath, main, mainSource, local, internal, pkg: req.pkg, | ||
const dep: ModuleDep = { | ||
name, version, sourcePath, main, mainLike, local, internal, pkg: req.pkg, | ||
parentSet: new Set([]), childSet: new Set([]), roleSet: new Set([]), prod: req.prod, topLevel: req.topLevel | ||
@@ -113,3 +96,3 @@ }; | ||
const { parent } = req; | ||
if (parent && dep.name !== this.ctx.mainModule) { | ||
if (parent && dep.name !== this.ctx.main.name) { | ||
dep.parentSet.add(parent.name); | ||
@@ -129,7 +112,10 @@ parent.childSet.add(dep.name); | ||
const main = mapping.get(this.ctx.mainModule)!; | ||
const main = mapping.get(this.ctx.main.name)!; | ||
// Visit all direct dependencies and mark | ||
for (const { el } of mapping.values()) { | ||
if (el.topLevel) { | ||
if (!main.child.has(el.name)) { // Not a direct descendent | ||
el.prod = false; | ||
} | ||
if (main.child.has(el.name) || (el.topLevel && el !== main.el)) { // Direct descendant | ||
el.roleSet = new Set(el.pkg.travetto?.roles ?? []); | ||
@@ -139,4 +125,2 @@ if (!el.roleSet.size) { | ||
} | ||
} else if (!main.child.has(el.name)) { // Not a direct descendent | ||
el.prod = false; | ||
} | ||
@@ -143,0 +127,0 @@ } |
@@ -1,4 +0,4 @@ | ||
import os from 'os'; | ||
import fs from 'fs/promises'; | ||
import { readFileSync } from 'fs'; | ||
import os from 'node:os'; | ||
import fs from 'node:fs/promises'; | ||
import { readFileSync } from 'node:fs'; | ||
@@ -51,6 +51,6 @@ import { path } from './path'; | ||
if (moduleSpecific) { | ||
parts.unshift('node_modules', ctx.mainModule); | ||
parts.unshift('node_modules', ctx.main.name); | ||
} | ||
return path.resolve(ctx.workspacePath, ctx.toolFolder, ...parts); | ||
return path.resolve(ctx.workspace.path, '.trv/tool', ...parts); | ||
} | ||
} |
@@ -80,3 +80,3 @@ import { ManifestModuleUtil } from './module'; | ||
this.#manifestFile = file; | ||
this.#outputRoot = path.resolve(this.#manifest.workspacePath, this.#manifest.outputFolder); | ||
this.#outputRoot = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder); | ||
this.#index(); | ||
@@ -88,3 +88,3 @@ } | ||
const isSource = type === 'ts' || type === 'js'; | ||
const sourceFile = path.resolve(this.#manifest.workspacePath, m.sourceFolder, f); | ||
const sourceFile = path.resolve(this.#manifest.workspace.path, m.sourceFolder, f); | ||
const js = isSource ? ManifestModuleUtil.sourceToOutputExt(f) : f; | ||
@@ -114,3 +114,3 @@ const outputFile = this.#resolveOutput(m.outputFolder, js); | ||
outputPath: this.#resolveOutput(m.outputFolder), | ||
sourcePath: path.resolve(this.#manifest.workspacePath, m.sourceFolder), | ||
sourcePath: path.resolve(this.#manifest.workspace.path, m.sourceFolder), | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
@@ -117,0 +117,0 @@ files: Object.fromEntries( |
@@ -1,2 +0,2 @@ | ||
import fs from 'fs/promises'; | ||
import fs from 'node:fs/promises'; | ||
@@ -29,2 +29,5 @@ import { path } from './path'; | ||
const STD_TOP_FOLDERS = new Set(['src', 'bin', 'support']); | ||
const STD_TOP_FILES = new Set([...INDEX_FILES, 'package.json']); | ||
export class ManifestModuleUtil { | ||
@@ -48,4 +51,4 @@ | ||
*/ | ||
static async scanFolder(folder: string, mainSource = false): Promise<string[]> { | ||
if (!mainSource && folder in this.#scanCache) { | ||
static async scanFolder(folder: string, mainLike = false): Promise<string[]> { | ||
if (!mainLike && folder in this.#scanCache) { | ||
return this.#scanCache[folder]; | ||
@@ -58,4 +61,2 @@ } | ||
const topFolders = new Set(mainSource ? [] : ['src', 'bin', 'support']); | ||
const topFiles = new Set(mainSource ? [] : [...INDEX_FILES, 'package.json']); | ||
const out: string[] = []; | ||
@@ -78,9 +79,10 @@ | ||
for (const sub of await fs.readdir(top)) { | ||
const valid = !sub.startsWith('.') && (depth > 0 || mainLike); | ||
const stat = await fs.stat(`${top}/${sub}`); | ||
if (stat.isFile()) { | ||
if (!sub.startsWith('.') && (depth > 0 || !topFiles.size || topFiles.has(sub))) { | ||
if (valid || STD_TOP_FILES.has(sub)) { | ||
out.push(`${top}/${sub}`); | ||
} | ||
} else { | ||
if (!sub.includes('node_modules') && !sub.startsWith('.') && (depth > 0 || !topFolders.size || topFolders.has(sub))) { | ||
if (!sub.includes('node_modules') && (valid || STD_TOP_FOLDERS.has(sub))) { | ||
stack.push([`${top}/${sub}`, depth + 1]); | ||
@@ -92,3 +94,3 @@ } | ||
if (!mainSource) { | ||
if (!mainLike) { | ||
this.#scanCache[folder] = out; | ||
@@ -184,7 +186,7 @@ } | ||
static async describeModule(ctx: ManifestContext, dep: ModuleDep): Promise<ManifestModule> { | ||
const { main, mainSource, local, name, version, sourcePath, roleSet, prod, parentSet, internal } = dep; | ||
const { main, mainLike, local, name, version, sourcePath, roleSet, prod, parentSet, internal } = dep; | ||
const files: ManifestModule['files'] = {}; | ||
for (const file of await this.scanFolder(sourcePath, mainSource)) { | ||
for (const file of await this.scanFolder(sourcePath, mainLike)) { | ||
// Group by top folder | ||
@@ -197,4 +199,4 @@ const moduleFile = file.replace(`${sourcePath}/`, ''); | ||
// Refine non-main source | ||
if (!mainSource) { | ||
// Refine non-main source, remove anything in root that is source (doesn't include $index) | ||
if (!mainLike) { | ||
files.$root = files.$root?.filter(([file, type]) => type !== 'ts'); | ||
@@ -206,5 +208,7 @@ } | ||
const outputFolder = `node_modules/${name}`; | ||
const sourceFolder = sourcePath === ctx.workspacePath ? '' : sourcePath.replace(`${ctx.workspacePath}/`, ''); | ||
const sourceFolder = sourcePath === ctx.workspace.path ? '' : sourcePath.replace(`${ctx.workspace.path}/`, ''); | ||
const res = { main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files }; | ||
const res: ManifestModule = { | ||
main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files | ||
}; | ||
return res; | ||
@@ -218,4 +222,3 @@ } | ||
const visitor = new ModuleDependencyVisitor(ctx); | ||
const mainPath = path.resolve(ctx.workspacePath, ctx.mainFolder); | ||
const declared = await PackageUtil.visitPackages(mainPath, visitor); | ||
const declared = await PackageUtil.visitPackages(visitor); | ||
const sorted = [...declared].sort((a, b) => a.name.localeCompare(b.name)); | ||
@@ -222,0 +225,0 @@ const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x))); |
@@ -1,5 +0,5 @@ | ||
import { createRequire } from 'module'; | ||
import { execSync } from 'child_process'; | ||
import { createRequire } from 'node:module'; | ||
import { execSync } from 'node:child_process'; | ||
import { ManifestContext, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types'; | ||
import type { ManifestContext, NodePackageManager, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types'; | ||
import { path } from './path'; | ||
@@ -13,3 +13,3 @@ import { ManifestFileUtil } from './file'; | ||
static #req = createRequire(path.resolve('node_modules')); | ||
static #resolvers: Record<string, (imp: string) => string> = {}; | ||
static #cache: Record<string, Package> = {}; | ||
@@ -25,11 +25,9 @@ static #workspaces: Record<string, PackageWorkspaceEntry[]> = {}; | ||
/** | ||
* Clear out cached package file reads | ||
* Resolve import given a manifest context | ||
*/ | ||
static clearCache(): void { | ||
this.#cache = {}; | ||
this.#workspaces = {}; | ||
static resolveImport(imp: string, root?: string): string { | ||
const loc = path.resolve(root ?? '.', 'node_modules'); | ||
return (this.#resolvers[loc] ??= createRequire(loc).resolve.bind(null))(imp); | ||
} | ||
static resolveImport = (library: string): string => this.#req.resolve(library); | ||
/** | ||
@@ -49,8 +47,8 @@ * Resolve version path, if file: url | ||
*/ | ||
static resolvePackagePath(name: string): string { | ||
static resolvePackagePath(name: string, root?: string): string { | ||
try { | ||
return path.dirname(this.resolveImport(`${name}/package.json`)); | ||
return path.dirname(this.resolveImport(`${name}/package.json`, root)); | ||
} catch { | ||
try { | ||
const resolved = this.resolveImport(name); | ||
const resolved = this.resolveImport(name, root); | ||
return path.join(resolved.split(name)[0], name); | ||
@@ -113,10 +111,5 @@ } catch { } | ||
*/ | ||
static async visitPackages<T>( | ||
rootOrPath: PackageVisitReq<T> | string, | ||
visitor: PackageVisitor<T> | ||
): Promise<Set<T>> { | ||
static async visitPackages<T>(visitor: PackageVisitor<T>): Promise<Set<T>> { | ||
const root = typeof rootOrPath === 'string' ? | ||
this.packageReq<T>(rootOrPath, false, true) : | ||
rootOrPath; | ||
const root = this.packageReq<T>(visitor.rootPath, false, true); | ||
@@ -162,3 +155,3 @@ const seen = new Map<string, T>(); | ||
if (!this.#workspaces[rootPath]) { | ||
const cache = path.resolve(ctx.workspacePath, ctx.outputFolder, 'workspaces.json'); | ||
const cache = path.resolve(ctx.workspace.path, ctx.build.outputFolder, 'workspaces.json'); | ||
try { | ||
@@ -168,3 +161,3 @@ return await ManifestFileUtil.readAsJson(cache); | ||
let out: PackageWorkspaceEntry[]; | ||
switch (ctx.packageManager) { | ||
switch (ctx.workspace.manager) { | ||
case 'npm': { | ||
@@ -189,2 +182,14 @@ const res = await this.#exec<{ location: string, name: string }[]>(rootPath, 'npm query .workspace'); | ||
} | ||
/** | ||
* Get an install command for a given npm module | ||
*/ | ||
static getInstallCommand(ctx: { workspace: { manager: NodePackageManager } }, pkg: string, prod = false): string { | ||
let install: string; | ||
switch (ctx.workspace.manager) { | ||
case 'npm': install = `npm i ${prod ? '' : '--save-dev '}${pkg}`; break; | ||
case 'yarn': install = `yarn add ${prod ? '' : '--dev '}${pkg}`; break; | ||
} | ||
return install; | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
import type * as pathMod from 'path'; | ||
import { extname, dirname, basename, resolve, join } from 'path/posix'; | ||
import { sep, resolve as nativeResolve, join as nativeJoin } from 'path'; | ||
import type * as pathMod from 'node:path'; | ||
import { extname, dirname, basename, resolve, join } from 'node:path/posix'; | ||
import { sep, resolve as nativeResolve, join as nativeJoin } from 'node:path'; | ||
@@ -5,0 +5,0 @@ /** |
export type NodeModuleType = 'module' | 'commonjs'; | ||
export type NodePackageManager = 'yarn' | 'npm'; | ||
@@ -13,3 +14,3 @@ export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md'; | ||
export type ManifestModuleFile = [string, ManifestModuleFileType, number] | [string, ManifestModuleFileType, number, ManifestModuleRole]; | ||
export type ManifestModuleCore = { | ||
export type ManifestDepCore = { | ||
name: string; | ||
@@ -19,8 +20,10 @@ main?: boolean; | ||
version: string; | ||
prod: boolean; | ||
internal?: boolean; | ||
}; | ||
export type ManifestModuleCore = ManifestDepCore & { | ||
sourceFolder: string; | ||
outputFolder: string; | ||
prod: boolean; | ||
roles: ManifestModuleRole[]; | ||
parents: string[]; | ||
internal?: boolean; | ||
}; | ||
@@ -33,15 +36,34 @@ | ||
export type ManifestContext = { | ||
mainModule: string; | ||
mainFolder: string; | ||
workspacePath: string; | ||
outputFolder: string; | ||
toolFolder: string; | ||
compilerFolder: string; | ||
monoRepo?: boolean; | ||
moduleType: NodeModuleType; | ||
packageManager: 'yarn' | 'npm'; | ||
frameworkVersion: string; | ||
description?: string; | ||
version: string; | ||
compilerUrl: string; | ||
workspace: { | ||
/** Workspace path for module */ | ||
path: string; | ||
/** The module name for the workspace root */ | ||
name: string; | ||
/** Is the workspace a monorepo? */ | ||
mono?: boolean; | ||
/** The module type of the workspace */ | ||
type: NodeModuleType; | ||
/** The package manager of the workspace */ | ||
manager: NodePackageManager; | ||
}; | ||
build: { | ||
/** Compiler folder, relative to workspace */ | ||
compilerFolder: string; | ||
/** Compiler module folder */ | ||
compilerModuleFolder: string; | ||
/** URL for the compiler server */ | ||
compilerUrl: string; | ||
/** Code output folder, relative to workspace */ | ||
outputFolder: string; | ||
}; | ||
main: { | ||
/** Main module for manifest */ | ||
name: string; | ||
/** Folder, relative to workspace for main module */ | ||
folder: string; | ||
/** Description of the main module */ | ||
description?: string; | ||
/** Version of the main module */ | ||
version: string; | ||
}; | ||
}; | ||
@@ -82,15 +104,14 @@ | ||
travetto?: { | ||
isolated?: boolean; | ||
displayName?: string; | ||
roles?: ManifestModuleRole[]; | ||
globalModules?: string[]; | ||
mainSource?: string[]; | ||
docOutput?: string[]; | ||
docRoot?: string; | ||
docBaseUrl?: string; | ||
docOutputs?: string[]; | ||
outputFolder?: string; | ||
toolFolder?: string; | ||
compilerFolder?: string; | ||
compilerUrl?: string; | ||
doc?: { | ||
output?: string[]; | ||
root?: string; | ||
baseUrl?: string; | ||
outputs?: string[]; | ||
}; | ||
build?: Partial<ManifestContext['build']> & { | ||
isolated?: boolean; | ||
withModules?: Record<string, 'main' | true>; | ||
}; | ||
}; | ||
@@ -106,2 +127,3 @@ workspaces?: string[]; | ||
export type PackageVisitor<T> = { | ||
rootPath: string; | ||
init?(req: PackageVisitReq<T>): OrProm<undefined | void | PackageVisitReq<T>[]>; | ||
@@ -108,0 +130,0 @@ valid?(req: PackageVisitReq<T>): boolean; |
@@ -5,2 +5,3 @@ import { path } from './path'; | ||
import { ManifestFileUtil } from './file'; | ||
import { PackageUtil } from './package'; | ||
@@ -14,11 +15,2 @@ const MANIFEST_FILE = 'manifest.json'; | ||
/** | ||
* Build a manifest context | ||
* @param folder | ||
*/ | ||
static async buildContext(folder?: string): Promise<ManifestContext> { | ||
const { getManifestContext } = await import('../bin/context.js'); | ||
return getManifestContext(folder); | ||
} | ||
/** | ||
* Produce manifest in memory | ||
@@ -46,5 +38,7 @@ */ | ||
), | ||
// Mark output folder/workspace path as portable | ||
outputFolder: '', | ||
workspacePath: '', | ||
build: { | ||
...manifest.build, | ||
// Mark output folder/workspace path as portable | ||
outputFolder: '$$PRODUCTION$$', | ||
} | ||
}; | ||
@@ -65,6 +59,6 @@ } | ||
const manifest: ManifestRoot = ManifestFileUtil.readAsJsonSync(file); | ||
// Support packaged environments, by allowing empty outputFolder | ||
if (!manifest.outputFolder) { | ||
manifest.outputFolder = path.cwd(); | ||
manifest.workspacePath = path.cwd(); | ||
// Support packaged environments, by allowing empty manifest.build.outputFolder | ||
if (manifest.build.outputFolder === '$$PRODUCTION$$') { | ||
manifest.build.outputFolder = path.cwd(); | ||
manifest.workspace.path = path.cwd(); | ||
} | ||
@@ -77,6 +71,6 @@ return { manifest, file }; | ||
*/ | ||
static writeManifest(ctx: ManifestContext, manifest: ManifestRoot): Promise<string> { | ||
return ManifestFileUtil.bufferedFileWrite( | ||
path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules', ctx.mainModule, MANIFEST_FILE), | ||
JSON.stringify(manifest) | ||
static writeManifest(manifest: ManifestRoot): Promise<string> { | ||
return this.writeManifestToFile( | ||
path.resolve(manifest.workspace.path, manifest.build.outputFolder, 'node_modules', manifest.main.name), | ||
manifest | ||
); | ||
@@ -99,9 +93,32 @@ } | ||
/** | ||
* Rewrite manifest for a given folder | ||
* Produce the manifest context for the workspace module | ||
*/ | ||
static async rewriteManifest(source: string): Promise<void> { | ||
const subCtx = await this.buildContext(source); | ||
const subManifest = await this.buildManifest(subCtx); | ||
await this.writeManifest(subCtx, subManifest); | ||
static getWorkspaceContext(ctx: ManifestContext): ManifestContext { | ||
return ctx.workspace.mono ? { | ||
...ctx, | ||
main: { | ||
name: ctx.workspace.name, | ||
folder: '', | ||
version: '0.0.0', | ||
} | ||
} : ctx; | ||
} | ||
/** | ||
* Produce the manifest context for a given module module | ||
*/ | ||
static getModuleContext(ctx: ManifestContext, folder: string): ManifestContext { | ||
const modPath = path.resolve(ctx.workspace.path, folder); | ||
const pkg = PackageUtil.readPackage(modPath); | ||
return { | ||
...ctx, | ||
main: { | ||
name: pkg.name, | ||
folder, | ||
version: pkg.version, | ||
description: pkg.description | ||
} | ||
}; | ||
} | ||
} |
@@ -12,4 +12,4 @@ import ts from 'typescript'; | ||
const ROOT_IDX_IMPORT = `${MANIFEST_MOD}/src/root-index`; | ||
const ROOT_IDX_CLS = 'RootIndex'; | ||
const RUNTIME_IDX_IMPORT = `${MANIFEST_MOD}/src/runtime`; | ||
const RUNTIME_IDX_CLS = 'RuntimeIndex'; | ||
@@ -19,6 +19,6 @@ const methods = Symbol.for(`${MANIFEST_MOD}:methods`); | ||
const fn = Symbol.for(`${MANIFEST_MOD}:function`); | ||
const rootIdx = Symbol.for(`${MANIFEST_MOD}:rootIndex`); | ||
const runtimeIdx = Symbol.for(`${MANIFEST_MOD}:runtimeIndex`); | ||
interface MetadataInfo { | ||
[rootIdx]?: Import; | ||
[runtimeIdx]?: Import; | ||
[methods]?: { | ||
@@ -77,4 +77,4 @@ [key: string]: { hash: number }; | ||
state[rootIdx] ??= state.importFile(ROOT_IDX_IMPORT); | ||
const ident = state.createAccess(state[rootIdx].ident, ROOT_IDX_CLS); | ||
state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT); | ||
const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS); | ||
@@ -123,4 +123,4 @@ const name = node.name?.escapedText.toString() ?? ''; | ||
// If we have a class like function | ||
state[rootIdx] ??= state.importFile(ROOT_IDX_IMPORT); | ||
const ident = state.createAccess(state[rootIdx].ident, ROOT_IDX_CLS); | ||
state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT); | ||
const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS); | ||
const meta = state.factory.createCallExpression( | ||
@@ -127,0 +127,0 @@ state.createAccess(ident, 'registerFunction'), |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
67555
1528
231
4
1