pkg-scaffold 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.scaffold-ignore +22 -0
- package/bin/cli.js +91 -0
- package/index.js +2254 -2544
- package/package.json +19 -7
- package/src/EngineContext.js +282 -0
- package/src/ast/ASTAnalyzer.js +313 -0
- package/src/ast/BarrelParser.js +177 -0
- package/src/ast/MagicDetector.js +154 -0
- package/src/healing/GitSandbox.js +160 -0
- package/src/healing/SelfHealer.js +150 -0
- package/src/index.js +343 -0
- package/src/performance/GraphCache.js +82 -0
- package/src/performance/SupplyChainGuard.js +106 -0
- package/src/performance/WorkerPool.js +89 -0
- package/src/performance/WorkerTaskRunner.js +64 -0
- package/src/refractor/ImpactAnalyzer.js +92 -0
- package/src/refractor/SourceRewriter.js +86 -0
- package/src/refractor/TransactionManager.js +131 -0
- package/src/refractor/TypeIntegrity.js +75 -0
- package/src/resolution/DepencyResolver.js +120 -0
- package/src/resolution/PathMapper.js +115 -0
- package/src/resolution/WorkSpaceGraph.js +171 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { glob } from 'fs/promises'; // Native sub-directory crawling
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Monorepo Cross-Linking Topology Manager
|
|
7
|
+
* Maps sub-package structural boundaries across pnpm, Yarn, or npm workspaces.
|
|
8
|
+
*/
|
|
9
|
+
export class WorkspaceGraph {
|
|
10
|
+
constructor(context) {
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.packageManifests = new Map(); // Package Name -> { manifestPath, rootDirectory, entryPoints[] }
|
|
13
|
+
this.workspacePackageNames = new Set();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Checks the environment layout to discover and map local workspace packages.
|
|
18
|
+
*/
|
|
19
|
+
async initializeWorkspaceMesh() {
|
|
20
|
+
const rootPackageJsonPath = path.join(this.context.cwd, 'package.json');
|
|
21
|
+
const pnpmWorkspacePath = path.join(this.context.cwd, 'pnpm-workspace.yaml');
|
|
22
|
+
|
|
23
|
+
let workspaceGlobs = [];
|
|
24
|
+
|
|
25
|
+
// Protocol A: Check for pnpm workspace configurations
|
|
26
|
+
try {
|
|
27
|
+
const yaml = await fs.readFile(pnpmWorkspacePath, 'utf8');
|
|
28
|
+
const lines = yaml.split('\n');
|
|
29
|
+
let insidePackagesBlock = false;
|
|
30
|
+
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
const trimmed = line.trim();
|
|
33
|
+
if (trimmed.startsWith('packages:')) {
|
|
34
|
+
insidePackagesBlock = true;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (insidePackagesBlock && trimmed.startsWith('-')) {
|
|
38
|
+
const pattern = trimmed.replace(/^-|['"]/g, '').trim();
|
|
39
|
+
workspaceGlobs.push(pattern);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// pnpm structure absent; check package.json workspace array paths instead
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Protocol B: Check for Yarn/npm workspaces array inside the root package.json
|
|
47
|
+
if (workspaceGlobs.length === 0) {
|
|
48
|
+
try {
|
|
49
|
+
const pkgText = await fs.readFile(rootPackageJsonPath, 'utf8');
|
|
50
|
+
const pkg = JSON.parse(pkgText);
|
|
51
|
+
if (pkg.workspaces) {
|
|
52
|
+
workspaceGlobs = Array.isArray(pkg.workspaces) ? pkg.workspaces : (pkg.workspaces.packages || []);
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
return; // Workspace mesh maps skipped for single-package targets
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Crawl target glob configurations to locate workspace packages
|
|
60
|
+
for (const pattern of workspaceGlobs) {
|
|
61
|
+
await this.locatePackagesViaPattern(pattern);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async locatePackagesViaPattern(globPattern) {
|
|
66
|
+
// Normalizes wildcards down into base query directories
|
|
67
|
+
const standardizedPattern = globPattern.replace(/\\/g, '/');
|
|
68
|
+
const baseDir = standardizedPattern.split('/*')[0];
|
|
69
|
+
const absoluteSearchPath = path.resolve(this.context.cwd, baseDir);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const contents = await fs.readdir(absoluteSearchPath, { withFileTypes: true });
|
|
73
|
+
|
|
74
|
+
for (const entity of contents) {
|
|
75
|
+
if (!entity.isDirectory()) continue;
|
|
76
|
+
|
|
77
|
+
const subPackageDir = path.join(absoluteSearchPath, entity.name);
|
|
78
|
+
const manifestFile = path.join(subPackageDir, 'package.json');
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const data = await fs.readFile(manifestFile, 'utf8');
|
|
82
|
+
const pkg = JSON.parse(data);
|
|
83
|
+
|
|
84
|
+
if (pkg.name) {
|
|
85
|
+
const entryPoints = this.calculatePackageExportsEntries(pkg, subPackageDir);
|
|
86
|
+
|
|
87
|
+
this.packageManifests.set(pkg.name, {
|
|
88
|
+
packageName: pkg.name,
|
|
89
|
+
rootDirectory: subPackageDir,
|
|
90
|
+
manifestPath: manifestFile,
|
|
91
|
+
entryPoints
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
this.workspacePackageNames.add(pkg.name);
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
// package.json parsing failed; ignore invalid directory roots
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// Unreadable target directories; pass tracking
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Tracks package entry points by evaluating standard fields and main/exports configurations.
|
|
107
|
+
*/
|
|
108
|
+
calculatePackageExportsEntries(pkg, pkgDir) {
|
|
109
|
+
const entries = new Set();
|
|
110
|
+
|
|
111
|
+
// Trace traditional entry fields
|
|
112
|
+
if (pkg.main) entries.add(path.resolve(pkgDir, pkg.main));
|
|
113
|
+
if (pkg.module) entries.add(path.resolve(pkgDir, pkg.module));
|
|
114
|
+
if (pkg.browser) entries.add(path.resolve(pkgDir, pkg.browser));
|
|
115
|
+
if (pkg.types) entries.add(path.resolve(pkgDir, pkg.types));
|
|
116
|
+
|
|
117
|
+
// Handle deep nested conditional exports matrices block parameters
|
|
118
|
+
if (pkg.exports) {
|
|
119
|
+
this.recursivelyUnwindExports(pkg.exports, pkgDir, entries);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Default file index fallback configurations
|
|
123
|
+
if (entries.size === 0) {
|
|
124
|
+
entries.add(path.resolve(pkgDir, 'index.js'));
|
|
125
|
+
entries.add(path.resolve(pkgDir, 'index.ts'));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return Array.from(entries);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
recursivelyUnwindExports(exportsValue, pkgDir, collected) {
|
|
132
|
+
if (typeof exportsValue === 'string') {
|
|
133
|
+
if (exportsValue.startsWith('.')) {
|
|
134
|
+
collected.add(path.resolve(pkgDir, exportsValue));
|
|
135
|
+
}
|
|
136
|
+
} else if (typeof exportsValue === 'object' && exportsValue !== null) {
|
|
137
|
+
for (const val of Object.values(exportsValue)) {
|
|
138
|
+
this.recursivelyUnwindExports(val, pkgDir, collected);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Checks if an import specifier matches a package registered in our workspace mesh.
|
|
145
|
+
*/
|
|
146
|
+
isLocalWorkspaceSpecifier(specifier) {
|
|
147
|
+
if (this.workspacePackageNames.has(specifier)) return true;
|
|
148
|
+
|
|
149
|
+
// Catch sub-path imports from monorepos (e.g., '@workspace/shared/utils')
|
|
150
|
+
for (const registeredPkgName of this.workspacePackageNames) {
|
|
151
|
+
if (specifier.startsWith(`${registeredPkgName}/`)) return true;
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Maps a workspace package specifier to its local absolute package root location on disk.
|
|
158
|
+
*/
|
|
159
|
+
getWorkspacePackageMatch(specifier) {
|
|
160
|
+
if (this.packageManifests.has(specifier)) {
|
|
161
|
+
return this.packageManifests.get(specifier);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const [name, metadata] of this.packageManifests.entries()) {
|
|
165
|
+
if (specifier.startsWith(`${name}/`)) {
|
|
166
|
+
return metadata;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ESNext"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./",
|
|
13
|
+
"allowJs": true,
|
|
14
|
+
"checkJs": false,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"emitDeclarationOnly": false
|
|
17
|
+
},
|
|
18
|
+
"include": [
|
|
19
|
+
"bin/**/*",
|
|
20
|
+
"src/**/*"
|
|
21
|
+
],
|
|
22
|
+
"exclude": [
|
|
23
|
+
"node_modules",
|
|
24
|
+
".scaffold-cache"
|
|
25
|
+
]
|
|
26
|
+
}
|