pkg-scaffold 2.3.0 → 3.0.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.
@@ -0,0 +1,75 @@
1
+ import ts from 'typescript';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+
5
+ /**
6
+ * Ambient Type Declaration (`.d.ts`) Alignment Supervisor
7
+ * Updates declaration mapping entries to keep compiler checks stable.
8
+ */
9
+ export class TypeIntegrity {
10
+ constructor(context) {
11
+ this.context = context;
12
+ }
13
+
14
+ /**
15
+ * Re-evaluates ambient files to verify type alignment after optimization changes.
16
+ * @param {string} sourceFilePath - Absolute filename target context location
17
+ * @param {string} prunedSymbolName - Target variable token removed from active source graph
18
+ */
19
+ async synchronizeDeclarationFile(sourceFilePath, prunedSymbolName) {
20
+ const fileDirectory = path.dirname(sourceFilePath);
21
+ const baselineName = path.basename(sourceFilePath, path.extname(sourceFilePath));
22
+
23
+ // Map standard ambient types build output combinations
24
+ const declarationTargets = [
25
+ path.join(fileDirectory, `${baselineName}.d.ts`),
26
+ path.join(this.context.cwd, 'dist', `${baselineName}.d.ts`),
27
+ path.join(this.context.cwd, 'types', `${baselineName}.d.ts`)
28
+ ];
29
+
30
+ for (const dtsPath of declarationTargets) {
31
+ try {
32
+ await fs.access(dtsPath);
33
+ const code = await fs.readFile(dtsPath, 'utf8');
34
+
35
+ const sourceFile = ts.createSourceFile(
36
+ dtsPath,
37
+ code,
38
+ ts.ScriptTarget.Latest,
39
+ true,
40
+ ts.ScriptKind.TS
41
+ );
42
+
43
+ const replacementIntervals = [];
44
+ this.inspectDtsNodes(sourceFile, prunedSymbolName, replacementIntervals);
45
+
46
+ if (replacementIntervals.length > 0) {
47
+ let updatedDtsText = code;
48
+ // Apply substring text deletions from back to front to keep offset indexes accurate
49
+ replacementIntervals.sort((a, b) => b.start - a.start);
50
+
51
+ for (const interval of replacementIntervals) {
52
+ updatedDtsText = updatedDtsText.slice(0, interval.start) + updatedDtsText.slice(interval.end);
53
+ }
54
+
55
+ await fs.writeFile(dtsPath, updatedDtsText, 'utf8');
56
+ }
57
+ } catch {
58
+ // Declaration file variation target absent; proceed to fallback check routes
59
+ }
60
+ }
61
+ }
62
+
63
+ inspectDtsNodes(node, matchSymbol, intervals) {
64
+ if (!node) return;
65
+
66
+ // Match type mutations inside ambient structural parameters
67
+ if (ts.isExportSpecifier(node) && node.name.text === matchSymbol) {
68
+ intervals.push({ start: node.getStart(), end: node.getEnd() });
69
+ } else if ((ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node)) && node.name && node.name.text === matchSymbol) {
70
+ intervals.push({ start: node.getStart(), end: node.getEnd() });
71
+ }
72
+
73
+ ts.forEachChild(node, child => this.inspectDtsNodes(child, matchSymbol, intervals));
74
+ }
75
+ }
@@ -0,0 +1,131 @@
1
+ import resolve from 'enhanced-resolve';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Industrial-Strength Module Resolution Supervisor
6
+ * Integrates path mapping and workspace topologies using enhanced-resolve.
7
+ */
8
+ export class DependencyResolver {
9
+ constructor(context, pathMapper, workspaceGraph) {
10
+ this.context = context;
11
+ this.pathMapper = pathMapper;
12
+ this.workspaceGraph = workspaceGraph;
13
+
14
+ // Instantiate production-grade enhanced-resolve workspace parameters
15
+ this.nativeResolver = resolve.create.sync({
16
+ conditionNames: ['import', 'module', 'require', 'node', 'types'],
17
+ extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json', '.vue'],
18
+ mainFields: ['module', 'main', 'types'],
19
+ exportsFields: ['exports'],
20
+ symlinks: true
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Resolves a raw import string from a source file into an absolute file path.
26
+ * @param {string} containingFile - Absolute path of the file containing the import declaration
27
+ * @param {string} importSpecifier - Raw import target string (e.g., '../components/Button' or '@utils/math')
28
+ * @returns {string|null} Resolved absolute file path location on disk, or null if external/third-party node_module
29
+ */
30
+ resolveModulePath(containingFile, importSpecifier) {
31
+ // Challenge #16: Ignore built-in Node.js modules (fs, path, etc.)
32
+ if (importSpecifier.startsWith('node:') || [
33
+ 'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console', 'constants',
34
+ 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'fs/promises', 'http', 'http2',
35
+ 'https', 'inspector', 'module', 'net', 'os', 'path', 'perf_hooks', 'process',
36
+ 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder',
37
+ 'timers', 'tls', 'trace_events', 'tty', 'url', 'util', 'v8', 'vm', 'worker_threads', 'zlib'
38
+ ].includes(importSpecifier)) {
39
+ return null;
40
+ }
41
+
42
+ const containingDir = path.dirname(containingFile);
43
+
44
+ // Rule A: Intercept and resolve local monorepo workspace cross-links
45
+ if (this.workspaceGraph.isLocalWorkspaceSpecifier(importSpecifier)) {
46
+ const match = this.workspaceGraph.getWorkspacePackageMatch(importSpecifier);
47
+ if (match) {
48
+ if (importSpecifier === match.packageName) {
49
+ // Point directly to the target package's configured index entry file
50
+ return match.entryPoints[0] || null;
51
+ }
52
+
53
+ // Handle deep sub-path monorepo target imports
54
+ const subPathOffset = importSpecifier.slice(match.packageName.length + 1);
55
+ try {
56
+ return this.nativeResolver(match.rootDirectory, `./${subPathOffset}`);
57
+ } catch {
58
+ // Fall back to scanning the package root directly if the sub-path lookup fails
59
+ }
60
+ }
61
+ }
62
+
63
+ // Rule B: Intercept and expand path mapping aliases (@/*)
64
+ const aliasedCandidates = this.pathMapper.resolveCandidatePaths(importSpecifier);
65
+ if (aliasedCandidates.length > 0) {
66
+ for (const candidate of aliasedCandidates) {
67
+ try {
68
+ const resolvedPath = this.nativeResolver(containingDir, candidate);
69
+ if (this.isAbsoluteInternalPath(resolvedPath)) {
70
+ return resolvedPath;
71
+ }
72
+ } catch {
73
+ // Candidate target path absent; try the next fallback pattern entry
74
+ }
75
+ }
76
+ }
77
+
78
+ // Rule C: Standard file system lookups for standard files or package assets
79
+ try {
80
+ const resolvedPath = this.nativeResolver(containingDir, importSpecifier);
81
+ if (this.isAbsoluteInternalPath(resolvedPath)) {
82
+ return resolvedPath;
83
+ }
84
+ } catch (err) {
85
+ if (this.context.verbose) {
86
+ // Output trace logs for unresolvable dependencies during deep code investigations
87
+ console.debug(`[Resolution Trace Skip] Specifier unresolvable from context: ${importSpecifier} inside ${containingFile}`);
88
+ }
89
+ }
90
+
91
+ return null; // Target is an external node_module dependency or an unresolvable asset
92
+ }
93
+
94
+ /**
95
+ * Ensures our tracking focus stays locked onto internal codebase components, bypassing third-party node_modules.
96
+ */
97
+ isAbsoluteInternalPath(resolvedPath) {
98
+ if (!resolvedPath) return false;
99
+ const normalized = resolvedPath.replace(/\\/g, '/');
100
+
101
+ // Ignore external node_modules blocks, but preserve local monorepo packages that live inside symlinked node_modules
102
+ if (normalized.includes('/node_modules/')) {
103
+ for (const [name, meta] of this.workspaceGraph.packageManifests.entries()) {
104
+ if (normalized.startsWith(meta.rootDirectory.replace(/\\/g, '/'))) {
105
+ return true;
106
+ }
107
+ }
108
+ return false;
109
+ }
110
+
111
+ return path.isAbsolute(resolvedPath);
112
+ }
113
+
114
+ /**
115
+ * Challenge #17 Intent Detection. Evaluates if an export serves as a consumer contract distribution node.
116
+ */
117
+ determineIntentProfile(filePath, declaredExportsManifest) {
118
+ const fileName = path.basename(filePath);
119
+ const isPublicContractFile = /(^index|^public\-api|^entry)\.(ts|js|tsx|jsx)$/i.test(fileName);
120
+
121
+ // If the file is a primary bundle entry point, flag its exports as protected public contracts
122
+ if (isPublicContractFile) {
123
+ for (const [symbolKey, metadata] of declaredExportsManifest.entries()) {
124
+ metadata.isLibraryContract = true;
125
+ }
126
+ return 'LIBRARY_CONSUMPTION_TARGET';
127
+ }
128
+
129
+ return 'INTERNAL_CODEBASE_ELEMENT';
130
+ }
131
+ }
@@ -0,0 +1,115 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Advanced TSConfig / JSConfig Compilation Path Alias Mapper
6
+ * Resolves deeply nested route mappings, wildcards, and base URL overrides.
7
+ */
8
+ export class PathMapper {
9
+ constructor(context) {
10
+ this.context = context;
11
+ this.baseUrl = '.';
12
+ this.absoluteBaseUrl = context.cwd;
13
+ this.mappings = []; // Collection of { prefix, suffix, targets[] }
14
+ }
15
+
16
+ /**
17
+ * Reads, cleans, and indexes custom alias entries from tsconfig.json files.
18
+ * @param {string} tsconfigFilename - Target designator (typically tsconfig.json)
19
+ */
20
+ async loadMappings(tsconfigFilename = 'tsconfig.json') {
21
+ const configPath = path.resolve(this.context.cwd, tsconfigFilename);
22
+
23
+ try {
24
+ await fs.access(configPath);
25
+ const rawText = await fs.readFile(configPath, 'utf8');
26
+
27
+ // Strip inline single-line and block comments before parsing
28
+ const jsonCleanText = rawText.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1');
29
+ const tsconfig = JSON.parse(jsonCleanText);
30
+
31
+ if (!tsconfig.compilerOptions) return;
32
+
33
+ const opts = tsconfig.compilerOptions;
34
+ if (opts.baseUrl) {
35
+ this.baseUrl = opts.baseUrl;
36
+ this.absoluteBaseUrl = path.resolve(this.context.cwd, this.baseUrl);
37
+ }
38
+
39
+ if (opts.paths) {
40
+ for (const [aliasPattern, targetArrays] of Object.entries(opts.paths)) {
41
+ this.registerPatternRule(aliasPattern, targetArrays);
42
+ }
43
+ }
44
+ } catch (error) {
45
+ if (this.context.verbose) {
46
+ console.warn(`⚠️ [PathMapper Override] Proceeding without custom path configurations. Source: ${error.message}`);
47
+ }
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Registers structural lookup parameters for alias strings.
53
+ */
54
+ registerPatternRule(pattern, targets) {
55
+ const wildcardIndex = pattern.indexOf('*');
56
+
57
+ if (wildcardIndex === -1) {
58
+ this.mappings.push({
59
+ isExact: true,
60
+ pattern,
61
+ targets: targets.map(t => path.normalize(t))
62
+ });
63
+ return;
64
+ }
65
+
66
+ const prefix = pattern.slice(0, wildcardIndex);
67
+ const suffix = pattern.slice(wildcardIndex + 1);
68
+
69
+ this.mappings.push({
70
+ isExact: false,
71
+ prefix,
72
+ suffix,
73
+ targets: targets.map(t => path.normalize(t))
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Resolves a raw import specifier against mapped path patterns.
79
+ * @param {string} specifier - Raw text from import declaration (e.g., '@ui/button')
80
+ * @returns {Array<string>} Candidates of absolute filesystem paths to try resolving
81
+ */
82
+ resolveCandidatePaths(specifier) {
83
+ const matchingCandidates = [];
84
+
85
+ for (const rule of this.mappings) {
86
+ if (rule.isExact) {
87
+ if (specifier === rule.pattern) {
88
+ rule.targets.forEach(target => {
89
+ matchingCandidates.push(path.resolve(this.absoluteBaseUrl, target));
90
+ });
91
+ }
92
+ } else {
93
+ // Evaluate wildcard pattern matches
94
+ if (specifier.startsWith(rule.prefix) && specifier.endsWith(rule.suffix)) {
95
+ const extractedWildcardContent = specifier.slice(
96
+ rule.prefix.length,
97
+ specifier.length - rule.suffix.length
98
+ );
99
+
100
+ rule.targets.forEach(targetTemplate => {
101
+ const interpolatedTarget = targetTemplate.replace('*', extractedWildcardContent);
102
+ matchingCandidates.push(path.resolve(this.absoluteBaseUrl, interpolatedTarget));
103
+ });
104
+ }
105
+ }
106
+ }
107
+
108
+ // Fall back to direct lookup relative to the base URL
109
+ if (!specifier.startsWith('.') && !path.isAbsolute(specifier)) {
110
+ matchingCandidates.push(path.resolve(this.absoluteBaseUrl, specifier));
111
+ }
112
+
113
+ return matchingCandidates;
114
+ }
115
+ }
@@ -0,0 +1,171 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ // Native sub-directory crawling removed as it's not in fs/promises in older node, but we use readdir anyway.
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
+ }