@echojs-ecosystem/architect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +791 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +170 -0
- package/dist/index.js +711 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { defineCommand, runMain } from 'citty';
|
|
3
|
+
import { relative, join, dirname, resolve, sep, basename } from 'path';
|
|
4
|
+
import * as process2 from 'process';
|
|
5
|
+
import process2__default from 'process';
|
|
6
|
+
import { fromError } from 'zod-validation-error';
|
|
7
|
+
import { ZodError, z } from 'zod';
|
|
8
|
+
import { loadConfig, watchConfig as watchConfig$1 } from 'c12';
|
|
9
|
+
import { map, switchMap, catchError, from, Observable, debounceTime, filter } from 'rxjs';
|
|
10
|
+
import { open, rm, mkdir, rename } from 'fs/promises';
|
|
11
|
+
import ts from 'typescript';
|
|
12
|
+
import { minimatch } from 'minimatch';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import precinct from 'precinct';
|
|
15
|
+
import { parse } from 'tsconfck';
|
|
16
|
+
import { produce } from 'immer';
|
|
17
|
+
import chokidar from 'chokidar';
|
|
18
|
+
import { isGitIgnored } from 'globby';
|
|
19
|
+
import chalk from 'chalk';
|
|
20
|
+
import figures from 'figures';
|
|
21
|
+
import terminalLink from 'terminal-link';
|
|
22
|
+
import prexit from 'prexit';
|
|
23
|
+
|
|
24
|
+
var __defProp = Object.defineProperty;
|
|
25
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
26
|
+
var __esm = (fn, res) => function __init() {
|
|
27
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
28
|
+
};
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/cli/commands/init.ts
|
|
35
|
+
var init_exports = {};
|
|
36
|
+
__export(init_exports, {
|
|
37
|
+
default: () => init_default
|
|
38
|
+
});
|
|
39
|
+
var init_default;
|
|
40
|
+
var init_init = __esm({
|
|
41
|
+
"src/cli/commands/init.ts"() {
|
|
42
|
+
init_default = defineCommand({
|
|
43
|
+
meta: {
|
|
44
|
+
name: "init",
|
|
45
|
+
description: "Initialize a fresh project"
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
var ConfigurationNotFoundError, ConfigurationInvalidError;
|
|
51
|
+
var init_errors = __esm({
|
|
52
|
+
"src/config/errors.ts"() {
|
|
53
|
+
ConfigurationNotFoundError = class extends Error {
|
|
54
|
+
constructor() {
|
|
55
|
+
super(`Configuration not found in ${process2.cwd()}`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
ConfigurationInvalidError = class extends Error {
|
|
59
|
+
constructor(error, filepath) {
|
|
60
|
+
super(
|
|
61
|
+
fromError(error, {
|
|
62
|
+
prefix: `Invalid configuration in ${relative(process2.cwd(), filepath)}`
|
|
63
|
+
}).toString()
|
|
64
|
+
);
|
|
65
|
+
this.error = error;
|
|
66
|
+
}
|
|
67
|
+
error;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
var RuleSchema, AbstractionSchema, EvolutionConfigSchema;
|
|
72
|
+
var init_schema = __esm({
|
|
73
|
+
"src/config/schema.ts"() {
|
|
74
|
+
RuleSchema = z.object({
|
|
75
|
+
name: z.string(),
|
|
76
|
+
check: z.custom(),
|
|
77
|
+
severity: z.enum(["off", "warn", "error"]),
|
|
78
|
+
descriptionUrl: z.string().optional()
|
|
79
|
+
});
|
|
80
|
+
AbstractionSchema = z.object({
|
|
81
|
+
name: z.string(),
|
|
82
|
+
children: z.record(z.lazy(() => AbstractionSchema)),
|
|
83
|
+
rules: z.array(RuleSchema),
|
|
84
|
+
fractal: z.string().optional(),
|
|
85
|
+
fileTemplate: z.custom()
|
|
86
|
+
});
|
|
87
|
+
EvolutionConfigSchema = z.object({
|
|
88
|
+
root: AbstractionSchema,
|
|
89
|
+
baseUrl: z.string().optional(),
|
|
90
|
+
files: z.array(z.string()).optional(),
|
|
91
|
+
ignores: z.array(z.string()).optional()
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
var CONFIG_NAME, parseConfigResult, watchConfig;
|
|
96
|
+
var init_load = __esm({
|
|
97
|
+
"src/config/load.ts"() {
|
|
98
|
+
init_errors();
|
|
99
|
+
init_schema();
|
|
100
|
+
CONFIG_NAME = "architect";
|
|
101
|
+
parseConfigResult = (filepath, data) => {
|
|
102
|
+
const parseResult = EvolutionConfigSchema.safeParse(data);
|
|
103
|
+
if (!parseResult.success) {
|
|
104
|
+
throw new ConfigurationInvalidError(parseResult.error, filepath);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
config: parseResult.data,
|
|
108
|
+
configPath: filepath
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
watchConfig = ({
|
|
112
|
+
cwd: cwd2,
|
|
113
|
+
onlyOne
|
|
114
|
+
}) => {
|
|
115
|
+
const config$ = from(
|
|
116
|
+
loadConfig({
|
|
117
|
+
cwd: cwd2,
|
|
118
|
+
name: CONFIG_NAME
|
|
119
|
+
})
|
|
120
|
+
).pipe(
|
|
121
|
+
map(({ configFile, config }) => {
|
|
122
|
+
if (!configFile) {
|
|
123
|
+
throw new ConfigurationNotFoundError();
|
|
124
|
+
}
|
|
125
|
+
return parseConfigResult(configFile, config);
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
if (onlyOne) {
|
|
129
|
+
return config$;
|
|
130
|
+
}
|
|
131
|
+
return config$.pipe(
|
|
132
|
+
switchMap(
|
|
133
|
+
({ configPath, config }) => new Observable((subscriber) => {
|
|
134
|
+
subscriber.next({ configPath, config });
|
|
135
|
+
let unwatchCallback = () => {
|
|
136
|
+
};
|
|
137
|
+
watchConfig$1({
|
|
138
|
+
cwd: cwd2,
|
|
139
|
+
name: CONFIG_NAME,
|
|
140
|
+
onUpdate: (config2) => {
|
|
141
|
+
subscriber.next(
|
|
142
|
+
parseConfigResult(configPath, config2.newConfig.config)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}).then(({ unwatch }) => {
|
|
146
|
+
unwatchCallback = unwatch;
|
|
147
|
+
});
|
|
148
|
+
return () => unwatchCallback();
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
var applyAutofixes, tryToApplyFixes;
|
|
156
|
+
var init_auto_fix = __esm({
|
|
157
|
+
"src/linter/auto-fix.ts"() {
|
|
158
|
+
applyAutofixes = async (diagnostics) => {
|
|
159
|
+
const stillRelevantDiagnostics = [];
|
|
160
|
+
const fixableDiagnostics = [];
|
|
161
|
+
for (const diagnostic of diagnostics) {
|
|
162
|
+
const fixes = diagnostic.fixes;
|
|
163
|
+
if (!fixes) {
|
|
164
|
+
stillRelevantDiagnostics.push(diagnostic);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
fixableDiagnostics.push(diagnostic);
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
await Promise.all(fixableDiagnostics.map(tryToApplyFixes));
|
|
171
|
+
} catch (error) {
|
|
172
|
+
stillRelevantDiagnostics.push(...fixableDiagnostics);
|
|
173
|
+
console.error(error);
|
|
174
|
+
}
|
|
175
|
+
return stillRelevantDiagnostics;
|
|
176
|
+
};
|
|
177
|
+
tryToApplyFixes = async (diagnostic) => {
|
|
178
|
+
const fixes = diagnostic.fixes ?? [];
|
|
179
|
+
return Promise.all(
|
|
180
|
+
fixes.map((fix) => {
|
|
181
|
+
switch (fix.type) {
|
|
182
|
+
case "rename":
|
|
183
|
+
return rename(fix.path, join(dirname(fix.path), fix.newName));
|
|
184
|
+
case "create-file":
|
|
185
|
+
return open(fix.path, "w").then((file) => {
|
|
186
|
+
file.write(fix.content);
|
|
187
|
+
return file.close();
|
|
188
|
+
});
|
|
189
|
+
case "create-folder":
|
|
190
|
+
return mkdir(fix.path, { recursive: true });
|
|
191
|
+
case "delete":
|
|
192
|
+
return rm(fix.path, { recursive: true });
|
|
193
|
+
case "modify-file":
|
|
194
|
+
return open(fix.path, "w").then(async (file) => {
|
|
195
|
+
await file.write(fix.content);
|
|
196
|
+
return file.close();
|
|
197
|
+
});
|
|
198
|
+
default:
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// src/shared/memoize.ts
|
|
208
|
+
var memoize;
|
|
209
|
+
var init_memoize = __esm({
|
|
210
|
+
"src/shared/memoize.ts"() {
|
|
211
|
+
memoize = (fn) => {
|
|
212
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
213
|
+
return function(arg) {
|
|
214
|
+
if (cache.has(arg)) {
|
|
215
|
+
return cache.get(arg);
|
|
216
|
+
}
|
|
217
|
+
const result = fn.call(this, arg);
|
|
218
|
+
cache.set(arg, result);
|
|
219
|
+
return result;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
var resolveImport, imperfectKeys, normalizeCompilerOptions;
|
|
225
|
+
var init_resolve_import = __esm({
|
|
226
|
+
"src/shared/resolve-import.ts"() {
|
|
227
|
+
resolveImport = (importedPath, importerPath, tsCompilerOptions, fileExists, directoryExists) => {
|
|
228
|
+
return ts.resolveModuleName(
|
|
229
|
+
importedPath,
|
|
230
|
+
importerPath,
|
|
231
|
+
normalizeCompilerOptions(tsCompilerOptions),
|
|
232
|
+
{
|
|
233
|
+
...ts.sys,
|
|
234
|
+
fileExists,
|
|
235
|
+
directoryExists
|
|
236
|
+
}
|
|
237
|
+
).resolvedModule?.resolvedFileName?.replaceAll("/", sep) ?? null;
|
|
238
|
+
};
|
|
239
|
+
imperfectKeys = {
|
|
240
|
+
module: ts.ModuleKind,
|
|
241
|
+
moduleResolution: {
|
|
242
|
+
...ts.ModuleResolutionKind,
|
|
243
|
+
node: ts.ModuleResolutionKind.Node10
|
|
244
|
+
},
|
|
245
|
+
moduleDetection: ts.ModuleDetectionKind,
|
|
246
|
+
newLine: ts.NewLineKind,
|
|
247
|
+
target: ts.ScriptTarget
|
|
248
|
+
};
|
|
249
|
+
normalizeCompilerOptions = (compilerOptions) => {
|
|
250
|
+
return Object.fromEntries(
|
|
251
|
+
Object.entries(compilerOptions).map(([key, value]) => {
|
|
252
|
+
if (Object.keys(imperfectKeys).includes(key) && typeof value === "string") {
|
|
253
|
+
for (const [enumKey, enumValue] of Object.entries(
|
|
254
|
+
imperfectKeys[key]
|
|
255
|
+
)) {
|
|
256
|
+
if (enumKey.toLowerCase() === value.toLowerCase()) {
|
|
257
|
+
return [key, enumValue];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return [key, value];
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// src/shared/index.ts
|
|
269
|
+
var init_shared = __esm({
|
|
270
|
+
"src/shared/index.ts"() {
|
|
271
|
+
init_memoize();
|
|
272
|
+
init_resolve_import();
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
var parseAbstractionInstance;
|
|
276
|
+
var init_parse = __esm({
|
|
277
|
+
"src/abstraction/instance/parse.ts"() {
|
|
278
|
+
init_shared();
|
|
279
|
+
parseAbstractionInstance = memoize(
|
|
280
|
+
(abstraction) => memoize((node) => {
|
|
281
|
+
if (node.type === "file") {
|
|
282
|
+
return {
|
|
283
|
+
abstraction,
|
|
284
|
+
path: node.path,
|
|
285
|
+
children: [],
|
|
286
|
+
childNodes: []
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const children = {};
|
|
290
|
+
for (const [pattern, childAbstraction] of Object.entries(
|
|
291
|
+
abstraction.children
|
|
292
|
+
)) {
|
|
293
|
+
const nodeAbstractionInstance = parseAbstractionInstance(childAbstraction);
|
|
294
|
+
const nodesStack = [node];
|
|
295
|
+
while (nodesStack.length) {
|
|
296
|
+
const currentNode = nodesStack.pop();
|
|
297
|
+
if (minimatch(relative(node.path, currentNode.path), pattern)) {
|
|
298
|
+
children[currentNode.path] = nodeAbstractionInstance(currentNode);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (children[currentNode.path]) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (currentNode.type === "folder") {
|
|
305
|
+
nodesStack.push(...currentNode.children);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const childNodes = [];
|
|
310
|
+
const childrenNodesStack = [node];
|
|
311
|
+
while (childrenNodesStack.length) {
|
|
312
|
+
const currentNode = childrenNodesStack.pop();
|
|
313
|
+
if (children[currentNode.path]) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (currentNode.path !== node.path) {
|
|
317
|
+
childNodes.push(currentNode.path);
|
|
318
|
+
}
|
|
319
|
+
if (currentNode.type === "folder") {
|
|
320
|
+
childrenNodesStack.push(...currentNode.children);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
abstraction,
|
|
325
|
+
path: node.path,
|
|
326
|
+
childNodes: Object.values(childNodes),
|
|
327
|
+
children: Object.values(children)
|
|
328
|
+
};
|
|
329
|
+
})
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// src/vfs/get-flatten-files.ts
|
|
335
|
+
var getFlattenFiles;
|
|
336
|
+
var init_get_flatten_files = __esm({
|
|
337
|
+
"src/vfs/get-flatten-files.ts"() {
|
|
338
|
+
init_shared();
|
|
339
|
+
getFlattenFiles = memoize((node) => {
|
|
340
|
+
if (node.type === "file") {
|
|
341
|
+
return [node];
|
|
342
|
+
}
|
|
343
|
+
return node.children.reduce((acc, child) => {
|
|
344
|
+
if (child.type === "file") {
|
|
345
|
+
return [...acc, child];
|
|
346
|
+
}
|
|
347
|
+
return [...acc, ...getFlattenFiles(child)];
|
|
348
|
+
}, []);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
var paperwork, parseDependenciesMap;
|
|
353
|
+
var init_parse2 = __esm({
|
|
354
|
+
"src/dependencies/parse.ts"() {
|
|
355
|
+
init_shared();
|
|
356
|
+
init_get_flatten_files();
|
|
357
|
+
({ paperwork } = precinct);
|
|
358
|
+
parseDependenciesMap = async (vfs) => {
|
|
359
|
+
const dependenciesMap = {
|
|
360
|
+
dependencies: {},
|
|
361
|
+
dependencyFor: {}
|
|
362
|
+
};
|
|
363
|
+
const basePath = vfs.path;
|
|
364
|
+
const { tsconfig } = await parse(basePath);
|
|
365
|
+
const files = getFlattenFiles(vfs);
|
|
366
|
+
for (const file of files) {
|
|
367
|
+
const dependencies = paperwork(file.path, {
|
|
368
|
+
includeCore: false,
|
|
369
|
+
fileSystem: fs
|
|
370
|
+
});
|
|
371
|
+
const resolvedDependencies = dependencies.map(
|
|
372
|
+
(dependency) => resolveImport(
|
|
373
|
+
dependency,
|
|
374
|
+
file.path,
|
|
375
|
+
tsconfig?.compilerOptions ?? {},
|
|
376
|
+
fs.existsSync,
|
|
377
|
+
fs.existsSync
|
|
378
|
+
)
|
|
379
|
+
).filter((dependency) => dependency !== null);
|
|
380
|
+
dependenciesMap.dependencies[file.path] = new Set(resolvedDependencies);
|
|
381
|
+
for (const dependency of resolvedDependencies) {
|
|
382
|
+
if (!dependenciesMap.dependencyFor[dependency]) {
|
|
383
|
+
dependenciesMap.dependencyFor[dependency] = /* @__PURE__ */ new Set();
|
|
384
|
+
}
|
|
385
|
+
dependenciesMap.dependencyFor[dependency].add(file.path);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return dependenciesMap;
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
var addDirectory;
|
|
393
|
+
var init_add_directory = __esm({
|
|
394
|
+
"src/vfs/add-directory.ts"() {
|
|
395
|
+
addDirectory = (tree, newDirectoryPath) => {
|
|
396
|
+
const rootPath = tree.path;
|
|
397
|
+
return produce(tree, (draft) => {
|
|
398
|
+
const pathSegments = relative(rootPath, newDirectoryPath).split(sep);
|
|
399
|
+
let currentFolder = draft;
|
|
400
|
+
for (const pathSegment of pathSegments.slice(0, -1)) {
|
|
401
|
+
const existingChild = currentFolder.children.find(
|
|
402
|
+
(child) => child.type === "folder" && basename(child.path) === pathSegment
|
|
403
|
+
);
|
|
404
|
+
if (existingChild === void 0) {
|
|
405
|
+
currentFolder.children.push({
|
|
406
|
+
type: "folder",
|
|
407
|
+
path: join(currentFolder.path, pathSegment),
|
|
408
|
+
children: []
|
|
409
|
+
});
|
|
410
|
+
currentFolder = currentFolder.children[currentFolder.children.length - 1];
|
|
411
|
+
} else {
|
|
412
|
+
currentFolder = existingChild;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
currentFolder.children.push({
|
|
416
|
+
type: "folder",
|
|
417
|
+
path: newDirectoryPath,
|
|
418
|
+
children: []
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
var addFile;
|
|
425
|
+
var init_add_file = __esm({
|
|
426
|
+
"src/vfs/add-file.ts"() {
|
|
427
|
+
addFile = (tree, newFilePath) => {
|
|
428
|
+
const rootPath = tree.path;
|
|
429
|
+
return produce(tree, (draft) => {
|
|
430
|
+
const pathSegments = relative(rootPath, newFilePath).split(sep);
|
|
431
|
+
let currentFolder = draft;
|
|
432
|
+
for (const pathSegment of pathSegments.slice(0, -1)) {
|
|
433
|
+
const existingChild = currentFolder.children.find(
|
|
434
|
+
(child) => child.type === "folder" && basename(child.path) === pathSegment
|
|
435
|
+
);
|
|
436
|
+
if (existingChild === void 0) {
|
|
437
|
+
currentFolder.children.push({
|
|
438
|
+
type: "folder",
|
|
439
|
+
path: join(currentFolder.path, pathSegment),
|
|
440
|
+
children: []
|
|
441
|
+
});
|
|
442
|
+
currentFolder = currentFolder.children[currentFolder.children.length - 1];
|
|
443
|
+
} else {
|
|
444
|
+
currentFolder = existingChild;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
currentFolder.children.push({ type: "file", path: newFilePath });
|
|
448
|
+
});
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// src/vfs/create-root.ts
|
|
454
|
+
var createVfsRoot;
|
|
455
|
+
var init_create_root = __esm({
|
|
456
|
+
"src/vfs/create-root.ts"() {
|
|
457
|
+
createVfsRoot = (path) => ({
|
|
458
|
+
type: "folder",
|
|
459
|
+
path,
|
|
460
|
+
children: []
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
var removeNode;
|
|
465
|
+
var init_remove_node = __esm({
|
|
466
|
+
"src/vfs/remove-node.ts"() {
|
|
467
|
+
removeNode = (tree, removedNodePath) => {
|
|
468
|
+
const rootPath = tree.path;
|
|
469
|
+
return produce(tree, (draft) => {
|
|
470
|
+
const pathSegments = relative(rootPath, removedNodePath).split(sep);
|
|
471
|
+
let currentFolder = draft;
|
|
472
|
+
for (const pathSegment of pathSegments.slice(0, -1)) {
|
|
473
|
+
const existingChild = currentFolder.children.find(
|
|
474
|
+
(child) => child.type === "folder" && basename(child.path) === pathSegment
|
|
475
|
+
);
|
|
476
|
+
if (existingChild === void 0) {
|
|
477
|
+
return tree;
|
|
478
|
+
} else {
|
|
479
|
+
currentFolder = existingChild;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const removedNodeIndex = currentFolder.children.findIndex(
|
|
483
|
+
(child) => child.path === removedNodePath
|
|
484
|
+
);
|
|
485
|
+
if (removedNodeIndex === -1) {
|
|
486
|
+
return tree;
|
|
487
|
+
}
|
|
488
|
+
currentFolder.children.splice(removedNodeIndex, 1);
|
|
489
|
+
});
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
var watchFs, createWatcherObservable;
|
|
494
|
+
var init_watch_fs = __esm({
|
|
495
|
+
"src/vfs/watch-fs.ts"() {
|
|
496
|
+
init_add_directory();
|
|
497
|
+
init_add_file();
|
|
498
|
+
init_create_root();
|
|
499
|
+
init_remove_node();
|
|
500
|
+
watchFs = (path, { onlyReady } = {}) => {
|
|
501
|
+
const isIgnored$ = from(isGitIgnored({ cwd: path }));
|
|
502
|
+
let vfs$ = isIgnored$.pipe(
|
|
503
|
+
switchMap((isIgnored) => createWatcherObservable({ path, isIgnored }))
|
|
504
|
+
);
|
|
505
|
+
if (onlyReady) {
|
|
506
|
+
vfs$ = vfs$.pipe(filter((e) => e.type === "ready"));
|
|
507
|
+
}
|
|
508
|
+
return vfs$;
|
|
509
|
+
};
|
|
510
|
+
createWatcherObservable = ({
|
|
511
|
+
path,
|
|
512
|
+
isIgnored
|
|
513
|
+
}) => {
|
|
514
|
+
return new Observable((observer) => {
|
|
515
|
+
let vfs = createVfsRoot(path);
|
|
516
|
+
const watcher = chokidar.watch(path, {
|
|
517
|
+
ignored: (path2) => path2.split(sep).includes("node_modules") || isIgnored(path2),
|
|
518
|
+
ignoreInitial: false,
|
|
519
|
+
alwaysStat: true,
|
|
520
|
+
awaitWriteFinish: true,
|
|
521
|
+
disableGlobbing: true,
|
|
522
|
+
cwd: path
|
|
523
|
+
});
|
|
524
|
+
watcher.on("add", async (relativePath) => {
|
|
525
|
+
vfs = addFile(vfs, join(path, relativePath));
|
|
526
|
+
observer.next({ type: "add", vfs });
|
|
527
|
+
});
|
|
528
|
+
watcher.on("addDir", async (relativePath) => {
|
|
529
|
+
vfs = addDirectory(vfs, join(path, relativePath));
|
|
530
|
+
observer.next({ type: "addDir", vfs });
|
|
531
|
+
});
|
|
532
|
+
watcher.on("change", async () => {
|
|
533
|
+
observer.next({ type: "change", vfs });
|
|
534
|
+
});
|
|
535
|
+
watcher.on("unlink", async (relativePath) => {
|
|
536
|
+
vfs = removeNode(vfs, join(path, relativePath));
|
|
537
|
+
observer.next({ type: "unlink", vfs });
|
|
538
|
+
});
|
|
539
|
+
watcher.on("unlinkDir", async (relativePath) => {
|
|
540
|
+
vfs = removeNode(vfs, join(path, relativePath));
|
|
541
|
+
observer.next({ type: "unlinkDir", vfs });
|
|
542
|
+
});
|
|
543
|
+
watcher.on("ready", () => {
|
|
544
|
+
observer.next({ type: "ready", vfs });
|
|
545
|
+
});
|
|
546
|
+
return () => {
|
|
547
|
+
watcher.close();
|
|
548
|
+
};
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
// src/linter/run-rules.ts
|
|
555
|
+
var runRules;
|
|
556
|
+
var init_run_rules = __esm({
|
|
557
|
+
"src/linter/run-rules.ts"() {
|
|
558
|
+
runRules = async ({
|
|
559
|
+
root,
|
|
560
|
+
instance,
|
|
561
|
+
dependenciesMap
|
|
562
|
+
}) => {
|
|
563
|
+
const ruleDiagnostics = (currentInstance) => async (rule) => {
|
|
564
|
+
if (rule.severity === "off") {
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
567
|
+
const { diagnostics } = await rule.check({
|
|
568
|
+
root,
|
|
569
|
+
instance: currentInstance,
|
|
570
|
+
dependenciesMap
|
|
571
|
+
});
|
|
572
|
+
return diagnostics.map((d) => ({ ...d, rule }));
|
|
573
|
+
};
|
|
574
|
+
const runAbstractionRules = (currentInstance) => {
|
|
575
|
+
return currentInstance.abstraction.rules.map(ruleDiagnostics(currentInstance)).concat(...currentInstance.children.flatMap(runAbstractionRules));
|
|
576
|
+
};
|
|
577
|
+
return await Promise.all(runAbstractionRules(instance)).then((r) => r.flat());
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
var lint;
|
|
582
|
+
var init_lint = __esm({
|
|
583
|
+
"src/linter/lint.ts"() {
|
|
584
|
+
init_parse();
|
|
585
|
+
init_parse2();
|
|
586
|
+
init_watch_fs();
|
|
587
|
+
init_run_rules();
|
|
588
|
+
lint = ({
|
|
589
|
+
watch,
|
|
590
|
+
config,
|
|
591
|
+
configPath
|
|
592
|
+
}) => {
|
|
593
|
+
const rootPath = resolve(dirname(configPath), config.baseUrl ?? "./");
|
|
594
|
+
const parseNode = parseAbstractionInstance(config.root);
|
|
595
|
+
return watchFs(rootPath, { onlyReady: !watch }).pipe(
|
|
596
|
+
debounceTime(500),
|
|
597
|
+
switchMap(async ({ vfs }) => ({
|
|
598
|
+
root: vfs,
|
|
599
|
+
instance: parseNode(vfs),
|
|
600
|
+
dependenciesMap: await parseDependenciesMap(vfs)
|
|
601
|
+
})),
|
|
602
|
+
switchMap(runRules)
|
|
603
|
+
);
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
var formatLocation, formatSingleDiagnostic;
|
|
608
|
+
var init_format_single_diagnostic = __esm({
|
|
609
|
+
"src/linter/reporter/format-single-diagnostic.ts"() {
|
|
610
|
+
formatLocation = (location, cwd2) => {
|
|
611
|
+
let path = relative(cwd2, location.path);
|
|
612
|
+
if (location.line !== void 0) {
|
|
613
|
+
path += `:${location.line}`;
|
|
614
|
+
if (location.column !== void 0) {
|
|
615
|
+
path += `:${location.column}`;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return path;
|
|
619
|
+
};
|
|
620
|
+
formatSingleDiagnostic = (d, cwd2) => {
|
|
621
|
+
const x = d.rule.severity === "error" ? chalk.red(figures.cross) : chalk.yellow(figures.warning);
|
|
622
|
+
const s2 = chalk.reset(figures.lineDownRight);
|
|
623
|
+
const bar = chalk.reset(figures.lineVertical);
|
|
624
|
+
const e = chalk.reset(figures.lineUpRight);
|
|
625
|
+
const message = chalk.reset(d.message);
|
|
626
|
+
const autofixable = d.fixes !== void 0 && d.fixes.length > 0 ? chalk.green(`${figures.tick} Auto-fixable`) : null;
|
|
627
|
+
const location = chalk.gray(formatLocation(d.location, cwd2));
|
|
628
|
+
const ruleName = d.rule.descriptionUrl ? chalk.blue(terminalLink(d.rule.name, d.rule.descriptionUrl)) : d.rule.name;
|
|
629
|
+
return `
|
|
630
|
+
${s2} ${location}
|
|
631
|
+
${x} ${message}
|
|
632
|
+
${autofixable ? `${autofixable}
|
|
633
|
+
${bar}` : bar}
|
|
634
|
+
${e} ${ruleName}
|
|
635
|
+
`.trim();
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// src/linter/reporter/pluralization.ts
|
|
641
|
+
var s;
|
|
642
|
+
var init_pluralization = __esm({
|
|
643
|
+
"src/linter/reporter/pluralization.ts"() {
|
|
644
|
+
s = (amount) => amount === 1 ? "" : "s";
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
var formatPretty, reportPretty;
|
|
648
|
+
var init_reporter = __esm({
|
|
649
|
+
"src/linter/reporter/index.ts"() {
|
|
650
|
+
init_format_single_diagnostic();
|
|
651
|
+
init_pluralization();
|
|
652
|
+
formatPretty = (diagnostics, cwd2) => {
|
|
653
|
+
if (diagnostics.length === 0) {
|
|
654
|
+
return chalk.green(`${figures.tick} No problems found!`);
|
|
655
|
+
}
|
|
656
|
+
const errors = diagnostics.filter((d) => d.rule.severity === "error");
|
|
657
|
+
const warnings = diagnostics.filter((d) => d.rule.severity === "warn");
|
|
658
|
+
let footer = `Found ${[
|
|
659
|
+
errors.length > 0 && chalk.red.bold(`${errors.length} error${s(errors.length)}`),
|
|
660
|
+
warnings.length > 0 && chalk.yellow.bold(`${warnings.length} warning${s(warnings.length)}`)
|
|
661
|
+
].filter(Boolean).join(" and ")}`;
|
|
662
|
+
const autofixable = diagnostics.filter((d) => (d.fixes?.length ?? 0) > 0);
|
|
663
|
+
if (autofixable.length === diagnostics.length) {
|
|
664
|
+
footer += ` (all can be fixed automatically with ${chalk.green.bold("--fix")})`;
|
|
665
|
+
} else if (autofixable.length > 0) {
|
|
666
|
+
footer += ` (${autofixable.length} can be fixed automatically with ${chalk.green.bold("--fix")})`;
|
|
667
|
+
} else {
|
|
668
|
+
footer += " (none can be fixed automatically)";
|
|
669
|
+
}
|
|
670
|
+
return `
|
|
671
|
+
${diagnostics.map((d) => formatSingleDiagnostic(d, cwd2)).join("\n\n")}
|
|
672
|
+
|
|
673
|
+
${chalk.gray(figures.line.repeat(footer.length))}
|
|
674
|
+
${footer}
|
|
675
|
+
`;
|
|
676
|
+
};
|
|
677
|
+
reportPretty = (diagnostics, cwd2) => {
|
|
678
|
+
console.error(formatPretty(diagnostics, cwd2));
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
// src/linter/index.ts
|
|
684
|
+
var init_linter = __esm({
|
|
685
|
+
"src/linter/index.ts"() {
|
|
686
|
+
init_auto_fix();
|
|
687
|
+
init_lint();
|
|
688
|
+
init_reporter();
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// src/cli/commands/lint.ts
|
|
693
|
+
var lint_exports = {};
|
|
694
|
+
__export(lint_exports, {
|
|
695
|
+
default: () => lint_default
|
|
696
|
+
});
|
|
697
|
+
var lint_default;
|
|
698
|
+
var init_lint2 = __esm({
|
|
699
|
+
"src/cli/commands/lint.ts"() {
|
|
700
|
+
init_load();
|
|
701
|
+
init_linter();
|
|
702
|
+
lint_default = defineCommand({
|
|
703
|
+
meta: {
|
|
704
|
+
name: "lint",
|
|
705
|
+
description: "Lint the project"
|
|
706
|
+
},
|
|
707
|
+
args: {
|
|
708
|
+
watch: {
|
|
709
|
+
type: "boolean",
|
|
710
|
+
description: "Watch for changes",
|
|
711
|
+
default: false
|
|
712
|
+
},
|
|
713
|
+
fix: {
|
|
714
|
+
type: "boolean",
|
|
715
|
+
description: "Apply autofixes",
|
|
716
|
+
default: false
|
|
717
|
+
},
|
|
718
|
+
"fail-on-warning": {
|
|
719
|
+
type: "boolean",
|
|
720
|
+
description: "Fail on warnings",
|
|
721
|
+
default: false
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
async run(ctx) {
|
|
725
|
+
const { watch, fix, "fail-on-warning": failOnWarning } = ctx.args;
|
|
726
|
+
const subscription = watchConfig({
|
|
727
|
+
cwd: process2__default.cwd(),
|
|
728
|
+
onlyOne: !watch
|
|
729
|
+
}).pipe(
|
|
730
|
+
map(({ configPath, config }) => ({ configPath, config, watch })),
|
|
731
|
+
switchMap(lint),
|
|
732
|
+
catchError((e) => {
|
|
733
|
+
if (e instanceof ZodError) {
|
|
734
|
+
console.error(fromError(e).toString());
|
|
735
|
+
} else if (e instanceof Error) {
|
|
736
|
+
console.error(e.message);
|
|
737
|
+
}
|
|
738
|
+
process2__default.exit(1);
|
|
739
|
+
})
|
|
740
|
+
).subscribe(async (diagnostics) => {
|
|
741
|
+
if (watch) {
|
|
742
|
+
console.clear();
|
|
743
|
+
reportPretty(diagnostics, process2__default.cwd());
|
|
744
|
+
if (fix) {
|
|
745
|
+
await applyAutofixes(diagnostics);
|
|
746
|
+
}
|
|
747
|
+
} else {
|
|
748
|
+
let stillRelevantDiagnostics = diagnostics;
|
|
749
|
+
reportPretty(diagnostics, process2__default.cwd());
|
|
750
|
+
if (fix) {
|
|
751
|
+
stillRelevantDiagnostics = await applyAutofixes(diagnostics);
|
|
752
|
+
}
|
|
753
|
+
if (stillRelevantDiagnostics.length > 0) {
|
|
754
|
+
const onlyWarnings = stillRelevantDiagnostics.every(
|
|
755
|
+
(d) => d.rule.severity === "warn"
|
|
756
|
+
);
|
|
757
|
+
if (failOnWarning || !onlyWarnings) {
|
|
758
|
+
process2__default.exit(1);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
process2__default.exit(0);
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
prexit(() => subscription.unsubscribe());
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
// src/cli/version.ts
|
|
771
|
+
var version = "0.1.0";
|
|
772
|
+
|
|
773
|
+
// src/cli/commands/index.ts
|
|
774
|
+
var _rDefault = (r) => r.default || r;
|
|
775
|
+
var commands = {
|
|
776
|
+
init: () => Promise.resolve().then(() => (init_init(), init_exports)).then(_rDefault),
|
|
777
|
+
lint: () => Promise.resolve().then(() => (init_lint2(), lint_exports)).then(_rDefault)
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
// src/cli/index.ts
|
|
781
|
+
var main = defineCommand({
|
|
782
|
+
meta: {
|
|
783
|
+
name: "echo-architect",
|
|
784
|
+
version,
|
|
785
|
+
description: "EchoJS architecture linter CLI"
|
|
786
|
+
},
|
|
787
|
+
subCommands: commands
|
|
788
|
+
});
|
|
789
|
+
runMain(main);
|
|
790
|
+
//# sourceMappingURL=index.js.map
|
|
791
|
+
//# sourceMappingURL=index.js.map
|