@norrix/cli 0.0.25 → 0.0.27
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/CHANGELOG.md +42 -0
- package/dist/cli.js +98 -7
- package/dist/cli.js.map +1 -1
- package/dist/lib/amplify-config.js +0 -1
- package/dist/lib/cli-settings.d.ts +15 -0
- package/dist/lib/cli-settings.js +50 -0
- package/dist/lib/cli-settings.js.map +1 -0
- package/dist/lib/commands.d.ts +74 -4
- package/dist/lib/commands.js +952 -109
- package/dist/lib/commands.js.map +1 -1
- package/dist/lib/config-helpers.spec.js +8 -0
- package/dist/lib/config.d.ts +50 -0
- package/dist/lib/config.js +41 -5
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/defaults.js +0 -1
- package/dist/lib/dev-defaults.js +0 -1
- package/dist/lib/fingerprinting.js +0 -1
- package/dist/lib/norrix-cli.js +0 -1
- package/dist/lib/prod-defaults.js +0 -1
- package/dist/lib/workspace.d.ts +18 -1
- package/dist/lib/workspace.js +378 -24
- package/dist/lib/workspace.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/defaults.js
CHANGED
package/dist/lib/dev-defaults.js
CHANGED
|
@@ -265,4 +265,3 @@ export function writeRuntimeFingerprintFile(projectRoot, fingerprint, _platform)
|
|
|
265
265
|
// If needed in the future, we can add helpers to read the
|
|
266
266
|
// runtime fingerprint file from the app source tree, but for
|
|
267
267
|
// now only the build-time writer is required.
|
|
268
|
-
//# sourceMappingURL=fingerprinting.js.map
|
package/dist/lib/norrix-cli.js
CHANGED
package/dist/lib/workspace.d.ts
CHANGED
|
@@ -48,6 +48,15 @@ export interface NxProjectInfo {
|
|
|
48
48
|
implicitDependencies?: string[];
|
|
49
49
|
tags?: string[];
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Available Nx build configurations for a project
|
|
53
|
+
*/
|
|
54
|
+
export interface NxBuildConfigurations {
|
|
55
|
+
/** List of configuration names (e.g., ['prod', 'stg', 'dev']) */
|
|
56
|
+
configurations: string[];
|
|
57
|
+
/** The default configuration if specified in project.json */
|
|
58
|
+
defaultConfiguration?: string;
|
|
59
|
+
}
|
|
51
60
|
export interface WorkspaceDependencies {
|
|
52
61
|
/** Relative paths to lib directories that the app depends on */
|
|
53
62
|
libPaths: string[];
|
|
@@ -57,17 +66,25 @@ export interface WorkspaceDependencies {
|
|
|
57
66
|
toolPaths: string[];
|
|
58
67
|
/** Asset paths referenced by the app */
|
|
59
68
|
assetPaths: string[];
|
|
69
|
+
/** Local file dependencies from package.json (file: protocol paths) */
|
|
70
|
+
localFileDeps: string[];
|
|
60
71
|
}
|
|
61
72
|
/**
|
|
62
73
|
* Detect the workspace context from the current working directory.
|
|
63
74
|
* Walks up the directory tree looking for nx.json to identify Nx workspaces.
|
|
64
75
|
*/
|
|
65
76
|
export declare function detectWorkspaceContext(appRoot?: string): WorkspaceContext;
|
|
77
|
+
/**
|
|
78
|
+
* Detect available Nx build configurations from project.json.
|
|
79
|
+
* Reads the 'build' target's configurations to find options like 'prod', 'stg', 'dev'.
|
|
80
|
+
*/
|
|
81
|
+
export declare function detectNxBuildConfigurations(appRoot: string): NxBuildConfigurations | undefined;
|
|
66
82
|
/**
|
|
67
83
|
* Query Nx for the project dependency graph.
|
|
68
84
|
* Returns the list of lib paths that the specified project depends on.
|
|
85
|
+
* Also supplements with webpack alias detection for SCSS and other non-TS dependencies.
|
|
69
86
|
*/
|
|
70
|
-
export declare function getNxProjectDependencies(projectName: string, workspaceRoot: string, verbose?: boolean): WorkspaceDependencies | undefined;
|
|
87
|
+
export declare function getNxProjectDependencies(projectName: string, workspaceRoot: string, verbose?: boolean, appRoot?: string): WorkspaceDependencies | undefined;
|
|
71
88
|
/**
|
|
72
89
|
* Get project info using nx show project command
|
|
73
90
|
*/
|
package/dist/lib/workspace.js
CHANGED
|
@@ -59,6 +59,34 @@ function detectProjectName(appRoot) {
|
|
|
59
59
|
}
|
|
60
60
|
return undefined;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Detect available Nx build configurations from project.json.
|
|
64
|
+
* Reads the 'build' target's configurations to find options like 'prod', 'stg', 'dev'.
|
|
65
|
+
*/
|
|
66
|
+
export function detectNxBuildConfigurations(appRoot) {
|
|
67
|
+
const projectJsonPath = path.join(appRoot, 'project.json');
|
|
68
|
+
if (!fs.existsSync(projectJsonPath)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const projectJson = JSON.parse(fs.readFileSync(projectJsonPath, 'utf8'));
|
|
73
|
+
const buildTarget = projectJson.targets?.build;
|
|
74
|
+
if (!buildTarget || !buildTarget.configurations) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const configurations = Object.keys(buildTarget.configurations);
|
|
78
|
+
if (configurations.length === 0) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
configurations,
|
|
83
|
+
defaultConfiguration: buildTarget.defaultConfiguration,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
62
90
|
/**
|
|
63
91
|
* Load TypeScript path mappings from tsconfig.base.json
|
|
64
92
|
*/
|
|
@@ -81,8 +109,9 @@ function loadPathMappings(workspaceRoot) {
|
|
|
81
109
|
/**
|
|
82
110
|
* Query Nx for the project dependency graph.
|
|
83
111
|
* Returns the list of lib paths that the specified project depends on.
|
|
112
|
+
* Also supplements with webpack alias detection for SCSS and other non-TS dependencies.
|
|
84
113
|
*/
|
|
85
|
-
export function getNxProjectDependencies(projectName, workspaceRoot, verbose = false) {
|
|
114
|
+
export function getNxProjectDependencies(projectName, workspaceRoot, verbose = false, appRoot) {
|
|
86
115
|
try {
|
|
87
116
|
// Check if nx is available
|
|
88
117
|
execSync('npx nx --version', {
|
|
@@ -101,27 +130,44 @@ export function getNxProjectDependencies(projectName, workspaceRoot, verbose = f
|
|
|
101
130
|
// Extract all dependencies for the project (recursive)
|
|
102
131
|
const allDeps = collectAllDependencies(projectName, graph);
|
|
103
132
|
if (verbose) {
|
|
104
|
-
console.log(`[workspace]
|
|
133
|
+
console.log(`[workspace] Nx graph found ${allDeps.size} dependencies for ${projectName}`);
|
|
105
134
|
}
|
|
106
135
|
// Convert to paths
|
|
107
|
-
const libPaths =
|
|
136
|
+
const libPaths = new Set();
|
|
108
137
|
for (const depName of allDeps) {
|
|
109
138
|
const node = graph.graph.nodes[depName];
|
|
110
139
|
if (node && node.data.root) {
|
|
111
|
-
libPaths.
|
|
140
|
+
libPaths.add(node.data.root);
|
|
112
141
|
}
|
|
113
142
|
}
|
|
143
|
+
// Supplement with webpack alias detection (catches SCSS and other non-TS dependencies)
|
|
144
|
+
// The Nx graph may miss webpack-only aliases that aren't in tsconfig
|
|
145
|
+
if (appRoot) {
|
|
146
|
+
const webpackRefs = parseWebpackReferences(appRoot, workspaceRoot, verbose);
|
|
147
|
+
for (const ref of webpackRefs) {
|
|
148
|
+
if (!libPaths.has(ref)) {
|
|
149
|
+
libPaths.add(ref);
|
|
150
|
+
if (verbose) {
|
|
151
|
+
console.log(`[workspace] Added webpack alias dependency: ${ref}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Scan package.json for local file dependencies
|
|
157
|
+
const localFileDeps = scanLocalFileDependencies(workspaceRoot, verbose);
|
|
114
158
|
return {
|
|
115
|
-
libPaths,
|
|
159
|
+
libPaths: Array.from(libPaths),
|
|
116
160
|
rootConfigs: [
|
|
117
161
|
'nx.json',
|
|
118
162
|
'tsconfig.base.json',
|
|
119
163
|
'package.json',
|
|
120
164
|
'package-lock.json',
|
|
121
165
|
'.npmrc',
|
|
166
|
+
'references.d.ts', // NativeScript global type definitions
|
|
122
167
|
],
|
|
123
168
|
toolPaths: ['tools/'],
|
|
124
|
-
assetPaths: ['libs/assets/'],
|
|
169
|
+
assetPaths: ['libs/assets/', 'packages/assets/'],
|
|
170
|
+
localFileDeps,
|
|
125
171
|
};
|
|
126
172
|
}
|
|
127
173
|
catch (error) {
|
|
@@ -186,8 +232,8 @@ export function getWorkspaceDependenciesFallback(workspaceCtx, verbose = false)
|
|
|
186
232
|
}
|
|
187
233
|
}
|
|
188
234
|
}
|
|
189
|
-
// 2. Parse webpack.config.js for additional references
|
|
190
|
-
const webpackRefs = parseWebpackReferences(workspaceCtx.appRoot, workspaceCtx.workspaceRoot);
|
|
235
|
+
// 2. Parse webpack.config.js for additional references (includes SCSS aliases)
|
|
236
|
+
const webpackRefs = parseWebpackReferences(workspaceCtx.appRoot, workspaceCtx.workspaceRoot, verbose);
|
|
191
237
|
for (const ref of webpackRefs) {
|
|
192
238
|
libPaths.add(ref);
|
|
193
239
|
}
|
|
@@ -196,22 +242,195 @@ export function getWorkspaceDependenciesFallback(workspaceCtx, verbose = false)
|
|
|
196
242
|
for (const ref of hookRefs) {
|
|
197
243
|
libPaths.add(ref);
|
|
198
244
|
}
|
|
199
|
-
|
|
200
|
-
|
|
245
|
+
// 4. Parse project.json for implicit dependencies
|
|
246
|
+
const implicitDeps = parseImplicitDependencies(workspaceCtx.appRoot, workspaceCtx.workspaceRoot, verbose);
|
|
247
|
+
for (const dep of implicitDeps) {
|
|
248
|
+
libPaths.add(dep);
|
|
249
|
+
}
|
|
250
|
+
// 5. Recursively scan lib dependencies to find transitive deps
|
|
251
|
+
if (workspaceCtx.pathMappings) {
|
|
252
|
+
const initialLibCount = libPaths.size;
|
|
253
|
+
scanTransitiveLibDependencies(Array.from(libPaths), workspaceCtx.workspaceRoot, workspaceCtx.pathMappings, libPaths, verbose);
|
|
254
|
+
if (verbose && libPaths.size > initialLibCount) {
|
|
255
|
+
console.log(`[workspace] Found ${libPaths.size - initialLibCount} transitive lib dependencies`);
|
|
256
|
+
}
|
|
201
257
|
}
|
|
258
|
+
if (verbose) {
|
|
259
|
+
console.log(`[workspace] Fallback found ${libPaths.size} total lib dependencies`);
|
|
260
|
+
}
|
|
261
|
+
// 6. Scan package.json for local file dependencies
|
|
262
|
+
const allLocalFileDeps = scanLocalFileDependencies(workspaceCtx.workspaceRoot, verbose);
|
|
263
|
+
// Filter out local file deps that are already covered by libPaths to avoid duplicates
|
|
264
|
+
const libPathsArray = Array.from(libPaths);
|
|
265
|
+
const localFileDeps = allLocalFileDeps.filter(localDep => {
|
|
266
|
+
for (const libPath of libPathsArray) {
|
|
267
|
+
// Skip if local dep is inside a lib path or vice versa
|
|
268
|
+
if (localDep.startsWith(libPath + '/') || localDep === libPath ||
|
|
269
|
+
libPath.startsWith(localDep + '/')) {
|
|
270
|
+
if (verbose) {
|
|
271
|
+
console.log(`[workspace] Filtering redundant local dep: ${localDep} (covered by ${libPath})`);
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return true;
|
|
277
|
+
});
|
|
202
278
|
return {
|
|
203
|
-
libPaths:
|
|
279
|
+
libPaths: libPathsArray,
|
|
204
280
|
rootConfigs: [
|
|
205
281
|
'nx.json',
|
|
206
282
|
'tsconfig.base.json',
|
|
207
283
|
'package.json',
|
|
208
284
|
'package-lock.json',
|
|
209
285
|
'.npmrc',
|
|
286
|
+
'references.d.ts', // NativeScript global type definitions
|
|
210
287
|
],
|
|
211
288
|
toolPaths: ['tools/'],
|
|
212
|
-
assetPaths: ['libs/assets/'],
|
|
289
|
+
assetPaths: ['libs/assets/', 'packages/assets/'],
|
|
290
|
+
localFileDeps,
|
|
213
291
|
};
|
|
214
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Parse project.json for implicit dependencies.
|
|
295
|
+
* These are libs explicitly declared as dependencies in the Nx project config.
|
|
296
|
+
*/
|
|
297
|
+
function parseImplicitDependencies(appRoot, workspaceRoot, verbose = false) {
|
|
298
|
+
const deps = [];
|
|
299
|
+
const projectJsonPath = path.join(appRoot, 'project.json');
|
|
300
|
+
if (!fs.existsSync(projectJsonPath)) {
|
|
301
|
+
return deps;
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
const content = fs.readFileSync(projectJsonPath, 'utf8');
|
|
305
|
+
const projectJson = JSON.parse(content);
|
|
306
|
+
const implicitDeps = projectJson.implicitDependencies;
|
|
307
|
+
if (Array.isArray(implicitDeps)) {
|
|
308
|
+
for (const depName of implicitDeps) {
|
|
309
|
+
// Try to find the lib path by scanning for project.json with this name
|
|
310
|
+
const libPath = findLibPathByProjectName(depName, workspaceRoot);
|
|
311
|
+
if (libPath) {
|
|
312
|
+
deps.push(libPath);
|
|
313
|
+
if (verbose) {
|
|
314
|
+
console.log(`[workspace] Found implicit dependency: ${depName} -> ${libPath}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// Ignore parse errors
|
|
322
|
+
}
|
|
323
|
+
return deps;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Find a lib's path by its Nx project name.
|
|
327
|
+
* Scans libs/ and packages/ directories for project.json files with matching name.
|
|
328
|
+
*/
|
|
329
|
+
function findLibPathByProjectName(projectName, workspaceRoot) {
|
|
330
|
+
// Cache of project name -> lib path mappings (built on first call)
|
|
331
|
+
const projectNameCache = buildProjectNameCache(workspaceRoot);
|
|
332
|
+
return projectNameCache.get(projectName);
|
|
333
|
+
}
|
|
334
|
+
// Module-level cache for project name mappings
|
|
335
|
+
let _projectNameCache;
|
|
336
|
+
let _projectNameCacheRoot;
|
|
337
|
+
function buildProjectNameCache(workspaceRoot) {
|
|
338
|
+
// Return cached version if same workspace
|
|
339
|
+
if (_projectNameCache && _projectNameCacheRoot === workspaceRoot) {
|
|
340
|
+
return _projectNameCache;
|
|
341
|
+
}
|
|
342
|
+
const cache = new Map();
|
|
343
|
+
// Scan both libs/ and packages/ directories (common Nx workspace layouts)
|
|
344
|
+
const sharedDirs = ['libs', 'packages'];
|
|
345
|
+
for (const dir of sharedDirs) {
|
|
346
|
+
const sharedPath = path.join(workspaceRoot, dir);
|
|
347
|
+
if (fs.existsSync(sharedPath)) {
|
|
348
|
+
scanForProjectJsonFiles(sharedPath, workspaceRoot, cache);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
_projectNameCache = cache;
|
|
352
|
+
_projectNameCacheRoot = workspaceRoot;
|
|
353
|
+
return cache;
|
|
354
|
+
}
|
|
355
|
+
function scanForProjectJsonFiles(dir, workspaceRoot, cache) {
|
|
356
|
+
try {
|
|
357
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
358
|
+
for (const entry of entries) {
|
|
359
|
+
if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const fullPath = path.join(dir, entry.name);
|
|
363
|
+
if (entry.isDirectory()) {
|
|
364
|
+
// Check for project.json in this directory
|
|
365
|
+
const projectJsonPath = path.join(fullPath, 'project.json');
|
|
366
|
+
if (fs.existsSync(projectJsonPath)) {
|
|
367
|
+
try {
|
|
368
|
+
const content = fs.readFileSync(projectJsonPath, 'utf8');
|
|
369
|
+
const projectJson = JSON.parse(content);
|
|
370
|
+
if (projectJson.name) {
|
|
371
|
+
const relativePath = path.relative(workspaceRoot, fullPath);
|
|
372
|
+
cache.set(projectJson.name, relativePath);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Ignore parse errors
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Continue scanning subdirectories
|
|
380
|
+
scanForProjectJsonFiles(fullPath, workspaceRoot, cache);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
// Ignore directory read errors
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Recursively scan libs for their dependencies on other libs.
|
|
390
|
+
* This finds transitive dependencies that the app doesn't directly import.
|
|
391
|
+
*/
|
|
392
|
+
function scanTransitiveLibDependencies(initialLibPaths, workspaceRoot, pathMappings, allLibPaths, verbose = false) {
|
|
393
|
+
const toScan = [...initialLibPaths];
|
|
394
|
+
const scanned = new Set();
|
|
395
|
+
while (toScan.length > 0) {
|
|
396
|
+
const libPath = toScan.pop();
|
|
397
|
+
if (scanned.has(libPath)) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
scanned.add(libPath);
|
|
401
|
+
const absoluteLibPath = path.join(workspaceRoot, libPath);
|
|
402
|
+
if (!fs.existsSync(absoluteLibPath)) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
// Scan this lib's source files for imports of other path aliases
|
|
406
|
+
const usedAliases = scanForUsedPathAliases(absoluteLibPath, Object.keys(pathMappings), false // Don't verbose for recursive scans
|
|
407
|
+
);
|
|
408
|
+
for (const alias of usedAliases) {
|
|
409
|
+
const paths = pathMappings[alias];
|
|
410
|
+
if (paths && paths.length > 0) {
|
|
411
|
+
const depLibPath = extractLibPath(paths[0]);
|
|
412
|
+
if (depLibPath && !allLibPaths.has(depLibPath)) {
|
|
413
|
+
allLibPaths.add(depLibPath);
|
|
414
|
+
toScan.push(depLibPath);
|
|
415
|
+
if (verbose) {
|
|
416
|
+
console.log(`[workspace] Found transitive dependency: ${libPath} -> ${depLibPath}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Also check the lib's project.json for implicit dependencies
|
|
422
|
+
const implicitDeps = parseImplicitDependencies(absoluteLibPath, workspaceRoot, false);
|
|
423
|
+
for (const dep of implicitDeps) {
|
|
424
|
+
if (!allLibPaths.has(dep)) {
|
|
425
|
+
allLibPaths.add(dep);
|
|
426
|
+
toScan.push(dep);
|
|
427
|
+
if (verbose) {
|
|
428
|
+
console.log(`[workspace] Found transitive implicit dependency: ${libPath} -> ${dep}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
215
434
|
/**
|
|
216
435
|
* Scan source files for path alias imports
|
|
217
436
|
*/
|
|
@@ -263,22 +482,24 @@ function scanForUsedPathAliases(appRoot, aliases, verbose = false) {
|
|
|
263
482
|
*/
|
|
264
483
|
function extractLibPath(mappingPath) {
|
|
265
484
|
// e.g., "libs/xplat/core/src/index.ts" -> "libs/xplat/core"
|
|
485
|
+
// e.g., "packages/shared/utils/src/index.ts" -> "packages/shared/utils"
|
|
266
486
|
// e.g., "libs/xplat/core/src/lib/*" -> "libs/xplat/core"
|
|
267
|
-
const match = mappingPath.match(/^(libs\/[^/]+(?:\/[^/]+)*?)\/src/);
|
|
487
|
+
const match = mappingPath.match(/^((?:libs|packages)\/[^/]+(?:\/[^/]+)*?)\/src/);
|
|
268
488
|
if (match) {
|
|
269
489
|
return match[1];
|
|
270
490
|
}
|
|
271
491
|
// Try simpler pattern
|
|
272
|
-
const simpleMatch = mappingPath.match(/^(libs\/[^/]+(?:\/[^/]+)*)/);
|
|
492
|
+
const simpleMatch = mappingPath.match(/^((?:libs|packages)\/[^/]+(?:\/[^/]+)*)/);
|
|
273
493
|
if (simpleMatch) {
|
|
274
494
|
return simpleMatch[1];
|
|
275
495
|
}
|
|
276
496
|
return undefined;
|
|
277
497
|
}
|
|
278
498
|
/**
|
|
279
|
-
* Parse webpack.config.js for references to workspace paths
|
|
499
|
+
* Parse webpack.config.js for references to workspace paths.
|
|
500
|
+
* Handles both relative path references and resolve.alias configurations.
|
|
280
501
|
*/
|
|
281
|
-
function parseWebpackReferences(appRoot, workspaceRoot) {
|
|
502
|
+
function parseWebpackReferences(appRoot, workspaceRoot, verbose = false) {
|
|
282
503
|
const refs = [];
|
|
283
504
|
const webpackPath = path.join(appRoot, 'webpack.config.js');
|
|
284
505
|
if (!fs.existsSync(webpackPath)) {
|
|
@@ -286,7 +507,7 @@ function parseWebpackReferences(appRoot, workspaceRoot) {
|
|
|
286
507
|
}
|
|
287
508
|
try {
|
|
288
509
|
const content = fs.readFileSync(webpackPath, 'utf8');
|
|
289
|
-
// Look for patterns like '../../../libs/...' or 'tools/...'
|
|
510
|
+
// Look for patterns like '../../../libs/...' or '../../../packages/...' or 'tools/...'
|
|
290
511
|
const relativePathRegex = /['"`](\.\.\/)+([^'"`]+)['"`]/g;
|
|
291
512
|
let match;
|
|
292
513
|
while ((match = relativePathRegex.exec(content)) !== null) {
|
|
@@ -294,11 +515,15 @@ function parseWebpackReferences(appRoot, workspaceRoot) {
|
|
|
294
515
|
const absolutePath = path.resolve(appRoot, relativePath);
|
|
295
516
|
const relativeToWorkspace = path.relative(workspaceRoot, absolutePath);
|
|
296
517
|
if (relativeToWorkspace.startsWith('libs/') ||
|
|
518
|
+
relativeToWorkspace.startsWith('packages/') ||
|
|
297
519
|
relativeToWorkspace.startsWith('tools/')) {
|
|
298
|
-
// Extract the
|
|
299
|
-
const
|
|
300
|
-
if (
|
|
301
|
-
refs.push(
|
|
520
|
+
// Extract the lib directory - need to handle deep paths like libs/xplat/nativescript/scss/src
|
|
521
|
+
const libPath = extractLibPathFromRelative(relativeToWorkspace);
|
|
522
|
+
if (libPath) {
|
|
523
|
+
refs.push(libPath);
|
|
524
|
+
if (verbose) {
|
|
525
|
+
console.log(`[webpack] Found lib reference: ${libPath}`);
|
|
526
|
+
}
|
|
302
527
|
}
|
|
303
528
|
}
|
|
304
529
|
}
|
|
@@ -306,10 +531,31 @@ function parseWebpackReferences(appRoot, workspaceRoot) {
|
|
|
306
531
|
const copyRuleRegex = /from:\s*['"`]([^'"`]+)['"`]/g;
|
|
307
532
|
while ((match = copyRuleRegex.exec(content)) !== null) {
|
|
308
533
|
const fromPath = match[1];
|
|
309
|
-
if (fromPath.includes('libs/')) {
|
|
310
|
-
const libMatch = fromPath.match(/(libs\/[^/]+(?:\/[^/]+)*)/);
|
|
534
|
+
if (fromPath.includes('libs/') || fromPath.includes('packages/')) {
|
|
535
|
+
const libMatch = fromPath.match(/((?:libs|packages)\/[^/]+(?:\/[^/]+)*)/);
|
|
311
536
|
if (libMatch) {
|
|
312
|
-
|
|
537
|
+
const libPath = extractLibPathFromRelative(libMatch[1]);
|
|
538
|
+
if (libPath) {
|
|
539
|
+
refs.push(libPath);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
// Look for webpack resolve.alias patterns like:
|
|
545
|
+
// config.resolve.alias.set('@ups/xplat-scss', resolve(__dirname, '../../../libs/xplat/scss/src/'))
|
|
546
|
+
// or: alias: { '@ups/xplat-scss': path.resolve(...) }
|
|
547
|
+
const aliasSetRegex = /\.alias\.set\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?:resolve|path\.resolve)\s*\([^,]+,\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
548
|
+
while ((match = aliasSetRegex.exec(content)) !== null) {
|
|
549
|
+
const aliasPath = match[2];
|
|
550
|
+
const absolutePath = path.resolve(appRoot, aliasPath);
|
|
551
|
+
const relativeToWorkspace = path.relative(workspaceRoot, absolutePath);
|
|
552
|
+
if (relativeToWorkspace.startsWith('libs/') || relativeToWorkspace.startsWith('packages/')) {
|
|
553
|
+
const libPath = extractLibPathFromRelative(relativeToWorkspace);
|
|
554
|
+
if (libPath) {
|
|
555
|
+
refs.push(libPath);
|
|
556
|
+
if (verbose) {
|
|
557
|
+
console.log(`[webpack] Found alias reference: ${match[1]} -> ${libPath}`);
|
|
558
|
+
}
|
|
313
559
|
}
|
|
314
560
|
}
|
|
315
561
|
}
|
|
@@ -319,6 +565,49 @@ function parseWebpackReferences(appRoot, workspaceRoot) {
|
|
|
319
565
|
}
|
|
320
566
|
return [...new Set(refs)];
|
|
321
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Extract the lib directory from a relative path.
|
|
570
|
+
* Handles paths like:
|
|
571
|
+
* - libs/xplat/scss/src -> libs/xplat/scss
|
|
572
|
+
* - packages/shared/utils/src -> packages/shared/utils
|
|
573
|
+
* - libs/xplat/nativescript/scss/src/ -> libs/xplat/nativescript/scss
|
|
574
|
+
* - libs/assets/mobile/fonts -> libs/assets
|
|
575
|
+
*/
|
|
576
|
+
function extractLibPathFromRelative(relativePath) {
|
|
577
|
+
// Remove trailing slash
|
|
578
|
+
const cleanPath = relativePath.replace(/\/+$/, '');
|
|
579
|
+
// Handle /src or /src/... suffix - find the lib root
|
|
580
|
+
const srcMatch = cleanPath.match(/^((?:libs|packages)\/(?:[^/]+\/)*[^/]+)\/src(?:\/|$)/);
|
|
581
|
+
if (srcMatch) {
|
|
582
|
+
return srcMatch[1];
|
|
583
|
+
}
|
|
584
|
+
// For paths without /src, extract based on common patterns
|
|
585
|
+
// libs/assets -> libs/assets
|
|
586
|
+
// libs/xplat/core -> libs/xplat/core
|
|
587
|
+
// packages/shared -> packages/shared
|
|
588
|
+
if (cleanPath.startsWith('libs/') || cleanPath.startsWith('packages/')) {
|
|
589
|
+
const parts = cleanPath.split('/');
|
|
590
|
+
// Check if this path has a project.json to determine lib boundary
|
|
591
|
+
// For now, use heuristics: assets are at libs/assets, others are deeper
|
|
592
|
+
if (parts[1] === 'assets') {
|
|
593
|
+
return `${parts[0]}/${parts[1]}`;
|
|
594
|
+
}
|
|
595
|
+
// For xplat and other nested structures, typically 3 levels: libs/xplat/core
|
|
596
|
+
// But can be deeper: libs/xplat/nativescript/scss
|
|
597
|
+
// Try to find project.json to determine the actual lib root
|
|
598
|
+
let testPath = '';
|
|
599
|
+
for (let i = 0; i < parts.length; i++) {
|
|
600
|
+
testPath += (i > 0 ? '/' : '') + parts[i];
|
|
601
|
+
// We'll return the deepest valid lib path that's not a 'src' dir
|
|
602
|
+
if (parts[i] === 'src') {
|
|
603
|
+
return parts.slice(0, i).join('/');
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// If no /src found, return up to 4 levels or the full path
|
|
607
|
+
return parts.slice(0, Math.min(parts.length, 4)).join('/');
|
|
608
|
+
}
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
322
611
|
/**
|
|
323
612
|
* Parse nativescript.config.ts for hook script references
|
|
324
613
|
*/
|
|
@@ -351,6 +640,71 @@ function parseNativeScriptHooks(appRoot, workspaceRoot) {
|
|
|
351
640
|
}
|
|
352
641
|
return [...new Set(refs)];
|
|
353
642
|
}
|
|
643
|
+
/**
|
|
644
|
+
* Scan package.json for local file dependencies (file: protocol).
|
|
645
|
+
* Returns an array of relative paths (files or directories) that need to be included in the bundle.
|
|
646
|
+
*/
|
|
647
|
+
function scanLocalFileDependencies(workspaceRoot, verbose = false) {
|
|
648
|
+
const localDeps = new Set();
|
|
649
|
+
const packageJsonPath = path.join(workspaceRoot, 'package.json');
|
|
650
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
651
|
+
return [];
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
655
|
+
// Scan dependencies, devDependencies, and overrides for file: protocol
|
|
656
|
+
const sections = [
|
|
657
|
+
packageJson.dependencies,
|
|
658
|
+
packageJson.devDependencies,
|
|
659
|
+
packageJson.optionalDependencies,
|
|
660
|
+
packageJson.overrides,
|
|
661
|
+
];
|
|
662
|
+
for (const section of sections) {
|
|
663
|
+
if (!section || typeof section !== 'object')
|
|
664
|
+
continue;
|
|
665
|
+
for (const [name, value] of Object.entries(section)) {
|
|
666
|
+
if (typeof value !== 'string')
|
|
667
|
+
continue;
|
|
668
|
+
// Match file: protocol (e.g., "file:libs/xplat/web/plugins/util-0.12.5.tgz")
|
|
669
|
+
if (value.startsWith('file:')) {
|
|
670
|
+
const relativePath = value.slice(5); // Remove 'file:' prefix
|
|
671
|
+
const absolutePath = path.resolve(workspaceRoot, relativePath);
|
|
672
|
+
// Verify the path exists
|
|
673
|
+
if (fs.existsSync(absolutePath)) {
|
|
674
|
+
// If it's a file (like a .tgz), include the directory containing it
|
|
675
|
+
const stat = fs.statSync(absolutePath);
|
|
676
|
+
if (stat.isFile()) {
|
|
677
|
+
// Include the specific file
|
|
678
|
+
localDeps.add(relativePath);
|
|
679
|
+
if (verbose) {
|
|
680
|
+
console.log(`[workspace] Found local file dependency: ${relativePath}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
else if (stat.isDirectory()) {
|
|
684
|
+
// Include the directory
|
|
685
|
+
localDeps.add(relativePath);
|
|
686
|
+
if (verbose) {
|
|
687
|
+
console.log(`[workspace] Found local directory dependency: ${relativePath}`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
else if (verbose) {
|
|
692
|
+
console.log(`[workspace] Warning: Local dependency not found: ${relativePath}`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
catch (error) {
|
|
699
|
+
if (verbose) {
|
|
700
|
+
console.log(`[workspace] Error scanning package.json for local deps: ${error?.message}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (verbose && localDeps.size > 0) {
|
|
704
|
+
console.log(`[workspace] Found ${localDeps.size} local file dependencies`);
|
|
705
|
+
}
|
|
706
|
+
return Array.from(localDeps);
|
|
707
|
+
}
|
|
354
708
|
export function createWorkspaceManifest(workspaceCtx, deps) {
|
|
355
709
|
return {
|
|
356
710
|
version: '1.0',
|