@solid-stack/mason 1.0.33 → 1.0.34
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/dist/bin.cjs +493 -382
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +491 -380
- package/dist/bin.js.map +1 -1
- package/dist/core/lintEngine.d.ts +4 -4
- package/dist/core/lintEngine.d.ts.map +1 -1
- package/dist/index.cjs +496 -384
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +494 -383
- package/dist/index.js.map +1 -1
- package/dist/types/lint.d.ts +5 -0
- package/dist/types/lint.d.ts.map +1 -1
- package/dist/utils/config.d.ts +9 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var fs17 = require('fs');
|
|
4
|
+
var path26 = require('path');
|
|
5
5
|
var p19 = require('@clack/prompts');
|
|
6
6
|
var pc14 = require('picocolors');
|
|
7
7
|
var url = require('url');
|
|
@@ -31,8 +31,8 @@ function _interopNamespace(e) {
|
|
|
31
31
|
return Object.freeze(n);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
var
|
|
35
|
-
var
|
|
34
|
+
var fs17__default = /*#__PURE__*/_interopDefault(fs17);
|
|
35
|
+
var path26__default = /*#__PURE__*/_interopDefault(path26);
|
|
36
36
|
var p19__namespace = /*#__PURE__*/_interopNamespace(p19);
|
|
37
37
|
var pc14__default = /*#__PURE__*/_interopDefault(pc14);
|
|
38
38
|
var Handlebars__default = /*#__PURE__*/_interopDefault(Handlebars);
|
|
@@ -105,8 +105,8 @@ function isValidIdentifier(str) {
|
|
|
105
105
|
}
|
|
106
106
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
107
107
|
const projectRoot = options.projectRoot || process.cwd();
|
|
108
|
-
const relPath =
|
|
109
|
-
const existedBefore =
|
|
108
|
+
const relPath = path26__default.default.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
109
|
+
const existedBefore = fs17__default.default.existsSync(absolutePath);
|
|
110
110
|
if (options.dryRun) {
|
|
111
111
|
return {
|
|
112
112
|
relativePath: relPath,
|
|
@@ -125,11 +125,11 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
125
125
|
existedBefore: true
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
|
-
const dir =
|
|
129
|
-
if (!
|
|
130
|
-
|
|
128
|
+
const dir = path26__default.default.dirname(absolutePath);
|
|
129
|
+
if (!fs17__default.default.existsSync(dir)) {
|
|
130
|
+
fs17__default.default.mkdirSync(dir, { recursive: true });
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
fs17__default.default.writeFileSync(absolutePath, content, "utf-8");
|
|
133
133
|
return {
|
|
134
134
|
relativePath: relPath,
|
|
135
135
|
absolutePath,
|
|
@@ -156,17 +156,17 @@ function printGeneratedFiles(files, isDryRun = false) {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
function loadMasonConfig(startDir = process.cwd()) {
|
|
159
|
-
let current =
|
|
159
|
+
let current = path26__default.default.resolve(startDir);
|
|
160
160
|
while (true) {
|
|
161
|
-
const configPath =
|
|
162
|
-
if (
|
|
161
|
+
const configPath = path26__default.default.join(current, "mason.config.json");
|
|
162
|
+
if (fs17__default.default.existsSync(configPath)) {
|
|
163
163
|
try {
|
|
164
|
-
return JSON.parse(
|
|
164
|
+
return JSON.parse(fs17__default.default.readFileSync(configPath, "utf-8"));
|
|
165
165
|
} catch {
|
|
166
166
|
return null;
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
const parent =
|
|
169
|
+
const parent = path26__default.default.dirname(current);
|
|
170
170
|
if (parent === current) break;
|
|
171
171
|
current = parent;
|
|
172
172
|
}
|
|
@@ -176,70 +176,91 @@ function getEffectiveMode(projectRoot, flags) {
|
|
|
176
176
|
if (flags?.registry) return "registry";
|
|
177
177
|
const config = loadMasonConfig(projectRoot);
|
|
178
178
|
if (config?.mode) return config.mode;
|
|
179
|
-
if (
|
|
179
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "index.json")) && (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "features")) || fs17__default.default.existsSync(path26__default.default.join(projectRoot, "shared")) || fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/features")) || fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/shared")))) {
|
|
180
180
|
return "registry";
|
|
181
181
|
}
|
|
182
182
|
return "app";
|
|
183
183
|
}
|
|
184
184
|
function getConfiguredFeaturesDir(projectRoot, flags) {
|
|
185
|
-
if (flags?.target) return
|
|
186
|
-
if (flags?.dest) return
|
|
185
|
+
if (flags?.target) return path26__default.default.resolve(projectRoot, flags.target);
|
|
186
|
+
if (flags?.dest) return path26__default.default.resolve(projectRoot, flags.dest);
|
|
187
187
|
const config = loadMasonConfig(projectRoot);
|
|
188
188
|
if (config?.paths?.features) {
|
|
189
|
-
return
|
|
189
|
+
return path26__default.default.resolve(projectRoot, config.paths.features);
|
|
190
190
|
}
|
|
191
191
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
192
192
|
if (mode === "registry") {
|
|
193
|
-
if (
|
|
194
|
-
return
|
|
193
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/features"))) {
|
|
194
|
+
return path26__default.default.join(projectRoot, "src/features");
|
|
195
195
|
}
|
|
196
|
-
return
|
|
196
|
+
return path26__default.default.join(projectRoot, "features");
|
|
197
197
|
}
|
|
198
|
-
if (
|
|
199
|
-
return
|
|
198
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/features"))) {
|
|
199
|
+
return path26__default.default.join(projectRoot, "src/features");
|
|
200
200
|
}
|
|
201
|
-
return
|
|
201
|
+
return path26__default.default.join(projectRoot, "features");
|
|
202
202
|
}
|
|
203
203
|
function getConfiguredSharedDir(projectRoot, flags) {
|
|
204
|
-
if (flags?.target) return
|
|
205
|
-
if (flags?.dest) return
|
|
204
|
+
if (flags?.target) return path26__default.default.resolve(projectRoot, flags.target);
|
|
205
|
+
if (flags?.dest) return path26__default.default.resolve(projectRoot, flags.dest);
|
|
206
206
|
const config = loadMasonConfig(projectRoot);
|
|
207
207
|
if (config?.paths?.shared) {
|
|
208
|
-
return
|
|
208
|
+
return path26__default.default.resolve(projectRoot, config.paths.shared);
|
|
209
209
|
}
|
|
210
210
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
211
211
|
if (mode === "registry") {
|
|
212
|
-
if (
|
|
213
|
-
return
|
|
212
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/shared"))) {
|
|
213
|
+
return path26__default.default.join(projectRoot, "src/shared");
|
|
214
214
|
}
|
|
215
|
-
return
|
|
215
|
+
return path26__default.default.join(projectRoot, "shared");
|
|
216
216
|
}
|
|
217
|
-
if (
|
|
218
|
-
return
|
|
217
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "src/shared"))) {
|
|
218
|
+
return path26__default.default.join(projectRoot, "src/shared");
|
|
219
219
|
}
|
|
220
|
-
return
|
|
220
|
+
return path26__default.default.join(projectRoot, "shared");
|
|
221
221
|
}
|
|
222
222
|
function loadLintConfig(projectRoot) {
|
|
223
|
-
const configPath =
|
|
224
|
-
if (
|
|
223
|
+
const configPath = path26__default.default.join(projectRoot, "mason-lint.config.json");
|
|
224
|
+
if (fs17__default.default.existsSync(configPath)) {
|
|
225
225
|
try {
|
|
226
|
-
return JSON.parse(
|
|
226
|
+
return JSON.parse(fs17__default.default.readFileSync(configPath, "utf-8"));
|
|
227
227
|
} catch {
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
-
return {
|
|
230
|
+
return {};
|
|
231
|
+
}
|
|
232
|
+
function getResolvedLintPaths(projectRoot, config) {
|
|
233
|
+
const masonConfig = loadMasonConfig(projectRoot);
|
|
234
|
+
const configuredFeatures = config.paths?.features ?? masonConfig?.paths?.features;
|
|
235
|
+
const configuredShared = config.paths?.shared ?? masonConfig?.paths?.shared;
|
|
236
|
+
const configuredErrors = config.paths?.errors;
|
|
237
|
+
const resolveBase = (configuredPath, defaultSrc, defaultRoot) => {
|
|
238
|
+
if (configuredPath !== void 0) {
|
|
239
|
+
return path26__default.default.resolve(projectRoot, configuredPath);
|
|
240
|
+
}
|
|
241
|
+
const srcPath = path26__default.default.join(projectRoot, defaultSrc);
|
|
242
|
+
if (fs17__default.default.existsSync(srcPath)) return srcPath;
|
|
243
|
+
const rootPath = path26__default.default.join(projectRoot, defaultRoot);
|
|
244
|
+
if (fs17__default.default.existsSync(rootPath)) return rootPath;
|
|
245
|
+
return srcPath;
|
|
246
|
+
};
|
|
247
|
+
return {
|
|
248
|
+
featuresBase: resolveBase(configuredFeatures, "src/features", "features"),
|
|
249
|
+
sharedBase: resolveBase(configuredShared, "src/shared", "shared"),
|
|
250
|
+
errorsBase: resolveBase(configuredErrors, "src/errors", "errors")
|
|
251
|
+
};
|
|
231
252
|
}
|
|
232
253
|
|
|
233
254
|
// src/utils/project.ts
|
|
234
255
|
function findProjectRoot(startDir = process.cwd()) {
|
|
235
|
-
let current =
|
|
256
|
+
let current = path26__default.default.resolve(startDir);
|
|
236
257
|
while (true) {
|
|
237
|
-
if (
|
|
258
|
+
if (fs17__default.default.existsSync(path26__default.default.join(current, "package.json"))) {
|
|
238
259
|
return current;
|
|
239
260
|
}
|
|
240
|
-
const parent =
|
|
261
|
+
const parent = path26__default.default.dirname(current);
|
|
241
262
|
if (parent === current) {
|
|
242
|
-
return
|
|
263
|
+
return path26__default.default.resolve(startDir);
|
|
243
264
|
}
|
|
244
265
|
current = parent;
|
|
245
266
|
}
|
|
@@ -252,9 +273,9 @@ function resolveSharedDir(projectRoot, flags) {
|
|
|
252
273
|
}
|
|
253
274
|
function listExistingShared(projectRoot) {
|
|
254
275
|
const sharedDir = resolveSharedDir(projectRoot);
|
|
255
|
-
if (!
|
|
276
|
+
if (!fs17__default.default.existsSync(sharedDir)) return [];
|
|
256
277
|
try {
|
|
257
|
-
const entries =
|
|
278
|
+
const entries = fs17__default.default.readdirSync(sharedDir, { withFileTypes: true });
|
|
258
279
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
259
280
|
} catch {
|
|
260
281
|
return [];
|
|
@@ -262,9 +283,9 @@ function listExistingShared(projectRoot) {
|
|
|
262
283
|
}
|
|
263
284
|
function listExistingFeatures(projectRoot) {
|
|
264
285
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
265
|
-
if (!
|
|
286
|
+
if (!fs17__default.default.existsSync(featuresDir)) return [];
|
|
266
287
|
try {
|
|
267
|
-
const entries =
|
|
288
|
+
const entries = fs17__default.default.readdirSync(featuresDir, { withFileTypes: true });
|
|
268
289
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
269
290
|
} catch {
|
|
270
291
|
return [];
|
|
@@ -274,14 +295,14 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
274
295
|
const results = [];
|
|
275
296
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
276
297
|
for (const feat of features) {
|
|
277
|
-
const domainDir =
|
|
278
|
-
if (!
|
|
298
|
+
const domainDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
299
|
+
if (!fs17__default.default.existsSync(domainDir)) continue;
|
|
279
300
|
try {
|
|
280
|
-
const files =
|
|
301
|
+
const files = fs17__default.default.readdirSync(domainDir);
|
|
281
302
|
for (const file of files) {
|
|
282
303
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
283
304
|
const name = file.replace(/\.ts$/, "");
|
|
284
|
-
const fullPath =
|
|
305
|
+
const fullPath = path26__default.default.join(domainDir, file);
|
|
285
306
|
if (/^I[A-Z]/.test(name)) {
|
|
286
307
|
results.push({
|
|
287
308
|
name,
|
|
@@ -290,7 +311,7 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
290
311
|
});
|
|
291
312
|
} else {
|
|
292
313
|
try {
|
|
293
|
-
const content =
|
|
314
|
+
const content = fs17__default.default.readFileSync(fullPath, "utf-8");
|
|
294
315
|
if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
|
|
295
316
|
results.push({
|
|
296
317
|
name,
|
|
@@ -312,17 +333,17 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
312
333
|
const results = [];
|
|
313
334
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
314
335
|
for (const feat of features) {
|
|
315
|
-
const domainDir =
|
|
316
|
-
if (!
|
|
336
|
+
const domainDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
337
|
+
if (!fs17__default.default.existsSync(domainDir)) continue;
|
|
317
338
|
try {
|
|
318
|
-
const files =
|
|
339
|
+
const files = fs17__default.default.readdirSync(domainDir);
|
|
319
340
|
for (const file of files) {
|
|
320
341
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
321
342
|
const name = file.replace(/\.ts$/, "");
|
|
322
343
|
if (!/^I[A-Z]/.test(name)) {
|
|
323
344
|
results.push({
|
|
324
345
|
name,
|
|
325
|
-
fullPath:
|
|
346
|
+
fullPath: path26__default.default.join(domainDir, file),
|
|
326
347
|
feature: feat
|
|
327
348
|
});
|
|
328
349
|
}
|
|
@@ -337,16 +358,16 @@ function listUseCases(projectRoot, featureName) {
|
|
|
337
358
|
const results = [];
|
|
338
359
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
339
360
|
for (const feat of features) {
|
|
340
|
-
const useCasesDir =
|
|
341
|
-
if (!
|
|
361
|
+
const useCasesDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
362
|
+
if (!fs17__default.default.existsSync(useCasesDir)) continue;
|
|
342
363
|
try {
|
|
343
|
-
const files =
|
|
364
|
+
const files = fs17__default.default.readdirSync(useCasesDir);
|
|
344
365
|
for (const file of files) {
|
|
345
366
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
346
367
|
const name = file.replace(/\.ts$/, "");
|
|
347
368
|
results.push({
|
|
348
369
|
name,
|
|
349
|
-
fullPath:
|
|
370
|
+
fullPath: path26__default.default.join(useCasesDir, file),
|
|
350
371
|
feature: feat
|
|
351
372
|
});
|
|
352
373
|
}
|
|
@@ -458,25 +479,25 @@ function normalizeRegistryUrl(urlOrPath, baseDir) {
|
|
|
458
479
|
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
|
|
459
480
|
}
|
|
460
481
|
if (baseDir && (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed === "." || trimmed === "..")) {
|
|
461
|
-
return
|
|
482
|
+
return path26__default.default.resolve(baseDir, trimmed);
|
|
462
483
|
}
|
|
463
484
|
return trimmed;
|
|
464
485
|
}
|
|
465
486
|
function findLocalRegistry(startDir = process.cwd()) {
|
|
466
|
-
let current =
|
|
487
|
+
let current = path26__default.default.resolve(startDir);
|
|
467
488
|
while (true) {
|
|
468
|
-
const candidate =
|
|
469
|
-
if (
|
|
489
|
+
const candidate = path26__default.default.join(current, "mason-registry");
|
|
490
|
+
if (fs17__default.default.existsSync(candidate) && fs17__default.default.existsSync(path26__default.default.join(candidate, "index.json"))) {
|
|
470
491
|
return candidate;
|
|
471
492
|
}
|
|
472
|
-
const parent =
|
|
493
|
+
const parent = path26__default.default.dirname(current);
|
|
473
494
|
if (parent === current) break;
|
|
474
495
|
current = parent;
|
|
475
496
|
}
|
|
476
497
|
return null;
|
|
477
498
|
}
|
|
478
499
|
function getRegistryBase(projectRoot, override) {
|
|
479
|
-
const rootDir = projectRoot ?
|
|
500
|
+
const rootDir = projectRoot ? path26__default.default.resolve(projectRoot) : process.cwd();
|
|
480
501
|
if (override && override.trim()) {
|
|
481
502
|
return normalizeRegistryUrl(override.trim(), rootDir);
|
|
482
503
|
}
|
|
@@ -484,30 +505,30 @@ function getRegistryBase(projectRoot, override) {
|
|
|
484
505
|
return normalizeRegistryUrl(process.env.MASON_REGISTRY_URL.trim(), rootDir);
|
|
485
506
|
}
|
|
486
507
|
const configLocations = [
|
|
487
|
-
|
|
488
|
-
|
|
508
|
+
path26__default.default.join(rootDir, "mason.config.json"),
|
|
509
|
+
path26__default.default.join(process.cwd(), "mason.config.json")
|
|
489
510
|
];
|
|
490
511
|
for (const configPath of configLocations) {
|
|
491
|
-
if (
|
|
512
|
+
if (fs17__default.default.existsSync(configPath)) {
|
|
492
513
|
try {
|
|
493
|
-
const config = JSON.parse(
|
|
514
|
+
const config = JSON.parse(fs17__default.default.readFileSync(configPath, "utf-8"));
|
|
494
515
|
if (config.registry && typeof config.registry === "string") {
|
|
495
|
-
return normalizeRegistryUrl(config.registry.trim(),
|
|
516
|
+
return normalizeRegistryUrl(config.registry.trim(), path26__default.default.dirname(configPath));
|
|
496
517
|
}
|
|
497
518
|
} catch {
|
|
498
519
|
}
|
|
499
520
|
}
|
|
500
521
|
}
|
|
501
522
|
const pkgLocations = [
|
|
502
|
-
|
|
503
|
-
|
|
523
|
+
path26__default.default.join(rootDir, "package.json"),
|
|
524
|
+
path26__default.default.join(process.cwd(), "package.json")
|
|
504
525
|
];
|
|
505
526
|
for (const pkgPath of pkgLocations) {
|
|
506
|
-
if (
|
|
527
|
+
if (fs17__default.default.existsSync(pkgPath)) {
|
|
507
528
|
try {
|
|
508
|
-
const pkg = JSON.parse(
|
|
529
|
+
const pkg = JSON.parse(fs17__default.default.readFileSync(pkgPath, "utf-8"));
|
|
509
530
|
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
510
|
-
return normalizeRegistryUrl(pkg.mason.registry.trim(),
|
|
531
|
+
return normalizeRegistryUrl(pkg.mason.registry.trim(), path26__default.default.dirname(pkgPath));
|
|
511
532
|
}
|
|
512
533
|
} catch {
|
|
513
534
|
}
|
|
@@ -555,16 +576,16 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
555
576
|
if (baseDir.startsWith("file://")) {
|
|
556
577
|
baseDir = url.fileURLToPath(baseDir);
|
|
557
578
|
}
|
|
558
|
-
let filePath =
|
|
559
|
-
if (!
|
|
560
|
-
const inSrcPath =
|
|
561
|
-
if (
|
|
579
|
+
let filePath = path26__default.default.resolve(baseDir, cleanRelPath);
|
|
580
|
+
if (!fs17__default.default.existsSync(filePath)) {
|
|
581
|
+
const inSrcPath = path26__default.default.resolve(baseDir, "src", cleanRelPath);
|
|
582
|
+
if (fs17__default.default.existsSync(inSrcPath)) {
|
|
562
583
|
filePath = inSrcPath;
|
|
563
584
|
} else {
|
|
564
585
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
565
586
|
}
|
|
566
587
|
}
|
|
567
|
-
return
|
|
588
|
+
return fs17__default.default.promises.readFile(filePath, "utf-8");
|
|
568
589
|
}
|
|
569
590
|
async function fetchRegistryIndex(registryBase) {
|
|
570
591
|
const content = await fetchRegistryFile(registryBase, "index.json");
|
|
@@ -626,19 +647,19 @@ function findClosestMatch(target, candidates) {
|
|
|
626
647
|
return null;
|
|
627
648
|
}
|
|
628
649
|
function detectPackageManager(projectRoot) {
|
|
629
|
-
if (
|
|
630
|
-
if (
|
|
631
|
-
if (
|
|
650
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
651
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
652
|
+
if (fs17__default.default.existsSync(path26__default.default.join(projectRoot, "bun.lockb")) || fs17__default.default.existsSync(path26__default.default.join(projectRoot, "bun.lock"))) return "bun";
|
|
632
653
|
return "npm";
|
|
633
654
|
}
|
|
634
655
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
635
656
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
636
|
-
const pkgJsonPath =
|
|
637
|
-
if (!
|
|
657
|
+
const pkgJsonPath = path26__default.default.join(projectRoot, "package.json");
|
|
658
|
+
if (!fs17__default.default.existsSync(pkgJsonPath)) {
|
|
638
659
|
return requiredPackages;
|
|
639
660
|
}
|
|
640
661
|
try {
|
|
641
|
-
const pkg = JSON.parse(
|
|
662
|
+
const pkg = JSON.parse(fs17__default.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
642
663
|
const installed = /* @__PURE__ */ new Set([
|
|
643
664
|
...Object.keys(pkg.dependencies || {}),
|
|
644
665
|
...Object.keys(pkg.devDependencies || {}),
|
|
@@ -677,12 +698,12 @@ function installNpmPackages(projectRoot, packages, pm) {
|
|
|
677
698
|
});
|
|
678
699
|
}
|
|
679
700
|
function getAllFiles(dir, baseDir = dir) {
|
|
680
|
-
if (!
|
|
681
|
-
const entries =
|
|
701
|
+
if (!fs17__default.default.existsSync(dir)) return [];
|
|
702
|
+
const entries = fs17__default.default.readdirSync(dir, { withFileTypes: true });
|
|
682
703
|
const files = [];
|
|
683
704
|
for (const entry of entries) {
|
|
684
|
-
const fullPath =
|
|
685
|
-
const relPath =
|
|
705
|
+
const fullPath = path26__default.default.join(dir, entry.name);
|
|
706
|
+
const relPath = path26__default.default.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
686
707
|
if (entry.isDirectory()) {
|
|
687
708
|
if (entry.name === "__tests__" || entry.name.startsWith(".")) {
|
|
688
709
|
continue;
|
|
@@ -698,13 +719,13 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
698
719
|
return files.sort();
|
|
699
720
|
}
|
|
700
721
|
function computeDirectoryHash(dirPath, files) {
|
|
701
|
-
if (!
|
|
722
|
+
if (!fs17__default.default.existsSync(dirPath)) return "";
|
|
702
723
|
const hash = crypto.createHash("sha256");
|
|
703
724
|
const fileList = (files ?? getAllFiles(dirPath)).sort();
|
|
704
725
|
for (const relativePath of fileList) {
|
|
705
|
-
const absolutePath =
|
|
706
|
-
if (!
|
|
707
|
-
const content =
|
|
726
|
+
const absolutePath = path26__default.default.join(dirPath, relativePath);
|
|
727
|
+
if (!fs17__default.default.existsSync(absolutePath)) continue;
|
|
728
|
+
const content = fs17__default.default.readFileSync(absolutePath, "utf8");
|
|
708
729
|
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
709
730
|
hash.update(relativePath);
|
|
710
731
|
hash.update(normalizedContent);
|
|
@@ -727,33 +748,33 @@ hbs.registerHelper("join", (arr, sep) => {
|
|
|
727
748
|
});
|
|
728
749
|
var cachedTemplatesDir = null;
|
|
729
750
|
function getTemplatesDir() {
|
|
730
|
-
if (cachedTemplatesDir &&
|
|
751
|
+
if (cachedTemplatesDir && fs17__default.default.existsSync(cachedTemplatesDir)) {
|
|
731
752
|
return cachedTemplatesDir;
|
|
732
753
|
}
|
|
733
|
-
const currentDir = typeof __dirname !== "undefined" ? __dirname :
|
|
734
|
-
const cand1 =
|
|
735
|
-
if (
|
|
754
|
+
const currentDir = typeof __dirname !== "undefined" ? __dirname : path26__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
755
|
+
const cand1 = path26__default.default.resolve(currentDir, "../../templates");
|
|
756
|
+
if (fs17__default.default.existsSync(cand1)) {
|
|
736
757
|
cachedTemplatesDir = cand1;
|
|
737
758
|
return cand1;
|
|
738
759
|
}
|
|
739
|
-
const cand2 =
|
|
740
|
-
if (
|
|
760
|
+
const cand2 = path26__default.default.resolve(currentDir, "../templates");
|
|
761
|
+
if (fs17__default.default.existsSync(cand2)) {
|
|
741
762
|
cachedTemplatesDir = cand2;
|
|
742
763
|
return cand2;
|
|
743
764
|
}
|
|
744
|
-
const cand3 =
|
|
745
|
-
if (
|
|
765
|
+
const cand3 = path26__default.default.resolve(currentDir, "templates");
|
|
766
|
+
if (fs17__default.default.existsSync(cand3)) {
|
|
746
767
|
cachedTemplatesDir = cand3;
|
|
747
768
|
return cand3;
|
|
748
769
|
}
|
|
749
770
|
let curr = currentDir;
|
|
750
771
|
while (true) {
|
|
751
|
-
const candTemplates =
|
|
752
|
-
if (
|
|
772
|
+
const candTemplates = path26__default.default.join(curr, "templates");
|
|
773
|
+
if (fs17__default.default.existsSync(candTemplates)) {
|
|
753
774
|
cachedTemplatesDir = candTemplates;
|
|
754
775
|
return candTemplates;
|
|
755
776
|
}
|
|
756
|
-
const parent =
|
|
777
|
+
const parent = path26__default.default.dirname(curr);
|
|
757
778
|
if (parent === curr) break;
|
|
758
779
|
curr = parent;
|
|
759
780
|
}
|
|
@@ -761,8 +782,8 @@ function getTemplatesDir() {
|
|
|
761
782
|
}
|
|
762
783
|
var templateCache = /* @__PURE__ */ new Map();
|
|
763
784
|
function loadTemplate(relativePath) {
|
|
764
|
-
const fullPath =
|
|
765
|
-
return
|
|
785
|
+
const fullPath = path26__default.default.isAbsolute(relativePath) ? relativePath : path26__default.default.join(getTemplatesDir(), relativePath);
|
|
786
|
+
return fs17__default.default.readFileSync(fullPath, "utf-8");
|
|
766
787
|
}
|
|
767
788
|
function renderTemplateFile(relativePath, context) {
|
|
768
789
|
let compiled = templateCache.get(relativePath);
|
|
@@ -847,8 +868,8 @@ function generateDomainEntityCode(name, kind = "interface", properties = []) {
|
|
|
847
868
|
function generateDomain(options) {
|
|
848
869
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
849
870
|
const entityName = toPascalCase(options.name);
|
|
850
|
-
const targetDir = options.targetDir ||
|
|
851
|
-
const filePath =
|
|
871
|
+
const targetDir = options.targetDir || path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
872
|
+
const filePath = path26__default.default.join(targetDir, `${entityName}.ts`);
|
|
852
873
|
const code = generateDomainEntityCode(
|
|
853
874
|
entityName,
|
|
854
875
|
options.kind || "interface",
|
|
@@ -897,8 +918,8 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
897
918
|
function generateInterface(options) {
|
|
898
919
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
899
920
|
const ifaceName = ensureInterfacePrefix(options.name);
|
|
900
|
-
const targetDir = options.targetDir ||
|
|
901
|
-
const filePath =
|
|
921
|
+
const targetDir = options.targetDir || path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
922
|
+
const filePath = path26__default.default.join(targetDir, `${ifaceName}.ts`);
|
|
902
923
|
const code = generateInterfaceCode(
|
|
903
924
|
ifaceName,
|
|
904
925
|
options.kind || "abstractClass",
|
|
@@ -1133,7 +1154,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
|
|
|
1133
1154
|
};
|
|
1134
1155
|
}
|
|
1135
1156
|
function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
1136
|
-
if (customPath &&
|
|
1157
|
+
if (customPath && fs17__default.default.existsSync(customPath)) {
|
|
1137
1158
|
return { filePath: customPath, ifaceName };
|
|
1138
1159
|
}
|
|
1139
1160
|
const candidateNames = [
|
|
@@ -1143,22 +1164,22 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
1143
1164
|
];
|
|
1144
1165
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
1145
1166
|
for (const feat of features) {
|
|
1146
|
-
const domainDir =
|
|
1147
|
-
if (!
|
|
1167
|
+
const domainDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
1168
|
+
if (!fs17__default.default.existsSync(domainDir)) continue;
|
|
1148
1169
|
for (const cand of candidateNames) {
|
|
1149
|
-
const p1 =
|
|
1150
|
-
if (
|
|
1170
|
+
const p1 = path26__default.default.join(domainDir, `${cand}.ts`);
|
|
1171
|
+
if (fs17__default.default.existsSync(p1)) {
|
|
1151
1172
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
1152
1173
|
}
|
|
1153
1174
|
}
|
|
1154
1175
|
}
|
|
1155
1176
|
for (const cand of candidateNames) {
|
|
1156
|
-
const p1 =
|
|
1157
|
-
if (
|
|
1158
|
-
const p22 =
|
|
1159
|
-
if (
|
|
1160
|
-
const p32 =
|
|
1161
|
-
if (
|
|
1177
|
+
const p1 = path26__default.default.join(projectRoot, "domain", `${cand}.ts`);
|
|
1178
|
+
if (fs17__default.default.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
1179
|
+
const p22 = path26__default.default.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
1180
|
+
if (fs17__default.default.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
1181
|
+
const p32 = path26__default.default.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
1182
|
+
if (fs17__default.default.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
1162
1183
|
}
|
|
1163
1184
|
return null;
|
|
1164
1185
|
}
|
|
@@ -1181,7 +1202,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
|
|
|
1181
1202
|
while (currentFile && !visited.has(currentFile)) {
|
|
1182
1203
|
visited.add(currentFile);
|
|
1183
1204
|
try {
|
|
1184
|
-
const content =
|
|
1205
|
+
const content = fs17__default.default.readFileSync(currentFile, "utf-8");
|
|
1185
1206
|
const parsed = parseInterfaceMethodsAndImports(content, currentName);
|
|
1186
1207
|
for (const m of parsed.methods) {
|
|
1187
1208
|
if (!allMethods.some((existing) => existing.name === m.name)) {
|
|
@@ -1257,7 +1278,7 @@ function generateStubCode(stubClassName, ifaceName, entityName, featureName, met
|
|
|
1257
1278
|
const entitiesVar = `${entityVar}s`;
|
|
1258
1279
|
const idKey = `${entityVar}Id`;
|
|
1259
1280
|
const impPath = ifaceImportPath || `../domain/${ifaceName}.js`;
|
|
1260
|
-
const entityImportPath = ifaceImportPath ? `${
|
|
1281
|
+
const entityImportPath = ifaceImportPath ? `${path26__default.default.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1261
1282
|
const importsByFrom = /* @__PURE__ */ new Map();
|
|
1262
1283
|
for (const imp of domainImports) {
|
|
1263
1284
|
if (imp.name === ifaceName || imp.name === baseEntity) continue;
|
|
@@ -1306,7 +1327,7 @@ function generateConcreteInfraCode(className, ifaceName, dependencies = [], meth
|
|
|
1306
1327
|
if (baseEntity) {
|
|
1307
1328
|
finalMethods = synthesizeCrudMethods(baseEntity);
|
|
1308
1329
|
if (!finalDomainImports.some((imp) => imp.name === baseEntity)) {
|
|
1309
|
-
const importPath = ifaceImportPath ? `${
|
|
1330
|
+
const importPath = ifaceImportPath ? `${path26__default.default.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1310
1331
|
finalDomainImports.push({
|
|
1311
1332
|
name: baseEntity,
|
|
1312
1333
|
from: importPath,
|
|
@@ -1351,8 +1372,8 @@ function generateInfrastructure(options) {
|
|
|
1351
1372
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1352
1373
|
const className = toPascalCase(options.name);
|
|
1353
1374
|
const isFeatureScope = options.scope !== "global" && Boolean(options.feature);
|
|
1354
|
-
const targetDir = options.targetDir || (isFeatureScope ?
|
|
1355
|
-
const filePath =
|
|
1375
|
+
const targetDir = options.targetDir || (isFeatureScope ? path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path26__default.default.join(projectRoot, "infrastructure"));
|
|
1376
|
+
const filePath = path26__default.default.join(targetDir, `${className}.ts`);
|
|
1356
1377
|
let code;
|
|
1357
1378
|
if (options.implementsInterface) {
|
|
1358
1379
|
const rawIfaceName = options.implementsInterface;
|
|
@@ -1366,7 +1387,7 @@ function generateInfrastructure(options) {
|
|
|
1366
1387
|
const ifaceFilePath = hierarchy.ifaceFilePath;
|
|
1367
1388
|
let ifaceImportPath;
|
|
1368
1389
|
if (ifaceFilePath) {
|
|
1369
|
-
let rel =
|
|
1390
|
+
let rel = path26__default.default.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
|
|
1370
1391
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1371
1392
|
ifaceImportPath = rel;
|
|
1372
1393
|
} else if (isFeatureScope) {
|
|
@@ -1379,8 +1400,8 @@ function generateInfrastructure(options) {
|
|
|
1379
1400
|
if (new RegExp(`\\b${item.name}\\b`).test(allSignatures)) {
|
|
1380
1401
|
let fromPath;
|
|
1381
1402
|
if (imp.specifier.startsWith(".") && ifaceFilePath) {
|
|
1382
|
-
const absTarget =
|
|
1383
|
-
let rel =
|
|
1403
|
+
const absTarget = path26__default.default.resolve(path26__default.default.dirname(ifaceFilePath), imp.specifier);
|
|
1404
|
+
let rel = path26__default.default.relative(targetDir, absTarget).replace(/\\/g, "/");
|
|
1384
1405
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1385
1406
|
fromPath = rel;
|
|
1386
1407
|
} else {
|
|
@@ -1567,8 +1588,8 @@ function generateUseCase(options) {
|
|
|
1567
1588
|
const files = [];
|
|
1568
1589
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1569
1590
|
const ucName = toPascalCase(options.name);
|
|
1570
|
-
const targetDir = options.targetDir ||
|
|
1571
|
-
const filePath =
|
|
1591
|
+
const targetDir = options.targetDir || path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
|
|
1592
|
+
const filePath = path26__default.default.join(targetDir, `${ucName}.ts`);
|
|
1572
1593
|
const code = generateUseCaseCode(
|
|
1573
1594
|
ucName,
|
|
1574
1595
|
options.dependencies || [],
|
|
@@ -1584,7 +1605,7 @@ function generateUseCase(options) {
|
|
|
1584
1605
|
})
|
|
1585
1606
|
);
|
|
1586
1607
|
if (options.includeTest) {
|
|
1587
|
-
const testPath =
|
|
1608
|
+
const testPath = path26__default.default.join(targetDir, `${ucName}.test.ts`);
|
|
1588
1609
|
const testCode = generateUseCaseTestCode(ucName, options.dependencies || []);
|
|
1589
1610
|
files.push(
|
|
1590
1611
|
writeFileSafely(testPath, testCode, {
|
|
@@ -1652,10 +1673,10 @@ function generateHttpHandler(options) {
|
|
|
1652
1673
|
const files = [];
|
|
1653
1674
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1654
1675
|
const className = toPascalCase(options.name);
|
|
1655
|
-
const pxDir =
|
|
1656
|
-
const handlersDir =
|
|
1657
|
-
const pxIndexPath =
|
|
1658
|
-
if (!
|
|
1676
|
+
const pxDir = path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1677
|
+
const handlersDir = path26__default.default.join(pxDir, "handlers");
|
|
1678
|
+
const pxIndexPath = path26__default.default.join(pxDir, "index.ts");
|
|
1679
|
+
if (!fs17__default.default.existsSync(pxIndexPath)) {
|
|
1659
1680
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1660
1681
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
1661
1682
|
routePath: featurePath
|
|
@@ -1668,7 +1689,7 @@ function generateHttpHandler(options) {
|
|
|
1668
1689
|
})
|
|
1669
1690
|
);
|
|
1670
1691
|
}
|
|
1671
|
-
const handlerFilePath =
|
|
1692
|
+
const handlerFilePath = path26__default.default.join(handlersDir, `${className}.ts`);
|
|
1672
1693
|
const code = generateHttpHandlerCode(
|
|
1673
1694
|
className,
|
|
1674
1695
|
options.method || "get",
|
|
@@ -1689,11 +1710,11 @@ function generateHttpHandler(options) {
|
|
|
1689
1710
|
return files;
|
|
1690
1711
|
}
|
|
1691
1712
|
function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], options = {}) {
|
|
1692
|
-
const providerPath =
|
|
1713
|
+
const providerPath = path26__default.default.join(featureDir, "diProvider.ts");
|
|
1693
1714
|
const pascalFeature = toPascalCase(featureName);
|
|
1694
1715
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1695
|
-
if (
|
|
1696
|
-
let content =
|
|
1716
|
+
if (fs17__default.default.existsSync(providerPath) && !options.overwrite) {
|
|
1717
|
+
let content = fs17__default.default.readFileSync(providerPath, "utf-8");
|
|
1697
1718
|
content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
|
|
1698
1719
|
for (const b of bindings) {
|
|
1699
1720
|
const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
|
|
@@ -1752,7 +1773,7 @@ function generateFeature(options) {
|
|
|
1752
1773
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1753
1774
|
const rawName = options.name.trim();
|
|
1754
1775
|
const featureName = toCamelCase(rawName);
|
|
1755
|
-
const targetDir = options.targetDir ||
|
|
1776
|
+
const targetDir = options.targetDir || path26__default.default.join(resolveFeaturesDir(projectRoot), featureName);
|
|
1756
1777
|
const routePath = options.routePath || `/${featureName}`;
|
|
1757
1778
|
const rawEntities = [];
|
|
1758
1779
|
if (options.entityNames && options.entityNames.length > 0) {
|
|
@@ -1773,7 +1794,7 @@ function generateFeature(options) {
|
|
|
1773
1794
|
const domainFile = generateDomain({
|
|
1774
1795
|
name: ent,
|
|
1775
1796
|
feature: featureName,
|
|
1776
|
-
targetDir:
|
|
1797
|
+
targetDir: path26__default.default.join(targetDir, "domain"),
|
|
1777
1798
|
projectRoot,
|
|
1778
1799
|
dryRun: options.dryRun,
|
|
1779
1800
|
overwrite: options.overwrite,
|
|
@@ -1793,7 +1814,7 @@ function generateFeature(options) {
|
|
|
1793
1814
|
const ifaceFile = generateInterface({
|
|
1794
1815
|
name: ifaceName,
|
|
1795
1816
|
feature: featureName,
|
|
1796
|
-
targetDir:
|
|
1817
|
+
targetDir: path26__default.default.join(targetDir, "domain"),
|
|
1797
1818
|
entityName: ent,
|
|
1798
1819
|
projectRoot,
|
|
1799
1820
|
dryRun: options.dryRun,
|
|
@@ -1810,7 +1831,7 @@ function generateFeature(options) {
|
|
|
1810
1831
|
const stubFile = generateInfrastructure({
|
|
1811
1832
|
name: stubName,
|
|
1812
1833
|
feature: featureName,
|
|
1813
|
-
targetDir:
|
|
1834
|
+
targetDir: path26__default.default.join(targetDir, "infrastructure"),
|
|
1814
1835
|
kind: "stub",
|
|
1815
1836
|
implementsInterface: ifaceName,
|
|
1816
1837
|
entityName: ent,
|
|
@@ -1852,7 +1873,7 @@ function generateFeature(options) {
|
|
|
1852
1873
|
const ucFiles = generateUseCase({
|
|
1853
1874
|
name: ucName,
|
|
1854
1875
|
feature: featureName,
|
|
1855
|
-
targetDir:
|
|
1876
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
1856
1877
|
dependencies: options.includeInterface !== false ? [ifaceName] : [],
|
|
1857
1878
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1858
1879
|
outputProperties: [{ name: entVar, type: primaryEntity }],
|
|
@@ -1897,7 +1918,7 @@ function generateFeature(options) {
|
|
|
1897
1918
|
const ucFiles = generateUseCase({
|
|
1898
1919
|
name: ucName,
|
|
1899
1920
|
feature: featureName,
|
|
1900
|
-
targetDir:
|
|
1921
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
1901
1922
|
dependencies: deps,
|
|
1902
1923
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1903
1924
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1930,7 +1951,7 @@ function generateFeature(options) {
|
|
|
1930
1951
|
const ucFiles = generateUseCase({
|
|
1931
1952
|
name: ucName,
|
|
1932
1953
|
feature: featureName,
|
|
1933
|
-
targetDir:
|
|
1954
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
1934
1955
|
dependencies: deps,
|
|
1935
1956
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1936
1957
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1963,7 +1984,7 @@ function generateFeature(options) {
|
|
|
1963
1984
|
const ucFiles = generateUseCase({
|
|
1964
1985
|
name: ucName,
|
|
1965
1986
|
feature: featureName,
|
|
1966
|
-
targetDir:
|
|
1987
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
1967
1988
|
dependencies: deps,
|
|
1968
1989
|
inputProperties: [
|
|
1969
1990
|
{ name: "page", type: "number", optional: true },
|
|
@@ -2007,7 +2028,7 @@ function generateFeature(options) {
|
|
|
2007
2028
|
const ucFiles = generateUseCase({
|
|
2008
2029
|
name: ucName,
|
|
2009
2030
|
feature: featureName,
|
|
2010
|
-
targetDir:
|
|
2031
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
2011
2032
|
dependencies: deps,
|
|
2012
2033
|
inputProperties: [{ name: entVar, type: ent }],
|
|
2013
2034
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -2040,7 +2061,7 @@ function generateFeature(options) {
|
|
|
2040
2061
|
const ucFiles = generateUseCase({
|
|
2041
2062
|
name: ucName,
|
|
2042
2063
|
feature: featureName,
|
|
2043
|
-
targetDir:
|
|
2064
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
2044
2065
|
dependencies: deps,
|
|
2045
2066
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
2046
2067
|
outputProperties: [{ name: "success", type: "boolean" }],
|
|
@@ -2077,7 +2098,7 @@ function generateFeature(options) {
|
|
|
2077
2098
|
const ucFiles = generateUseCase({
|
|
2078
2099
|
name: ucName,
|
|
2079
2100
|
feature: featureName,
|
|
2080
|
-
targetDir:
|
|
2101
|
+
targetDir: path26__default.default.join(targetDir, "useCases"),
|
|
2081
2102
|
dependencies: customUc.dependencies || [],
|
|
2082
2103
|
inputProperties: customUc.inputProperties || [],
|
|
2083
2104
|
outputProperties: customUc.outputProperties || [],
|
|
@@ -2109,8 +2130,8 @@ function generateFeature(options) {
|
|
|
2109
2130
|
}
|
|
2110
2131
|
}
|
|
2111
2132
|
if (options.includeExpress !== false) {
|
|
2112
|
-
const pxDir =
|
|
2113
|
-
const pxIndexPath =
|
|
2133
|
+
const pxDir = path26__default.default.join(targetDir, "pxExpress");
|
|
2134
|
+
const pxIndexPath = path26__default.default.join(pxDir, "index.ts");
|
|
2114
2135
|
if (!files.some((f) => f.absolutePath === pxIndexPath)) {
|
|
2115
2136
|
const pxIndexContent = renderTemplate(expressIndexTemplate, { routePath });
|
|
2116
2137
|
files.push(
|
|
@@ -2155,7 +2176,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2155
2176
|
}
|
|
2156
2177
|
const normalizedName = toCamelCase(name);
|
|
2157
2178
|
const baseFeaturesDir = resolveFeaturesDir(projectRoot, flags);
|
|
2158
|
-
const defaultDir =
|
|
2179
|
+
const defaultDir = path26__default.default.relative(projectRoot, path26__default.default.join(baseFeaturesDir, normalizedName));
|
|
2159
2180
|
let targetDirRel = defaultDir;
|
|
2160
2181
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2161
2182
|
targetDirRel = handleCancel(
|
|
@@ -2166,7 +2187,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2166
2187
|
})
|
|
2167
2188
|
).trim();
|
|
2168
2189
|
}
|
|
2169
|
-
const targetDir = flags.dest ?
|
|
2190
|
+
const targetDir = flags.dest ? path26__default.default.resolve(projectRoot, flags.dest) : flags.target ? path26__default.default.resolve(projectRoot, flags.target) : path26__default.default.resolve(projectRoot, targetDirRel);
|
|
2170
2191
|
let includeExpress = flags.express !== void 0 ? Boolean(flags.express) : true;
|
|
2171
2192
|
let routePath = `/${normalizedName}`;
|
|
2172
2193
|
let includeDomain = true;
|
|
@@ -2408,8 +2429,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2408
2429
|
};
|
|
2409
2430
|
const files = generateFeature(options);
|
|
2410
2431
|
if (isRegistry) {
|
|
2411
|
-
const registryPath =
|
|
2412
|
-
if (!
|
|
2432
|
+
const registryPath = path26__default.default.join(targetDir, "registry.json");
|
|
2433
|
+
if (!fs17__default.default.existsSync(registryPath)) {
|
|
2413
2434
|
const manifest = {
|
|
2414
2435
|
name: toKebabCase(normalizedName),
|
|
2415
2436
|
type: "feature",
|
|
@@ -2435,7 +2456,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2435
2456
|
printGeneratedFiles(files, options.dryRun);
|
|
2436
2457
|
p19__namespace.outro(
|
|
2437
2458
|
pc14__default.default.green(
|
|
2438
|
-
`\u2713 Feature '${normalizedName}' initialized in ${
|
|
2459
|
+
`\u2713 Feature '${normalizedName}' initialized in ${path26__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2439
2460
|
)
|
|
2440
2461
|
);
|
|
2441
2462
|
}
|
|
@@ -2446,7 +2467,7 @@ function generateShared(options) {
|
|
|
2446
2467
|
const pascalName = toPascalCase(rawName);
|
|
2447
2468
|
const camelName = toCamelCase(rawName);
|
|
2448
2469
|
const kebabName = toKebabCase(rawName);
|
|
2449
|
-
const targetDir = options.targetDir ||
|
|
2470
|
+
const targetDir = options.targetDir || path26__default.default.join(resolveSharedDir(projectRoot), kebabName);
|
|
2450
2471
|
const fileDefs = [];
|
|
2451
2472
|
const facadeContent = `import { MakeInjectable, type DepsType } from "@solid-stack/di";
|
|
2452
2473
|
import { I${pascalName}Engine } from "./ports/I${pascalName}Engine.js";
|
|
@@ -2458,7 +2479,7 @@ export class ${pascalName} {
|
|
|
2458
2479
|
}
|
|
2459
2480
|
`;
|
|
2460
2481
|
fileDefs.push({
|
|
2461
|
-
absolutePath:
|
|
2482
|
+
absolutePath: path26__default.default.join(targetDir, `${pascalName}.ts`),
|
|
2462
2483
|
content: facadeContent
|
|
2463
2484
|
});
|
|
2464
2485
|
const portContent = `export abstract class I${pascalName}Engine {
|
|
@@ -2466,7 +2487,7 @@ export class ${pascalName} {
|
|
|
2466
2487
|
}
|
|
2467
2488
|
`;
|
|
2468
2489
|
fileDefs.push({
|
|
2469
|
-
absolutePath:
|
|
2490
|
+
absolutePath: path26__default.default.join(targetDir, "ports", `I${pascalName}Engine.ts`),
|
|
2470
2491
|
content: portContent
|
|
2471
2492
|
});
|
|
2472
2493
|
const concreteContent = `import { MakeInjectable } from "@solid-stack/di";
|
|
@@ -2478,7 +2499,7 @@ export class Default${pascalName}Engine implements I${pascalName}Engine {
|
|
|
2478
2499
|
}
|
|
2479
2500
|
`;
|
|
2480
2501
|
fileDefs.push({
|
|
2481
|
-
absolutePath:
|
|
2502
|
+
absolutePath: path26__default.default.join(targetDir, "infrastructure", `Default${pascalName}Engine.ts`),
|
|
2482
2503
|
content: concreteContent
|
|
2483
2504
|
});
|
|
2484
2505
|
if (options.includeStub !== false) {
|
|
@@ -2491,7 +2512,7 @@ export class Stub${pascalName}Engine implements I${pascalName}Engine {
|
|
|
2491
2512
|
}
|
|
2492
2513
|
`;
|
|
2493
2514
|
fileDefs.push({
|
|
2494
|
-
absolutePath:
|
|
2515
|
+
absolutePath: path26__default.default.join(targetDir, "infrastructure", `Stub${pascalName}Engine.ts`),
|
|
2495
2516
|
content: stubContent
|
|
2496
2517
|
});
|
|
2497
2518
|
}
|
|
@@ -2506,7 +2527,7 @@ export const diProvider = (c: Container): void => {
|
|
|
2506
2527
|
export default diProvider;
|
|
2507
2528
|
`;
|
|
2508
2529
|
fileDefs.push({
|
|
2509
|
-
absolutePath:
|
|
2530
|
+
absolutePath: path26__default.default.join(targetDir, "diProvider.ts"),
|
|
2510
2531
|
content: providerContent
|
|
2511
2532
|
});
|
|
2512
2533
|
if (options.isRegistry) {
|
|
@@ -2523,7 +2544,7 @@ export default diProvider;
|
|
|
2523
2544
|
files: []
|
|
2524
2545
|
};
|
|
2525
2546
|
fileDefs.push({
|
|
2526
|
-
absolutePath:
|
|
2547
|
+
absolutePath: path26__default.default.join(targetDir, "registry.json"),
|
|
2527
2548
|
content: JSON.stringify(registryManifest, null, 2) + "\n"
|
|
2528
2549
|
});
|
|
2529
2550
|
}
|
|
@@ -2560,7 +2581,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2560
2581
|
}
|
|
2561
2582
|
const normalizedName = toKebabCase(name);
|
|
2562
2583
|
const baseSharedDir = resolveSharedDir(projectRoot, flags);
|
|
2563
|
-
const defaultDir =
|
|
2584
|
+
const defaultDir = path26__default.default.relative(projectRoot, path26__default.default.join(baseSharedDir, normalizedName));
|
|
2564
2585
|
let targetDirRel = defaultDir;
|
|
2565
2586
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2566
2587
|
targetDirRel = handleCancel(
|
|
@@ -2571,7 +2592,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2571
2592
|
})
|
|
2572
2593
|
).trim();
|
|
2573
2594
|
}
|
|
2574
|
-
const targetDir = flags.dest ?
|
|
2595
|
+
const targetDir = flags.dest ? path26__default.default.resolve(projectRoot, flags.dest) : flags.target ? path26__default.default.resolve(projectRoot, flags.target) : path26__default.default.resolve(projectRoot, targetDirRel);
|
|
2575
2596
|
let description = flags.description || "";
|
|
2576
2597
|
let includeStub = true;
|
|
2577
2598
|
if (!flags.yes) {
|
|
@@ -2605,7 +2626,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2605
2626
|
printGeneratedFiles(files, Boolean(flags.dryRun));
|
|
2606
2627
|
p19__namespace.outro(
|
|
2607
2628
|
pc14__default.default.green(
|
|
2608
|
-
`\u2713 Shared module '${normalizedName}' initialized in ${
|
|
2629
|
+
`\u2713 Shared module '${normalizedName}' initialized in ${path26__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2609
2630
|
)
|
|
2610
2631
|
);
|
|
2611
2632
|
}
|
|
@@ -3032,7 +3053,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
3032
3053
|
const infraFile = generateInfrastructure(options);
|
|
3033
3054
|
files.push(infraFile);
|
|
3034
3055
|
if (registerInProvider && scope === "feature" && feature && implementsInterface) {
|
|
3035
|
-
const featureDir =
|
|
3056
|
+
const featureDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feature);
|
|
3036
3057
|
const providerFile = updateOrGenerateDiProvider(
|
|
3037
3058
|
featureDir,
|
|
3038
3059
|
feature,
|
|
@@ -3194,7 +3215,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3194
3215
|
files.push(stubFile);
|
|
3195
3216
|
}
|
|
3196
3217
|
if (registerInProvider && generateStub) {
|
|
3197
|
-
const featureDir =
|
|
3218
|
+
const featureDir = path26__default.default.join(resolveFeaturesDir(projectRoot), feature);
|
|
3198
3219
|
const providerFile = updateOrGenerateDiProvider(
|
|
3199
3220
|
featureDir,
|
|
3200
3221
|
feature,
|
|
@@ -3382,21 +3403,21 @@ function generateInjectable(options) {
|
|
|
3382
3403
|
const className = toPascalCase(options.name);
|
|
3383
3404
|
let targetDir = "";
|
|
3384
3405
|
if (options.customPath) {
|
|
3385
|
-
targetDir =
|
|
3406
|
+
targetDir = path26__default.default.isAbsolute(options.customPath) ? options.customPath : path26__default.default.join(projectRoot, options.customPath);
|
|
3386
3407
|
} else if (options.location === "feature-service" && options.feature) {
|
|
3387
|
-
targetDir =
|
|
3408
|
+
targetDir = path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "services");
|
|
3388
3409
|
} else if (options.location === "feature-transformer" && options.feature) {
|
|
3389
|
-
targetDir =
|
|
3410
|
+
targetDir = path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
|
|
3390
3411
|
} else if (options.location === "module") {
|
|
3391
|
-
targetDir =
|
|
3412
|
+
targetDir = path26__default.default.join(projectRoot, "modules", className);
|
|
3392
3413
|
} else {
|
|
3393
|
-
targetDir = options.feature ?
|
|
3414
|
+
targetDir = options.feature ? path26__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path26__default.default.join(projectRoot, "shared", className.toLowerCase());
|
|
3394
3415
|
}
|
|
3395
|
-
const filePath =
|
|
3416
|
+
const filePath = path26__default.default.join(targetDir, `${className}.ts`);
|
|
3396
3417
|
let ifaceName;
|
|
3397
3418
|
if (options.generateInterface) {
|
|
3398
3419
|
ifaceName = `I${className}`;
|
|
3399
|
-
const ifacePath =
|
|
3420
|
+
const ifacePath = path26__default.default.join(targetDir, `${ifaceName}.ts`);
|
|
3400
3421
|
const ifaceContent = renderTemplate(injectableInterfaceTemplate, { ifaceName });
|
|
3401
3422
|
files.push(
|
|
3402
3423
|
writeFileSafely(ifacePath, ifaceContent, {
|
|
@@ -3525,7 +3546,7 @@ async function runEnvInit(flags = {}) {
|
|
|
3525
3546
|
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3526
3547
|
const s = p19__namespace.spinner();
|
|
3527
3548
|
s.start("Scanning for .example environment files...");
|
|
3528
|
-
const files =
|
|
3549
|
+
const files = fs17__default.default.readdirSync(projectRoot);
|
|
3529
3550
|
const exampleFiles = files.filter((file) => file.startsWith(".env") && file.endsWith(".example")).sort();
|
|
3530
3551
|
if (exampleFiles.length === 0) {
|
|
3531
3552
|
s.stop("No .example files found.");
|
|
@@ -3535,11 +3556,11 @@ async function runEnvInit(flags = {}) {
|
|
|
3535
3556
|
s.message(`Found ${exampleFiles.length} template(s). Generating...`);
|
|
3536
3557
|
const generatedFiles = [];
|
|
3537
3558
|
for (const exampleFile of exampleFiles) {
|
|
3538
|
-
const sourcePath =
|
|
3559
|
+
const sourcePath = path26__default.default.join(projectRoot, exampleFile);
|
|
3539
3560
|
const targetFile = exampleFile.replace(/\.example$/, "");
|
|
3540
|
-
const targetPath =
|
|
3561
|
+
const targetPath = path26__default.default.join(projectRoot, targetFile);
|
|
3541
3562
|
let overwrite = flags.overwrite;
|
|
3542
|
-
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY &&
|
|
3563
|
+
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17__default.default.existsSync(targetPath)) {
|
|
3543
3564
|
overwrite = await p19__namespace.confirm({
|
|
3544
3565
|
message: `${targetFile} already exists. Overwrite?`,
|
|
3545
3566
|
initialValue: false
|
|
@@ -3549,7 +3570,7 @@ async function runEnvInit(flags = {}) {
|
|
|
3549
3570
|
process.exit(0);
|
|
3550
3571
|
}
|
|
3551
3572
|
}
|
|
3552
|
-
const content =
|
|
3573
|
+
const content = fs17__default.default.readFileSync(sourcePath, "utf-8");
|
|
3553
3574
|
const genFile = writeFileSafely(targetPath, content, {
|
|
3554
3575
|
projectRoot,
|
|
3555
3576
|
dryRun: Boolean(flags.dryRun),
|
|
@@ -3568,7 +3589,7 @@ var EnvEditor = class {
|
|
|
3568
3589
|
filePath;
|
|
3569
3590
|
constructor(filePath) {
|
|
3570
3591
|
this.filePath = filePath;
|
|
3571
|
-
this.lines =
|
|
3592
|
+
this.lines = fs17__default.default.existsSync(filePath) ? fs17__default.default.readFileSync(filePath, "utf-8").split(/\r?\n/) : [];
|
|
3572
3593
|
}
|
|
3573
3594
|
getLines() {
|
|
3574
3595
|
return [...this.lines];
|
|
@@ -3632,18 +3653,18 @@ var EnvEditor = class {
|
|
|
3632
3653
|
});
|
|
3633
3654
|
}
|
|
3634
3655
|
save() {
|
|
3635
|
-
const dir =
|
|
3636
|
-
if (!
|
|
3637
|
-
|
|
3656
|
+
const dir = path26__default.default.dirname(this.filePath);
|
|
3657
|
+
if (!fs17__default.default.existsSync(dir)) {
|
|
3658
|
+
fs17__default.default.mkdirSync(dir, { recursive: true });
|
|
3638
3659
|
}
|
|
3639
|
-
|
|
3660
|
+
fs17__default.default.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
|
|
3640
3661
|
}
|
|
3641
3662
|
};
|
|
3642
3663
|
function discoverEnvironments(projectRoot) {
|
|
3643
|
-
if (!
|
|
3664
|
+
if (!fs17__default.default.existsSync(projectRoot)) {
|
|
3644
3665
|
return ["local", "dev", "prod"];
|
|
3645
3666
|
}
|
|
3646
|
-
const files =
|
|
3667
|
+
const files = fs17__default.default.readdirSync(projectRoot);
|
|
3647
3668
|
const envs = /* @__PURE__ */ new Set();
|
|
3648
3669
|
for (const file of files) {
|
|
3649
3670
|
if (file.startsWith(".env")) {
|
|
@@ -3668,7 +3689,7 @@ async function runEnvInitExamples(flags = {}) {
|
|
|
3668
3689
|
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3669
3690
|
const s = p19__namespace.spinner();
|
|
3670
3691
|
s.start("Scanning for local environment files...");
|
|
3671
|
-
const files =
|
|
3692
|
+
const files = fs17__default.default.readdirSync(projectRoot, { withFileTypes: true });
|
|
3672
3693
|
const envFiles = files.filter((dirent) => dirent.isFile() && dirent.name.startsWith(".env") && !dirent.name.endsWith(".example")).map((dirent) => dirent.name).sort();
|
|
3673
3694
|
if (envFiles.length === 0) {
|
|
3674
3695
|
s.stop("No local .env files found.");
|
|
@@ -3678,11 +3699,11 @@ async function runEnvInitExamples(flags = {}) {
|
|
|
3678
3699
|
s.message(`Found ${envFiles.length} local .env file(s). Generating templates...`);
|
|
3679
3700
|
const generatedFiles = [];
|
|
3680
3701
|
for (const envFile of envFiles) {
|
|
3681
|
-
const sourcePath =
|
|
3702
|
+
const sourcePath = path26__default.default.join(projectRoot, envFile);
|
|
3682
3703
|
const targetFile = `${envFile}.example`;
|
|
3683
|
-
const targetPath =
|
|
3704
|
+
const targetPath = path26__default.default.join(projectRoot, targetFile);
|
|
3684
3705
|
let overwrite = flags.overwrite;
|
|
3685
|
-
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY &&
|
|
3706
|
+
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17__default.default.existsSync(targetPath)) {
|
|
3686
3707
|
overwrite = await p19__namespace.confirm({
|
|
3687
3708
|
message: `${targetFile} already exists. Overwrite with redacted values?`,
|
|
3688
3709
|
initialValue: true
|
|
@@ -3716,12 +3737,12 @@ function isInteractive(flags) {
|
|
|
3716
3737
|
function getAllExistingKeys(projectRoot, envs) {
|
|
3717
3738
|
const keys = /* @__PURE__ */ new Set();
|
|
3718
3739
|
for (const env of envs) {
|
|
3719
|
-
const localPath =
|
|
3720
|
-
const examplePath =
|
|
3721
|
-
if (
|
|
3740
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3741
|
+
const examplePath = path26__default.default.join(projectRoot, resolveEnvFilename(env, true));
|
|
3742
|
+
if (fs17__default.default.existsSync(localPath)) {
|
|
3722
3743
|
new EnvEditor(localPath).getKeys().forEach((k) => keys.add(k));
|
|
3723
3744
|
}
|
|
3724
|
-
if (
|
|
3745
|
+
if (fs17__default.default.existsSync(examplePath)) {
|
|
3725
3746
|
new EnvEditor(examplePath).getKeys().forEach((k) => keys.add(k));
|
|
3726
3747
|
}
|
|
3727
3748
|
}
|
|
@@ -3793,8 +3814,8 @@ async function runEnvAdd(key, value, flags = {}) {
|
|
|
3793
3814
|
})
|
|
3794
3815
|
);
|
|
3795
3816
|
}
|
|
3796
|
-
const localPath =
|
|
3797
|
-
const examplePath =
|
|
3817
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3818
|
+
const examplePath = path26__default.default.join(projectRoot, resolveEnvFilename(env, true));
|
|
3798
3819
|
if (flags.dryRun) {
|
|
3799
3820
|
p19__namespace.log.info(
|
|
3800
3821
|
pc14__default.default.cyan(`[DRY RUN] Would set ${targetKey}=${envVal} in ${resolveEnvFilename(env, false)}`)
|
|
@@ -3841,8 +3862,8 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3841
3862
|
);
|
|
3842
3863
|
}
|
|
3843
3864
|
const envsWithKey = allEnvs.filter((env) => {
|
|
3844
|
-
const localPath =
|
|
3845
|
-
return
|
|
3865
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3866
|
+
return fs17__default.default.existsSync(localPath) && new EnvEditor(localPath).has(targetKey);
|
|
3846
3867
|
});
|
|
3847
3868
|
let targetEnvs = [];
|
|
3848
3869
|
if (flags.env) {
|
|
@@ -3868,7 +3889,7 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3868
3889
|
return { key: targetKey, environments: [] };
|
|
3869
3890
|
}
|
|
3870
3891
|
for (const env of targetEnvs) {
|
|
3871
|
-
const localPath =
|
|
3892
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3872
3893
|
const localEditor = new EnvEditor(localPath);
|
|
3873
3894
|
const currentVal = localEditor.getValue(targetKey);
|
|
3874
3895
|
let newVal = value;
|
|
@@ -3898,7 +3919,7 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3898
3919
|
} else {
|
|
3899
3920
|
localEditor.set(targetKey, newVal);
|
|
3900
3921
|
localEditor.save();
|
|
3901
|
-
const examplePath =
|
|
3922
|
+
const examplePath = path26__default.default.join(projectRoot, resolveEnvFilename(env, true));
|
|
3902
3923
|
const exampleEditor = new EnvEditor(examplePath);
|
|
3903
3924
|
if (!exampleEditor.has(targetKey)) {
|
|
3904
3925
|
exampleEditor.set(targetKey, "");
|
|
@@ -3934,9 +3955,9 @@ async function runEnvDelete(key, flags = {}) {
|
|
|
3934
3955
|
);
|
|
3935
3956
|
}
|
|
3936
3957
|
const envsWithKey = allEnvs.filter((env) => {
|
|
3937
|
-
const localPath =
|
|
3938
|
-
const examplePath =
|
|
3939
|
-
return
|
|
3958
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3959
|
+
const examplePath = path26__default.default.join(projectRoot, resolveEnvFilename(env, true));
|
|
3960
|
+
return fs17__default.default.existsSync(localPath) && new EnvEditor(localPath).has(targetKey) || fs17__default.default.existsSync(examplePath) && new EnvEditor(examplePath).has(targetKey);
|
|
3940
3961
|
});
|
|
3941
3962
|
let targetEnvs = [];
|
|
3942
3963
|
if (flags.env) {
|
|
@@ -3974,19 +3995,19 @@ async function runEnvDelete(key, flags = {}) {
|
|
|
3974
3995
|
}
|
|
3975
3996
|
}
|
|
3976
3997
|
for (const env of targetEnvs) {
|
|
3977
|
-
const localPath =
|
|
3978
|
-
const examplePath =
|
|
3998
|
+
const localPath = path26__default.default.join(projectRoot, resolveEnvFilename(env, false));
|
|
3999
|
+
const examplePath = path26__default.default.join(projectRoot, resolveEnvFilename(env, true));
|
|
3979
4000
|
if (flags.dryRun) {
|
|
3980
4001
|
p19__namespace.log.info(
|
|
3981
4002
|
pc14__default.default.cyan(`[DRY RUN] Would delete ${targetKey} from ${resolveEnvFilename(env, false)} and ${resolveEnvFilename(env, true)}`)
|
|
3982
4003
|
);
|
|
3983
4004
|
} else {
|
|
3984
|
-
if (
|
|
4005
|
+
if (fs17__default.default.existsSync(localPath)) {
|
|
3985
4006
|
const localEditor = new EnvEditor(localPath);
|
|
3986
4007
|
localEditor.delete(targetKey);
|
|
3987
4008
|
localEditor.save();
|
|
3988
4009
|
}
|
|
3989
|
-
if (
|
|
4010
|
+
if (fs17__default.default.existsSync(examplePath)) {
|
|
3990
4011
|
const exampleEditor = new EnvEditor(examplePath);
|
|
3991
4012
|
exampleEditor.delete(targetKey);
|
|
3992
4013
|
exampleEditor.save();
|
|
@@ -4011,10 +4032,10 @@ async function runEnvAudit(flags = {}) {
|
|
|
4011
4032
|
for (const env of envs) {
|
|
4012
4033
|
const localFile = resolveEnvFilename(env, false);
|
|
4013
4034
|
const exampleFile = resolveEnvFilename(env, true);
|
|
4014
|
-
const localPath =
|
|
4015
|
-
const examplePath =
|
|
4016
|
-
const localExists =
|
|
4017
|
-
const exampleExists =
|
|
4035
|
+
const localPath = path26__default.default.join(projectRoot, localFile);
|
|
4036
|
+
const examplePath = path26__default.default.join(projectRoot, exampleFile);
|
|
4037
|
+
const localExists = fs17__default.default.existsSync(localPath);
|
|
4038
|
+
const exampleExists = fs17__default.default.existsSync(examplePath);
|
|
4018
4039
|
const localEditor = new EnvEditor(localPath);
|
|
4019
4040
|
const exampleEditor = new EnvEditor(examplePath);
|
|
4020
4041
|
const localKeys = localExists ? localEditor.getKeys() : [];
|
|
@@ -4353,17 +4374,17 @@ function getModuleBaseDir(projectRoot, modType) {
|
|
|
4353
4374
|
return modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4354
4375
|
}
|
|
4355
4376
|
const folder = modType === "shared" ? "shared" : "features";
|
|
4356
|
-
return
|
|
4377
|
+
return path26__default.default.join(projectRoot, "src", folder);
|
|
4357
4378
|
}
|
|
4358
4379
|
function getExistingModuleDir(projectRoot, modType, modName) {
|
|
4359
4380
|
const folder = modType === "shared" ? "shared" : "features";
|
|
4360
4381
|
const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4361
|
-
const inConfigured =
|
|
4362
|
-
if (
|
|
4363
|
-
const inSrc =
|
|
4364
|
-
if (
|
|
4365
|
-
const inRoot =
|
|
4366
|
-
if (
|
|
4382
|
+
const inConfigured = path26__default.default.join(configuredDir, modName);
|
|
4383
|
+
if (fs17__default.default.existsSync(inConfigured)) return inConfigured;
|
|
4384
|
+
const inSrc = path26__default.default.join(projectRoot, "src", folder, modName);
|
|
4385
|
+
if (fs17__default.default.existsSync(inSrc)) return inSrc;
|
|
4386
|
+
const inRoot = path26__default.default.join(projectRoot, folder, modName);
|
|
4387
|
+
if (fs17__default.default.existsSync(inRoot)) return inRoot;
|
|
4367
4388
|
return null;
|
|
4368
4389
|
}
|
|
4369
4390
|
function checkModuleExists(projectRoot, modType, modName) {
|
|
@@ -4374,14 +4395,14 @@ function getAvailableLocalModules(projectRoot, modType) {
|
|
|
4374
4395
|
const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4375
4396
|
const dirs = [
|
|
4376
4397
|
configuredDir,
|
|
4377
|
-
|
|
4378
|
-
|
|
4398
|
+
path26__default.default.join(projectRoot, "src", folder),
|
|
4399
|
+
path26__default.default.join(projectRoot, folder)
|
|
4379
4400
|
];
|
|
4380
4401
|
const set = /* @__PURE__ */ new Set();
|
|
4381
4402
|
for (const dir of dirs) {
|
|
4382
|
-
if (
|
|
4403
|
+
if (fs17__default.default.existsSync(dir)) {
|
|
4383
4404
|
try {
|
|
4384
|
-
const entries =
|
|
4405
|
+
const entries = fs17__default.default.readdirSync(dir, { withFileTypes: true });
|
|
4385
4406
|
for (const e of entries) {
|
|
4386
4407
|
if (e.isDirectory() && !e.name.startsWith(".")) {
|
|
4387
4408
|
set.add(e.name);
|
|
@@ -4583,7 +4604,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4583
4604
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${programmaticAlias}/`);
|
|
4584
4605
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticAlias}`);
|
|
4585
4606
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
4586
|
-
const displayDest =
|
|
4607
|
+
const displayDest = path26__default.default.relative(projectRoot, path26__default.default.join(baseDir, programmaticAlias));
|
|
4587
4608
|
p19__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
4588
4609
|
resolutions.set(key, {
|
|
4589
4610
|
type: modType,
|
|
@@ -4771,7 +4792,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4771
4792
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${newName}/`);
|
|
4772
4793
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${newName}`);
|
|
4773
4794
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
4774
|
-
const displayDest =
|
|
4795
|
+
const displayDest = path26__default.default.relative(projectRoot, path26__default.default.join(baseDir, newName));
|
|
4775
4796
|
p19__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
4776
4797
|
resolutions.set(key, {
|
|
4777
4798
|
type: modType,
|
|
@@ -4823,7 +4844,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4823
4844
|
continue;
|
|
4824
4845
|
}
|
|
4825
4846
|
const folder = res.type === "shared" ? "shared" : "features";
|
|
4826
|
-
const targetDir =
|
|
4847
|
+
const targetDir = path26__default.default.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
|
|
4827
4848
|
const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
|
|
4828
4849
|
if (key !== rootKey) {
|
|
4829
4850
|
p19__namespace.log.step(
|
|
@@ -4833,30 +4854,30 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4833
4854
|
if (res.action === "overwrite" && !flags.dryRun) {
|
|
4834
4855
|
const existingDir = getExistingModuleDir(projectRoot, res.type, res.targetName);
|
|
4835
4856
|
if (existingDir && existingDir !== targetDir) {
|
|
4836
|
-
|
|
4857
|
+
fs17__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
4837
4858
|
}
|
|
4838
|
-
if (
|
|
4839
|
-
|
|
4859
|
+
if (fs17__default.default.existsSync(targetDir)) {
|
|
4860
|
+
fs17__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
4840
4861
|
}
|
|
4841
4862
|
}
|
|
4842
4863
|
for (const file of res.manifest.files || []) {
|
|
4843
4864
|
if (file === "registry.json") continue;
|
|
4844
4865
|
if (!includeTests && isTestFile(file)) continue;
|
|
4845
4866
|
const remoteFilePath = `${folder}/${res.registryName}/${file}`;
|
|
4846
|
-
const localFilePath =
|
|
4847
|
-
if (
|
|
4867
|
+
const localFilePath = path26__default.default.join(targetDir, file);
|
|
4868
|
+
if (fs17__default.default.existsSync(localFilePath) && !isOverwrite) {
|
|
4848
4869
|
p19__namespace.log.warn(
|
|
4849
|
-
` \u21B3 Skipping existing file: ${pc14__default.default.dim(
|
|
4870
|
+
` \u21B3 Skipping existing file: ${pc14__default.default.dim(path26__default.default.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
|
|
4850
4871
|
);
|
|
4851
4872
|
continue;
|
|
4852
4873
|
}
|
|
4853
4874
|
let content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
4854
4875
|
content = rewriteImports(content, globalAliasMap);
|
|
4855
4876
|
if (!flags.dryRun) {
|
|
4856
|
-
|
|
4857
|
-
|
|
4877
|
+
fs17__default.default.mkdirSync(path26__default.default.dirname(localFilePath), { recursive: true });
|
|
4878
|
+
fs17__default.default.writeFileSync(localFilePath, content, "utf-8");
|
|
4858
4879
|
}
|
|
4859
|
-
const displayPath =
|
|
4880
|
+
const displayPath = path26__default.default.relative(projectRoot, localFilePath);
|
|
4860
4881
|
totalWrittenFiles.push(displayPath);
|
|
4861
4882
|
p19__namespace.log.message(` ${pc14__default.default.green("+")} ${displayPath}`);
|
|
4862
4883
|
}
|
|
@@ -4882,7 +4903,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4882
4903
|
} else {
|
|
4883
4904
|
const rootRes = resolutions.get(rootKey);
|
|
4884
4905
|
const baseDir = getModuleBaseDir(projectRoot, type);
|
|
4885
|
-
const displayTarget =
|
|
4906
|
+
const displayTarget = path26__default.default.relative(projectRoot, path26__default.default.join(baseDir, rootRes.targetName));
|
|
4886
4907
|
p19__namespace.log.success(
|
|
4887
4908
|
pc14__default.default.green(
|
|
4888
4909
|
`Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
|
|
@@ -4901,19 +4922,19 @@ var DependencyRuleError = class extends Error {
|
|
|
4901
4922
|
}
|
|
4902
4923
|
};
|
|
4903
4924
|
function isTestFile2(filePath, projectRoot) {
|
|
4904
|
-
const norm = (projectRoot ?
|
|
4905
|
-
const base =
|
|
4925
|
+
const norm = (projectRoot ? path26__default.default.relative(projectRoot, filePath) : filePath).replace(/\\/g, "/");
|
|
4926
|
+
const base = path26__default.default.basename(norm);
|
|
4906
4927
|
return base.endsWith(".test.ts") || base.endsWith(".test.js") || base.endsWith(".spec.ts") || base.endsWith(".spec.js") || base.endsWith(".d.ts") || norm.includes("/__tests__/") || norm.startsWith("__tests__/") || /(?:^|\/)tests?\//.test(norm);
|
|
4907
4928
|
}
|
|
4908
4929
|
function scanDirFiles(dir, projectRoot) {
|
|
4909
|
-
if (!
|
|
4910
|
-
const entries =
|
|
4930
|
+
if (!fs17__default.default.existsSync(dir)) return [];
|
|
4931
|
+
const entries = fs17__default.default.readdirSync(dir, { withFileTypes: true });
|
|
4911
4932
|
const files = [];
|
|
4912
4933
|
for (const entry of entries) {
|
|
4913
4934
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "__tests__" || entry.name.startsWith(".")) {
|
|
4914
4935
|
continue;
|
|
4915
4936
|
}
|
|
4916
|
-
const fullPath =
|
|
4937
|
+
const fullPath = path26__default.default.join(dir, entry.name);
|
|
4917
4938
|
if (entry.isDirectory()) {
|
|
4918
4939
|
files.push(...scanDirFiles(fullPath, projectRoot));
|
|
4919
4940
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !isTestFile2(fullPath, projectRoot)) {
|
|
@@ -4922,42 +4943,19 @@ function scanDirFiles(dir, projectRoot) {
|
|
|
4922
4943
|
}
|
|
4923
4944
|
return files;
|
|
4924
4945
|
}
|
|
4925
|
-
function classifyFile(
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
} else if (subfolder === "infrastructure") {
|
|
4939
|
-
layer = "infrastructure";
|
|
4940
|
-
} else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
|
|
4941
|
-
layer = "presentation";
|
|
4942
|
-
}
|
|
4943
|
-
return { moduleType: "feature", moduleName: feature, feature, layer };
|
|
4944
|
-
}
|
|
4945
|
-
const sharedMatch = rel.match(/(?:^|\/)(?:src\/)?shared\/([^/]+)(?:\/(.*))?$/);
|
|
4946
|
-
if (sharedMatch && sharedMatch[1]) {
|
|
4947
|
-
const moduleName = sharedMatch[1];
|
|
4948
|
-
const rest = sharedMatch[2] || "";
|
|
4949
|
-
let layer = "root";
|
|
4950
|
-
if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
|
|
4951
|
-
layer = "domain";
|
|
4952
|
-
} else if (rest.startsWith("ports/") || rest === "ports") {
|
|
4953
|
-
layer = "ports";
|
|
4954
|
-
} else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
|
|
4955
|
-
layer = "infrastructure";
|
|
4956
|
-
}
|
|
4957
|
-
return { moduleType: "shared", moduleName, feature: moduleName, layer };
|
|
4958
|
-
}
|
|
4959
|
-
const errorMatch = rel.match(/(?:^|\/)(?:src\/)?errors(?:\/(.*))?$/);
|
|
4960
|
-
if (errorMatch) {
|
|
4946
|
+
function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
|
|
4947
|
+
if (!sharedBaseAbs || !errorsBaseAbs) {
|
|
4948
|
+
const paths = getResolvedLintPaths(featuresBaseAbs, loadLintConfig(featuresBaseAbs));
|
|
4949
|
+
featuresBaseAbs = paths.featuresBase;
|
|
4950
|
+
sharedBaseAbs = paths.sharedBase;
|
|
4951
|
+
errorsBaseAbs = paths.errorsBase;
|
|
4952
|
+
}
|
|
4953
|
+
const normFullPath = path26__default.default.resolve(fullPathAbs);
|
|
4954
|
+
const normErrorsBase = path26__default.default.resolve(errorsBaseAbs);
|
|
4955
|
+
const normSharedBase = path26__default.default.resolve(sharedBaseAbs);
|
|
4956
|
+
const normFeaturesBase = path26__default.default.resolve(featuresBaseAbs);
|
|
4957
|
+
const relErrors = path26__default.default.relative(normErrorsBase, normFullPath).replace(/\\/g, "/");
|
|
4958
|
+
if (!relErrors.startsWith("..") && !path26__default.default.isAbsolute(relErrors)) {
|
|
4961
4959
|
return {
|
|
4962
4960
|
moduleType: "error",
|
|
4963
4961
|
moduleName: "global-errors",
|
|
@@ -4965,46 +4963,154 @@ function classifyFile(fullPath, projectRoot) {
|
|
|
4965
4963
|
layer: "domain"
|
|
4966
4964
|
};
|
|
4967
4965
|
}
|
|
4966
|
+
const relShared = path26__default.default.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
|
|
4967
|
+
if (!relShared.startsWith("..") && !path26__default.default.isAbsolute(relShared)) {
|
|
4968
|
+
const parts = relShared.split("/").filter(Boolean);
|
|
4969
|
+
if (parts.length >= 1) {
|
|
4970
|
+
const moduleName = parts[0];
|
|
4971
|
+
const rest = parts.slice(1).join("/");
|
|
4972
|
+
let layer = "root";
|
|
4973
|
+
if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
|
|
4974
|
+
layer = "domain";
|
|
4975
|
+
} else if (rest.startsWith("ports/") || rest === "ports") {
|
|
4976
|
+
layer = "ports";
|
|
4977
|
+
} else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
|
|
4978
|
+
layer = "infrastructure";
|
|
4979
|
+
}
|
|
4980
|
+
return { moduleType: "shared", moduleName, feature: moduleName, layer };
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
const relFeatures = path26__default.default.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
|
|
4984
|
+
if (!relFeatures.startsWith("..") && !path26__default.default.isAbsolute(relFeatures)) {
|
|
4985
|
+
const parts = relFeatures.split("/").filter(Boolean);
|
|
4986
|
+
if (parts.length >= 2) {
|
|
4987
|
+
const moduleName = parts[0];
|
|
4988
|
+
const subfolder = parts[1];
|
|
4989
|
+
let layer;
|
|
4990
|
+
if (subfolder === "domain" || subfolder === "errors") {
|
|
4991
|
+
layer = "domain";
|
|
4992
|
+
} else if (subfolder === "useCases" || subfolder === "usecases") {
|
|
4993
|
+
layer = "useCases";
|
|
4994
|
+
} else if (subfolder === "services") {
|
|
4995
|
+
layer = "services";
|
|
4996
|
+
} else if (subfolder === "infrastructure") {
|
|
4997
|
+
layer = "infrastructure";
|
|
4998
|
+
} else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
|
|
4999
|
+
layer = "presentation";
|
|
5000
|
+
}
|
|
5001
|
+
return { moduleType: "feature", moduleName, feature: moduleName, layer };
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
4968
5004
|
return {};
|
|
4969
5005
|
}
|
|
4970
|
-
function classifyTarget(specifier, sourceFileAbs, projectRoot) {
|
|
5006
|
+
function classifyTarget(specifier, sourceFileAbs, projectRoot, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
|
|
4971
5007
|
if (specifier === "@solid-stack/di" || specifier.startsWith("@solid-stack/di/")) {
|
|
4972
5008
|
return { isExternal: true, isDiFramework: true };
|
|
4973
5009
|
}
|
|
4974
|
-
if (specifier.startsWith("node:") || [
|
|
5010
|
+
if (specifier.startsWith("node:") || [
|
|
5011
|
+
"crypto",
|
|
5012
|
+
"fs",
|
|
5013
|
+
"path",
|
|
5014
|
+
"http",
|
|
5015
|
+
"https",
|
|
5016
|
+
"url",
|
|
5017
|
+
"os",
|
|
5018
|
+
"child_process",
|
|
5019
|
+
"stream",
|
|
5020
|
+
"express",
|
|
5021
|
+
"cors",
|
|
5022
|
+
"dotenv"
|
|
5023
|
+
].includes(specifier)) {
|
|
4975
5024
|
return { isExternal: true, isDiFramework: false };
|
|
4976
5025
|
}
|
|
4977
|
-
|
|
5026
|
+
if (!featuresBaseAbs || !sharedBaseAbs || !errorsBaseAbs) {
|
|
5027
|
+
const paths = getResolvedLintPaths(projectRoot, loadLintConfig(projectRoot));
|
|
5028
|
+
featuresBaseAbs = featuresBaseAbs || paths.featuresBase;
|
|
5029
|
+
sharedBaseAbs = sharedBaseAbs || paths.sharedBase;
|
|
5030
|
+
errorsBaseAbs = errorsBaseAbs || paths.errorsBase;
|
|
5031
|
+
}
|
|
5032
|
+
const isGlobalConfig = specifier === "@configs" || specifier.startsWith("@configs/") || specifier === "@/configs" || specifier.startsWith("@/configs/") || specifier === "~/configs" || specifier.startsWith("~/configs/") || specifier === "configs" || specifier.startsWith("configs/");
|
|
5033
|
+
let targetAbs = null;
|
|
4978
5034
|
if (specifier.startsWith(".")) {
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5035
|
+
targetAbs = path26__default.default.resolve(path26__default.default.dirname(sourceFileAbs), specifier);
|
|
5036
|
+
} else {
|
|
5037
|
+
const featRel = path26__default.default.relative(projectRoot, featuresBaseAbs).replace(/\\/g, "/");
|
|
5038
|
+
const sharedRel = path26__default.default.relative(projectRoot, sharedBaseAbs).replace(/\\/g, "/");
|
|
5039
|
+
const errorsRel = path26__default.default.relative(projectRoot, errorsBaseAbs).replace(/\\/g, "/");
|
|
5040
|
+
const featPrefixes = ["features"];
|
|
5041
|
+
if (featRel && featRel !== "." && !featRel.startsWith("..")) {
|
|
5042
|
+
featPrefixes.push(featRel);
|
|
5043
|
+
const b = path26__default.default.basename(featRel);
|
|
5044
|
+
if (!featPrefixes.includes(b)) featPrefixes.push(b);
|
|
5045
|
+
}
|
|
5046
|
+
const sharedPrefixes = ["shared"];
|
|
5047
|
+
if (sharedRel && sharedRel !== "." && !sharedRel.startsWith("..")) {
|
|
5048
|
+
sharedPrefixes.push(sharedRel);
|
|
5049
|
+
const b = path26__default.default.basename(sharedRel);
|
|
5050
|
+
if (!sharedPrefixes.includes(b)) sharedPrefixes.push(b);
|
|
5051
|
+
}
|
|
5052
|
+
const errorsPrefixes = ["errors"];
|
|
5053
|
+
if (errorsRel && errorsRel !== "." && !errorsRel.startsWith("..")) {
|
|
5054
|
+
errorsPrefixes.push(errorsRel);
|
|
5055
|
+
const b = path26__default.default.basename(errorsRel);
|
|
5056
|
+
if (!errorsPrefixes.includes(b)) errorsPrefixes.push(b);
|
|
5057
|
+
}
|
|
5058
|
+
for (const prefix of featPrefixes) {
|
|
5059
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
|
|
5060
|
+
const m = specifier.match(aliasRegex);
|
|
5061
|
+
if (m && m[2]) {
|
|
5062
|
+
targetAbs = path26__default.default.resolve(featuresBaseAbs, m[2]);
|
|
5063
|
+
break;
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
5066
|
+
if (!targetAbs) {
|
|
5067
|
+
for (const prefix of sharedPrefixes) {
|
|
5068
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
|
|
5069
|
+
const m = specifier.match(aliasRegex);
|
|
5070
|
+
if (m && m[2]) {
|
|
5071
|
+
targetAbs = path26__default.default.resolve(sharedBaseAbs, m[2]);
|
|
5072
|
+
break;
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
if (!targetAbs) {
|
|
5077
|
+
for (const prefix of errorsPrefixes) {
|
|
5078
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}(?:\\/(.*))?$`);
|
|
5079
|
+
const m = specifier.match(aliasRegex);
|
|
5080
|
+
if (m) {
|
|
5081
|
+
targetAbs = path26__default.default.resolve(errorsBaseAbs, m[2] || "");
|
|
5082
|
+
break;
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
if (!targetAbs && (specifier.startsWith("@/") || specifier.startsWith("~/"))) {
|
|
5087
|
+
const sub = specifier.slice(2);
|
|
5088
|
+
const srcCandidate = path26__default.default.resolve(projectRoot, "src", sub);
|
|
5089
|
+
const rootCandidate = path26__default.default.resolve(projectRoot, sub);
|
|
5090
|
+
if (fs17__default.default.existsSync(srcCandidate)) {
|
|
5091
|
+
targetAbs = srcCandidate;
|
|
5092
|
+
} else if (fs17__default.default.existsSync(rootCandidate)) {
|
|
5093
|
+
targetAbs = rootCandidate;
|
|
5094
|
+
} else {
|
|
5095
|
+
targetAbs = srcCandidate;
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
if (!targetAbs) {
|
|
5099
|
+
const featCandidate = path26__default.default.resolve(featuresBaseAbs, specifier);
|
|
5100
|
+
if (fs17__default.default.existsSync(featCandidate) || fs17__default.default.existsSync(featCandidate + ".ts") || fs17__default.default.existsSync(featCandidate + ".js")) {
|
|
5101
|
+
targetAbs = featCandidate;
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
}
|
|
5105
|
+
if (!targetAbs) {
|
|
5106
|
+
return { isExternal: true, isDiFramework: false, isGlobalConfig };
|
|
5004
5107
|
}
|
|
5005
|
-
const
|
|
5006
|
-
const
|
|
5007
|
-
|
|
5108
|
+
const normTarget = path26__default.default.resolve(targetAbs);
|
|
5109
|
+
const srcConfig = path26__default.default.resolve(projectRoot, "src/configs");
|
|
5110
|
+
const rootConfig = path26__default.default.resolve(projectRoot, "configs");
|
|
5111
|
+
const isTargetConfig = isGlobalConfig || normTarget === srcConfig || normTarget.startsWith(srcConfig + path26__default.default.sep) || normTarget === rootConfig || normTarget.startsWith(rootConfig + path26__default.default.sep);
|
|
5112
|
+
const classification = classifyFile(targetAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs);
|
|
5113
|
+
if (classification.moduleType === "error") {
|
|
5008
5114
|
return {
|
|
5009
5115
|
isExternal: false,
|
|
5010
5116
|
isDiFramework: false,
|
|
@@ -5012,33 +5118,19 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
|
|
|
5012
5118
|
isTargetError: true
|
|
5013
5119
|
};
|
|
5014
5120
|
}
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
const
|
|
5018
|
-
const targetSubfolder =
|
|
5019
|
-
const
|
|
5020
|
-
let targetLayer;
|
|
5021
|
-
if (targetSubfolder === "domain" || targetSubfolder === "errors") {
|
|
5022
|
-
targetLayer = "domain";
|
|
5023
|
-
} else if (targetSubfolder === "useCases" || targetSubfolder === "usecases") {
|
|
5024
|
-
targetLayer = "useCases";
|
|
5025
|
-
} else if (targetSubfolder === "services") {
|
|
5026
|
-
targetLayer = "services";
|
|
5027
|
-
} else if (targetSubfolder === "infrastructure") {
|
|
5028
|
-
targetLayer = "infrastructure";
|
|
5029
|
-
} else if (targetSubfolder === "pxExpress" || targetSubfolder === "presentation" || targetSubfolder === "handlers" || targetSubfolder.startsWith("px")) {
|
|
5030
|
-
targetLayer = "presentation";
|
|
5031
|
-
}
|
|
5032
|
-
const basePart = rest ? path2__default.default.basename(rest) : targetSubfolder;
|
|
5033
|
-
const targetFileName = basePart.replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
5121
|
+
if (classification.moduleType === "feature") {
|
|
5122
|
+
const rel = path26__default.default.relative(featuresBaseAbs, targetAbs).replace(/\\/g, "/");
|
|
5123
|
+
const parts = rel.split("/").filter(Boolean);
|
|
5124
|
+
const targetSubfolder = parts[1];
|
|
5125
|
+
const targetFileName = path26__default.default.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
5034
5126
|
const isTargetPort = /^I[A-Z]/.test(targetFileName);
|
|
5035
5127
|
const isTargetRepo = isTargetPort && targetFileName.includes("Repo");
|
|
5036
|
-
const isTargetError = targetSubfolder === "errors" ||
|
|
5128
|
+
const isTargetError = targetSubfolder === "errors" || rel.includes("/errors/") || targetFileName.endsWith("Error") || targetFileName.endsWith("Errors");
|
|
5037
5129
|
return {
|
|
5038
5130
|
isExternal: false,
|
|
5039
5131
|
isDiFramework: false,
|
|
5040
|
-
targetFeature,
|
|
5041
|
-
targetLayer,
|
|
5132
|
+
targetFeature: classification.moduleName,
|
|
5133
|
+
targetLayer: classification.layer,
|
|
5042
5134
|
targetSubfolder,
|
|
5043
5135
|
targetFileName,
|
|
5044
5136
|
isTargetPort,
|
|
@@ -5046,25 +5138,21 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
|
|
|
5046
5138
|
isTargetError
|
|
5047
5139
|
};
|
|
5048
5140
|
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
const
|
|
5052
|
-
const sharedRest = sharedMatch[2] || "";
|
|
5053
|
-
const isSharedRoot = !sharedRest.includes("/");
|
|
5054
|
-
const isSharedPorts = sharedRest.startsWith("ports/") || sharedRest === "ports";
|
|
5055
|
-
const isSharedInfra = sharedRest.startsWith("infrastructure/") || sharedRest === "infrastructure";
|
|
5056
|
-
const isSharedDomain = sharedRest.startsWith("domain/") || sharedRest === "domain";
|
|
5141
|
+
if (classification.moduleType === "shared") {
|
|
5142
|
+
const targetFileName = path26__default.default.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
5143
|
+
const isTargetError = classification.layer === "domain" && (targetFileName.endsWith("Error") || targetFileName.endsWith("Errors") || targetAbs.includes("/errors/"));
|
|
5057
5144
|
return {
|
|
5058
5145
|
isExternal: false,
|
|
5059
5146
|
isDiFramework: false,
|
|
5060
|
-
targetSharedModule,
|
|
5061
|
-
isSharedRoot,
|
|
5062
|
-
isSharedPorts,
|
|
5063
|
-
isSharedInfra,
|
|
5064
|
-
isSharedDomain
|
|
5147
|
+
targetSharedModule: classification.moduleName,
|
|
5148
|
+
isSharedRoot: classification.layer === "root",
|
|
5149
|
+
isSharedPorts: classification.layer === "ports",
|
|
5150
|
+
isSharedInfra: classification.layer === "infrastructure",
|
|
5151
|
+
isSharedDomain: classification.layer === "domain",
|
|
5152
|
+
isTargetError
|
|
5065
5153
|
};
|
|
5066
5154
|
}
|
|
5067
|
-
return { isExternal: true, isDiFramework: false, isGlobalConfig };
|
|
5155
|
+
return { isExternal: true, isDiFramework: false, isGlobalConfig: isTargetConfig };
|
|
5068
5156
|
}
|
|
5069
5157
|
function extractImportStatements(content) {
|
|
5070
5158
|
const statements = [];
|
|
@@ -5186,22 +5274,50 @@ var FeatureDependencyGraph = class {
|
|
|
5186
5274
|
return dfs(start);
|
|
5187
5275
|
}
|
|
5188
5276
|
};
|
|
5189
|
-
function discoverAllFeatures(
|
|
5190
|
-
const
|
|
5191
|
-
if (!
|
|
5192
|
-
const
|
|
5193
|
-
|
|
5277
|
+
function discoverAllFeatures(featuresBaseAbs, excludeDirs = []) {
|
|
5278
|
+
const base = featuresBaseAbs;
|
|
5279
|
+
if (!fs17__default.default.existsSync(base)) return [];
|
|
5280
|
+
const excludeSet = new Set(excludeDirs.map((d) => path26__default.default.resolve(d)));
|
|
5281
|
+
const entries = fs17__default.default.readdirSync(base, { withFileTypes: true });
|
|
5282
|
+
return entries.filter((e) => {
|
|
5283
|
+
if (!e.isDirectory()) return false;
|
|
5284
|
+
if (e.name.startsWith(".")) return false;
|
|
5285
|
+
if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
|
|
5286
|
+
return false;
|
|
5287
|
+
}
|
|
5288
|
+
const resolved = path26__default.default.resolve(base, e.name);
|
|
5289
|
+
for (const ex of excludeSet) {
|
|
5290
|
+
if (ex === resolved || ex.startsWith(resolved + path26__default.default.sep) || resolved.startsWith(ex + path26__default.default.sep)) {
|
|
5291
|
+
return false;
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
return true;
|
|
5295
|
+
}).map((e) => ({
|
|
5194
5296
|
name: e.name,
|
|
5195
|
-
dir:
|
|
5297
|
+
dir: path26__default.default.join(base, e.name)
|
|
5196
5298
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
5197
5299
|
}
|
|
5198
|
-
function discoverAllShared(
|
|
5199
|
-
const
|
|
5200
|
-
if (!
|
|
5201
|
-
const
|
|
5202
|
-
|
|
5300
|
+
function discoverAllShared(sharedBaseAbs, excludeDirs = []) {
|
|
5301
|
+
const base = sharedBaseAbs;
|
|
5302
|
+
if (!fs17__default.default.existsSync(base)) return [];
|
|
5303
|
+
const excludeSet = new Set(excludeDirs.map((d) => path26__default.default.resolve(d)));
|
|
5304
|
+
const entries = fs17__default.default.readdirSync(base, { withFileTypes: true });
|
|
5305
|
+
return entries.filter((e) => {
|
|
5306
|
+
if (!e.isDirectory()) return false;
|
|
5307
|
+
if (e.name.startsWith(".")) return false;
|
|
5308
|
+
if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
|
|
5309
|
+
return false;
|
|
5310
|
+
}
|
|
5311
|
+
const resolved = path26__default.default.resolve(base, e.name);
|
|
5312
|
+
for (const ex of excludeSet) {
|
|
5313
|
+
if (ex === resolved || ex.startsWith(resolved + path26__default.default.sep) || resolved.startsWith(ex + path26__default.default.sep)) {
|
|
5314
|
+
return false;
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
return true;
|
|
5318
|
+
}).map((e) => ({
|
|
5203
5319
|
name: e.name,
|
|
5204
|
-
dir:
|
|
5320
|
+
dir: path26__default.default.join(base, e.name)
|
|
5205
5321
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
5206
5322
|
}
|
|
5207
5323
|
function extractClassMethods(content, className) {
|
|
@@ -5357,7 +5473,7 @@ function extractClassMethods(content, className) {
|
|
|
5357
5473
|
return methods;
|
|
5358
5474
|
}
|
|
5359
5475
|
function checkUseCaseShape(featureName, filePath, relativePath, content, addViolation) {
|
|
5360
|
-
const fileName =
|
|
5476
|
+
const fileName = path26__default.default.basename(filePath);
|
|
5361
5477
|
const lines = content.split(/\r?\n/);
|
|
5362
5478
|
const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
|
|
5363
5479
|
if (!classMatch) {
|
|
@@ -5453,7 +5569,7 @@ private ${m.name}(...) { ... }`
|
|
|
5453
5569
|
}
|
|
5454
5570
|
}
|
|
5455
5571
|
function checkServiceShape(featureName, filePath, relativePath, content, addViolation) {
|
|
5456
|
-
const fileName =
|
|
5572
|
+
const fileName = path26__default.default.basename(filePath);
|
|
5457
5573
|
const lines = content.split(/\r?\n/);
|
|
5458
5574
|
const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
|
|
5459
5575
|
if (!classMatch) {
|
|
@@ -5553,18 +5669,11 @@ function lintCodebase(options = {}) {
|
|
|
5553
5669
|
const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
|
|
5554
5670
|
const failFast = !options.complete;
|
|
5555
5671
|
const lintConfig = loadLintConfig(projectRoot);
|
|
5556
|
-
const
|
|
5557
|
-
const baseErrorAbs = path2__default.default.resolve(projectRoot, baseErrorRelative);
|
|
5558
|
-
const featuresBase = resolveFeaturesDir(projectRoot);
|
|
5559
|
-
const sharedBase = resolveSharedDir(projectRoot);
|
|
5560
|
-
let errorsBase = path2__default.default.join(projectRoot, "src/errors");
|
|
5561
|
-
if (!fs4__default.default.existsSync(errorsBase) && fs4__default.default.existsSync(path2__default.default.join(projectRoot, "errors"))) {
|
|
5562
|
-
errorsBase = path2__default.default.join(projectRoot, "errors");
|
|
5563
|
-
}
|
|
5672
|
+
const { featuresBase, sharedBase, errorsBase } = getResolvedLintPaths(projectRoot, lintConfig);
|
|
5564
5673
|
const missingFoundations = [];
|
|
5565
|
-
if (!
|
|
5566
|
-
if (!
|
|
5567
|
-
if (!
|
|
5674
|
+
if (!fs17__default.default.existsSync(featuresBase)) missingFoundations.push("features/");
|
|
5675
|
+
if (!fs17__default.default.existsSync(sharedBase)) missingFoundations.push("shared/");
|
|
5676
|
+
if (!fs17__default.default.existsSync(errorsBase)) missingFoundations.push("errors/");
|
|
5568
5677
|
if (missingFoundations.length > 0) {
|
|
5569
5678
|
throw new DependencyRuleError(
|
|
5570
5679
|
`Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every project must contain 'features/', 'shared/', and 'errors/'.`,
|
|
@@ -5572,20 +5681,22 @@ function lintCodebase(options = {}) {
|
|
|
5572
5681
|
true
|
|
5573
5682
|
);
|
|
5574
5683
|
}
|
|
5575
|
-
|
|
5684
|
+
const baseErrorRelative = lintConfig.baseErrorPath || path26__default.default.relative(projectRoot, path26__default.default.join(errorsBase, "AppError.ts")).replace(/\\/g, "/");
|
|
5685
|
+
const baseErrorAbs = path26__default.default.resolve(projectRoot, baseErrorRelative);
|
|
5686
|
+
if (!fs17__default.default.existsSync(baseErrorAbs)) {
|
|
5576
5687
|
throw new DependencyRuleError(
|
|
5577
5688
|
`Project Structure Violation: Base error class not found at '${baseErrorRelative}'. Create this file or update 'baseErrorPath' in mason-lint.config.json.`,
|
|
5578
5689
|
[],
|
|
5579
5690
|
true
|
|
5580
5691
|
);
|
|
5581
5692
|
}
|
|
5582
|
-
const baseErrorContent =
|
|
5693
|
+
const baseErrorContent = fs17__default.default.readFileSync(baseErrorAbs, "utf-8");
|
|
5583
5694
|
const baseClassMatch = baseErrorContent.match(
|
|
5584
5695
|
/(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)/
|
|
5585
5696
|
);
|
|
5586
5697
|
const baseErrorClassName = baseClassMatch ? baseClassMatch[1] : "AppError";
|
|
5587
|
-
const features = discoverAllFeatures(
|
|
5588
|
-
const sharedModules = discoverAllShared(
|
|
5698
|
+
const features = discoverAllFeatures(featuresBase, [sharedBase, errorsBase]);
|
|
5699
|
+
const sharedModules = discoverAllShared(sharedBase, [featuresBase, errorsBase]);
|
|
5589
5700
|
const errorModule = { name: "global-errors", dir: errorsBase, type: "error" };
|
|
5590
5701
|
const allModules = [
|
|
5591
5702
|
...features.map((f) => ({ ...f, type: "feature" })),
|
|
@@ -5628,12 +5739,12 @@ Code: ${v.code}`;
|
|
|
5628
5739
|
const allFiles = scanDirFiles(mod.dir, projectRoot);
|
|
5629
5740
|
modResult.scannedFilesCount = allFiles.length;
|
|
5630
5741
|
for (const file of allFiles) {
|
|
5631
|
-
const relPath =
|
|
5632
|
-
const { moduleType, moduleName, layer } = classifyFile(file,
|
|
5742
|
+
const relPath = path26__default.default.relative(projectRoot, file).replace(/\\/g, "/");
|
|
5743
|
+
const { moduleType, moduleName, layer } = classifyFile(file, featuresBase, sharedBase, errorsBase);
|
|
5633
5744
|
if (!layer || !moduleType || !moduleName) continue;
|
|
5634
|
-
const content =
|
|
5745
|
+
const content = fs17__default.default.readFileSync(file, "utf-8");
|
|
5635
5746
|
const statements = extractImportStatements(content);
|
|
5636
|
-
const baseName =
|
|
5747
|
+
const baseName = path26__default.default.basename(file);
|
|
5637
5748
|
const isBarrel = baseName === "index.ts" || baseName === "index.js";
|
|
5638
5749
|
const throwErrorRegex = /\bthrow\s+(?:new\s+)?Error\s*\(/g;
|
|
5639
5750
|
let throwMatch;
|
|
@@ -5660,7 +5771,7 @@ Code: ${v.code}`;
|
|
|
5660
5771
|
});
|
|
5661
5772
|
}
|
|
5662
5773
|
const isErrorFile = relPath.includes("/errors/") || relPath.startsWith("errors/") || relPath.startsWith("src/errors/") || moduleType === "error" || baseName.endsWith("Error.ts") || baseName.endsWith("Errors.ts") || baseName.endsWith("Error.js") || baseName.endsWith("Errors.js");
|
|
5663
|
-
const isBaseErrorFile =
|
|
5774
|
+
const isBaseErrorFile = path26__default.default.resolve(file) === path26__default.default.resolve(baseErrorAbs);
|
|
5664
5775
|
if (isErrorFile && !isBaseErrorFile) {
|
|
5665
5776
|
const classRegex = /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)(?:<[^>]+>)?(?:\s+extends\s+([A-Za-z0-9_]+))?/g;
|
|
5666
5777
|
let classMatch;
|
|
@@ -5710,7 +5821,7 @@ Code: ${v.code}`;
|
|
|
5710
5821
|
}
|
|
5711
5822
|
if (moduleType === "error") {
|
|
5712
5823
|
for (const stmt of statements) {
|
|
5713
|
-
const target = classifyTarget(stmt.specifier, file, projectRoot);
|
|
5824
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5714
5825
|
if (target.targetFeature) {
|
|
5715
5826
|
addViolation({
|
|
5716
5827
|
feature: "global-errors",
|
|
@@ -5776,7 +5887,7 @@ Code: ${v.code}`;
|
|
|
5776
5887
|
}
|
|
5777
5888
|
}
|
|
5778
5889
|
for (const stmt of statements) {
|
|
5779
|
-
const target = classifyTarget(stmt.specifier, file, projectRoot);
|
|
5890
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5780
5891
|
if (target.targetFeature) {
|
|
5781
5892
|
addViolation({
|
|
5782
5893
|
feature: moduleName,
|
|
@@ -5906,7 +6017,7 @@ Code: ${v.code}`;
|
|
|
5906
6017
|
}
|
|
5907
6018
|
}
|
|
5908
6019
|
for (const stmt of statements) {
|
|
5909
|
-
const target = classifyTarget(stmt.specifier, file, projectRoot);
|
|
6020
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5910
6021
|
if (target.targetFeature && target.targetFeature !== feat.name) {
|
|
5911
6022
|
const evidence = {
|
|
5912
6023
|
fromFeature: feat.name,
|
|
@@ -6817,6 +6928,7 @@ exports.getConfiguredSharedDir = getConfiguredSharedDir;
|
|
|
6817
6928
|
exports.getEffectiveMode = getEffectiveMode;
|
|
6818
6929
|
exports.getMissingNpmPackages = getMissingNpmPackages;
|
|
6819
6930
|
exports.getRegistryBase = getRegistryBase;
|
|
6931
|
+
exports.getResolvedLintPaths = getResolvedLintPaths;
|
|
6820
6932
|
exports.getTemplatesDir = getTemplatesDir;
|
|
6821
6933
|
exports.handleCancel = handleCancel;
|
|
6822
6934
|
exports.handleCreate = handleCreate;
|