laymos 0.0.2 → 0.0.3

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.
Files changed (133) hide show
  1. package/package.json +3 -3
  2. package/dist/architecture/analyze-project/analyze-project.d.ts +0 -9
  3. package/dist/architecture/analyze-project/analyze-project.d.ts.map +0 -1
  4. package/dist/architecture/analyze-project/analyze-project.js +0 -47
  5. package/dist/architecture/analyze-project/index.d.ts +0 -3
  6. package/dist/architecture/analyze-project/index.d.ts.map +0 -1
  7. package/dist/architecture/analyze-project/index.js +0 -1
  8. package/dist/architecture/build-report/build-report.d.ts +0 -7
  9. package/dist/architecture/build-report/build-report.d.ts.map +0 -1
  10. package/dist/architecture/build-report/build-report.js +0 -80
  11. package/dist/architecture/build-report/index.d.ts +0 -2
  12. package/dist/architecture/build-report/index.d.ts.map +0 -1
  13. package/dist/architecture/build-report/index.js +0 -1
  14. package/dist/architecture/errors.d.ts +0 -11
  15. package/dist/architecture/errors.d.ts.map +0 -1
  16. package/dist/architecture/errors.js +0 -3
  17. package/dist/architecture/extract-dependencies/extract-dependencies.d.ts +0 -12
  18. package/dist/architecture/extract-dependencies/extract-dependencies.d.ts.map +0 -1
  19. package/dist/architecture/extract-dependencies/extract-dependencies.js +0 -162
  20. package/dist/architecture/extract-dependencies/index.d.ts +0 -3
  21. package/dist/architecture/extract-dependencies/index.d.ts.map +0 -1
  22. package/dist/architecture/extract-dependencies/index.js +0 -1
  23. package/dist/architecture/resolve-architecture/index.d.ts +0 -3
  24. package/dist/architecture/resolve-architecture/index.d.ts.map +0 -1
  25. package/dist/architecture/resolve-architecture/index.js +0 -1
  26. package/dist/architecture/resolve-architecture/resolve-architecture.d.ts +0 -24
  27. package/dist/architecture/resolve-architecture/resolve-architecture.d.ts.map +0 -1
  28. package/dist/architecture/resolve-architecture/resolve-architecture.js +0 -74
  29. package/dist/architecture/validate-rules/index.d.ts +0 -3
  30. package/dist/architecture/validate-rules/index.d.ts.map +0 -1
  31. package/dist/architecture/validate-rules/index.js +0 -1
  32. package/dist/architecture/validate-rules/validate-rules.d.ts +0 -10
  33. package/dist/architecture/validate-rules/validate-rules.d.ts.map +0 -1
  34. package/dist/architecture/validate-rules/validate-rules.js +0 -80
  35. package/dist/cli/deps/dependency-tree.d.ts +0 -3
  36. package/dist/cli/deps/dependency-tree.d.ts.map +0 -1
  37. package/dist/cli/deps/dependency-tree.js +0 -39
  38. package/dist/cli/deps/deps.d.ts +0 -7
  39. package/dist/cli/deps/deps.d.ts.map +0 -1
  40. package/dist/cli/deps/deps.js +0 -26
  41. package/dist/cli/deps/index.d.ts +0 -2
  42. package/dist/cli/deps/index.d.ts.map +0 -1
  43. package/dist/cli/deps/index.js +0 -2
  44. package/dist/config/define-config.d.ts +0 -8
  45. package/dist/config/define-config.d.ts.map +0 -1
  46. package/dist/config/define-config.js +0 -373
  47. package/dist/config/index.d.ts +0 -11
  48. package/dist/config/index.d.ts.map +0 -1
  49. package/dist/config/index.js +0 -6
  50. package/dist/config/layer-graph.d.ts +0 -7
  51. package/dist/config/layer-graph.d.ts.map +0 -1
  52. package/dist/config/layer-graph.js +0 -26
  53. package/dist/config/layer.d.ts +0 -5
  54. package/dist/config/layer.d.ts.map +0 -1
  55. package/dist/config/layer.js +0 -8
  56. package/dist/config/load-config/index.d.ts +0 -2
  57. package/dist/config/load-config/index.d.ts.map +0 -1
  58. package/dist/config/load-config/index.js +0 -1
  59. package/dist/config/load-config/load-config.d.ts +0 -34
  60. package/dist/config/load-config/load-config.d.ts.map +0 -1
  61. package/dist/config/load-config/load-config.js +0 -127
  62. package/dist/config/module.d.ts +0 -11
  63. package/dist/config/module.d.ts.map +0 -1
  64. package/dist/config/module.js +0 -22
  65. package/dist/config/path.d.ts +0 -4
  66. package/dist/config/path.d.ts.map +0 -1
  67. package/dist/config/path.js +0 -32
  68. package/dist/config/project-narrative.d.ts +0 -15
  69. package/dist/config/project-narrative.d.ts.map +0 -1
  70. package/dist/config/project-narrative.js +0 -11
  71. package/dist/config/types.d.ts +0 -38
  72. package/dist/config/types.d.ts.map +0 -1
  73. package/dist/config/types.js +0 -1
  74. package/dist/domain/architecture-analysis/modules/unexposed-modules.d.ts +0 -3
  75. package/dist/domain/architecture-analysis/modules/unexposed-modules.d.ts.map +0 -1
  76. package/dist/domain/architecture-analysis/modules/unexposed-modules.js +0 -10
  77. package/dist/domain/project-config/validation/modules/containment.d.ts +0 -3
  78. package/dist/domain/project-config/validation/modules/containment.d.ts.map +0 -1
  79. package/dist/domain/project-config/validation/modules/containment.js +0 -24
  80. package/dist/domain/project-config/validation/modules/kinds.d.ts +0 -3
  81. package/dist/domain/project-config/validation/modules/kinds.d.ts.map +0 -1
  82. package/dist/domain/project-config/validation/modules/kinds.js +0 -18
  83. package/dist/domain/project-config/validation/modules/nested.d.ts +0 -3
  84. package/dist/domain/project-config/validation/modules/nested.d.ts.map +0 -1
  85. package/dist/domain/project-config/validation/modules/nested.js +0 -34
  86. package/dist/domain/project-config/validation/modules/subpaths.d.ts +0 -3
  87. package/dist/domain/project-config/validation/modules/subpaths.d.ts.map +0 -1
  88. package/dist/domain/project-config/validation/modules/subpaths.js +0 -40
  89. package/dist/entrypoints/cli/cli.d.ts +0 -3
  90. package/dist/entrypoints/cli/cli.d.ts.map +0 -1
  91. package/dist/entrypoints/cli/cli.js +0 -6
  92. package/dist/entrypoints/cli/run.d.ts +0 -13
  93. package/dist/entrypoints/cli/run.d.ts.map +0 -1
  94. package/dist/entrypoints/cli/run.js +0 -155
  95. package/dist/entrypoints/cli/test-output.d.ts +0 -17
  96. package/dist/entrypoints/cli/test-output.d.ts.map +0 -1
  97. package/dist/entrypoints/cli/test-output.js +0 -244
  98. package/dist/entrypoints/node/index.d.ts +0 -24
  99. package/dist/entrypoints/node/index.d.ts.map +0 -1
  100. package/dist/entrypoints/node/index.js +0 -27
  101. package/dist/entrypoints/report/index.d.ts +0 -2
  102. package/dist/entrypoints/report/index.d.ts.map +0 -1
  103. package/dist/entrypoints/report/index.js +0 -1
  104. package/dist/markdown/index.d.ts +0 -3
  105. package/dist/markdown/index.d.ts.map +0 -1
  106. package/dist/markdown/index.js +0 -1
  107. package/dist/markdown/markdown.d.ts +0 -7
  108. package/dist/markdown/markdown.d.ts.map +0 -1
  109. package/dist/markdown/markdown.js +0 -13
  110. package/dist/orchestrator/query-dependencies/index.d.ts +0 -3
  111. package/dist/orchestrator/query-dependencies/index.d.ts.map +0 -1
  112. package/dist/orchestrator/query-dependencies/index.js +0 -4
  113. package/dist/orchestrator/query-dependencies/query-dependencies.d.ts +0 -12
  114. package/dist/orchestrator/query-dependencies/query-dependencies.d.ts.map +0 -1
  115. package/dist/orchestrator/query-dependencies/query-dependencies.js +0 -20
  116. package/dist/report/architecture.d.ts +0 -104
  117. package/dist/report/architecture.d.ts.map +0 -1
  118. package/dist/report/architecture.js +0 -1
  119. package/dist/report/index.d.ts +0 -4
  120. package/dist/report/index.d.ts.map +0 -1
  121. package/dist/report/index.js +0 -2
  122. package/dist/report/tests.d.ts +0 -411
  123. package/dist/report/tests.d.ts.map +0 -1
  124. package/dist/report/tests.js +0 -102
  125. package/dist/tests/authoring/index.d.ts +0 -72
  126. package/dist/tests/authoring/index.d.ts.map +0 -1
  127. package/dist/tests/authoring/index.js +0 -312
  128. package/dist/tests/run-tests/index.d.ts +0 -3
  129. package/dist/tests/run-tests/index.d.ts.map +0 -1
  130. package/dist/tests/run-tests/index.js +0 -1
  131. package/dist/tests/run-tests/run-tests.d.ts +0 -26
  132. package/dist/tests/run-tests/run-tests.d.ts.map +0 -1
  133. package/dist/tests/run-tests/run-tests.js +0 -284
@@ -1,155 +0,0 @@
1
- import { statSync } from 'node:fs';
2
- import { resolve } from 'node:path';
3
- import { Effect, Option, Schema } from 'effect';
4
- import { Argument, Command, Flag } from 'effect/unstable/cli';
5
- import { analyzeProject, runTests } from '../node/index.js';
6
- import { renderTestsReport, selectedTestCases } from './test-output.js';
7
- const paint = (stream, code, color) => (text) => color && stream.isTTY && process.env['NO_COLOR'] === undefined
8
- ? `\x1b[${code}m${text}\x1b[0m`
9
- : text;
10
- export function lintPasses(report) {
11
- return report.violations.length === 0;
12
- }
13
- function lint(color) {
14
- const green = paint(process.stdout, '32', color);
15
- const yellow = paint(process.stdout, '33', color);
16
- const red = paint(process.stderr, '31', color);
17
- return analyzeProject({ projectDir: process.cwd() }).pipe(Effect.flatMap((report) => Effect.suspend(() => {
18
- reportCoverage(report, yellow);
19
- reportWarnings(report, yellow);
20
- if (lintPasses(report)) {
21
- process.stdout.write(green('No violations found.\n'));
22
- return Effect.void;
23
- }
24
- reportViolations(report.violations, red);
25
- return markFailure();
26
- })), Effect.catch((error) => Effect.sync(() => {
27
- process.stderr.write(red(`Error: ${errorMessage(error)}\n`));
28
- process.exitCode = 1;
29
- })));
30
- }
31
- function reportCoverage(report, yellow) {
32
- const ignored = Object.values(report.files).filter((file) => file.kind === 'ignored').length;
33
- const layerCoverage = report.coverage.layers;
34
- const moduleTotal = report.coverage.modules.reduce((total, coverage) => total + coverage.totalFiles, 0);
35
- const moduleCovered = report.coverage.modules.reduce((total, coverage) => total + coverage.coveredFiles, 0);
36
- const ignoredSuffix = ignored > 0 ? ` (${ignored} ignored)` : '';
37
- process.stdout.write([
38
- `Scanned ${layerCoverage.totalFiles} source file(s)${ignoredSuffix}.`,
39
- `Layers: ${layerCoverage.coveredFiles}/${layerCoverage.totalFiles} file(s) covered.`,
40
- `Modules: ${moduleCovered}/${moduleTotal} layer-covered file(s) covered.`,
41
- ].join('\n') + '\n');
42
- if (layerCoverage.uncovered.length > 0) {
43
- writeWarningList('file(s) not covered by any layer', layerCoverage.uncovered, yellow);
44
- }
45
- for (const coverage of report.coverage.modules) {
46
- if (coverage.uncovered.length > 0) {
47
- writeWarningList(`file(s) in layer "${coverage.layer}" not covered by a module`, coverage.uncovered, yellow);
48
- }
49
- }
50
- }
51
- function reportWarnings(report, yellow) {
52
- for (const warning of report.warnings) {
53
- const detail = warning.kind === 'missing-source-root'
54
- ? `source root does not exist: ${warning.path}`
55
- : warning.kind === 'missing-layer-path'
56
- ? `layer "${warning.layer}" path does not exist: ${warning.path}`
57
- : `module path does not exist: ${warning.path}`;
58
- process.stdout.write(yellow(`warning: ${detail}\n`));
59
- }
60
- }
61
- function writeWarningList(title, files, yellow) {
62
- process.stdout.write(yellow(`warning: ${files.length} ${title}:\n`));
63
- for (const file of files)
64
- process.stdout.write(yellow(` - ${file}\n`));
65
- }
66
- function reportViolations(violations, red) {
67
- process.stderr.write(red(`Found ${violations.length} architecture violation(s):\n`));
68
- for (const violation of violations) {
69
- if (violation.kind === 'layer') {
70
- process.stderr.write(red(` - [layer] ${violation.from.layer} -> ${violation.to.layer}\n`));
71
- }
72
- else if (violation.kind === 'module') {
73
- process.stderr.write(red(` - [${violation.rule}] ${violation.from.module} -> ${violation.to.module}\n`));
74
- }
75
- process.stderr.write(red(` ${violation.from.file} -> ${violation.to.file}\n`));
76
- }
77
- process.stderr.write(red(`Lint failed: ${violations.length} violation(s).\n`));
78
- }
79
- const ErrorMessageSchema = Schema.Struct({ message: Schema.String });
80
- function errorMessage(error) {
81
- const decoded = Schema.decodeUnknownOption(ErrorMessageSchema)(error);
82
- return Option.isSome(decoded) ? decoded.value.message : String(error);
83
- }
84
- const colorFlag = Flag.boolean('color').pipe(Flag.withDefault(true), Flag.withDescription('Enable terminal colors; use --no-color to disable.'));
85
- const rootCommand = Command.make('laymos', {}, () => Effect.void).pipe(Command.withSharedFlags({ color: colorFlag }));
86
- const lintCommand = Command.make('lint', {}, () => Effect.gen(function* () {
87
- const { color } = yield* rootCommand;
88
- yield* lint(color);
89
- })).pipe(Command.withDescription('Lint the declared project architecture.'));
90
- const targetArgument = Argument.string('target').pipe(Argument.withDescription('Existing test file or literal test-name query.'), Argument.optional);
91
- const verboseFlag = Flag.boolean('verbose').pipe(Flag.withDefault(false), Flag.withDescription('Expand all evidence, trace attributes, events, and logs.'));
92
- const testCommand = Command.make('test', { target: targetArgument, verbose: verboseFlag }, ({ target, verbose }) => Effect.gen(function* () {
93
- const { color } = yield* rootCommand;
94
- yield* test(Option.getOrUndefined(target), verbose, color);
95
- })).pipe(Command.withDescription('Run Vitest and present cases, assertions, traces, and timing.'));
96
- export const command = rootCommand.pipe(Command.withSubcommands([lintCommand, testCommand]));
97
- export const cli = command.pipe(Command.run({ version: '0.0.1' }));
98
- function test(target, verbose, color) {
99
- const selection = resolveTestSelection(target);
100
- const red = paint(process.stderr, '31', color);
101
- return runTests({
102
- projectDir: process.cwd(),
103
- ...(selection?.kind === 'file' ? { files: [selection.path] } : {}),
104
- ...(selection?.kind === 'name'
105
- ? { testNamePattern: literalNamePattern(selection.query) }
106
- : {}),
107
- }).pipe(Effect.flatMap((report) => Effect.suspend(() => {
108
- const nameQuery = selection?.kind === 'name' ? selection.query : undefined;
109
- const selected = selectedTestCases(report, nameQuery);
110
- const reportOptions = {
111
- color: color &&
112
- process.stdout.isTTY === true &&
113
- process.env['NO_COLOR'] === undefined,
114
- detailed: target !== undefined || verbose,
115
- ...(nameQuery === undefined ? {} : { nameQuery }),
116
- verbose,
117
- };
118
- if (selected.length === 0) {
119
- if (report.status === 'failed') {
120
- process.stdout.write(renderTestsReport(report, reportOptions));
121
- }
122
- const message = nameQuery === undefined
123
- ? 'No tests found.'
124
- : `No tests matched "${nameQuery}".`;
125
- process.stderr.write(red(`${message}\n`));
126
- return markFailure();
127
- }
128
- process.stdout.write(renderTestsReport(report, reportOptions));
129
- return report.status === 'failed' ? markFailure() : Effect.void;
130
- })), Effect.catch((error) => Effect.sync(() => {
131
- process.stderr.write(red(`Error: ${errorMessage(error)}\n`));
132
- process.exitCode = 1;
133
- })));
134
- }
135
- function markFailure() {
136
- return Effect.sync(() => {
137
- process.exitCode = 1;
138
- });
139
- }
140
- function resolveTestSelection(target) {
141
- if (target === undefined)
142
- return undefined;
143
- const path = resolve(process.cwd(), target);
144
- try {
145
- if (statSync(path).isFile())
146
- return { kind: 'file', path };
147
- }
148
- catch {
149
- return { kind: 'name', query: target };
150
- }
151
- return { kind: 'name', query: target };
152
- }
153
- function literalNamePattern(query) {
154
- return new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
155
- }
@@ -1,17 +0,0 @@
1
- import type { TestCaseReport, TestsReport } from '../../report/tests.js';
2
- export interface TestOutputOptions {
3
- readonly color: boolean;
4
- readonly detailed: boolean;
5
- readonly nameQuery?: string;
6
- readonly verbose: boolean;
7
- }
8
- interface SelectedCase {
9
- readonly caseReport: TestCaseReport;
10
- readonly modulePath: string;
11
- }
12
- /** Returns the cases visible for an optional literal full-name query. */
13
- export declare function selectedTestCases(report: TestsReport, nameQuery?: string): readonly SelectedCase[];
14
- /** Renders a completed Test Report for terminal presentation. */
15
- export declare function renderTestsReport(report: TestsReport, options: TestOutputOptions): string;
16
- export {};
17
- //# sourceMappingURL=test-output.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-output.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/cli/test-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EAOd,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AASD,UAAU,YAAY;IACpB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,SAAS,YAAY,EAAE,CAqBzB;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,iBAAiB,GACzB,MAAM,CA+CR"}
@@ -1,244 +0,0 @@
1
- /** Returns the cases visible for an optional literal full-name query. */
2
- export function selectedTestCases(report, nameQuery) {
3
- const normalizedQuery = nameQuery?.toLocaleLowerCase();
4
- return report.modules.flatMap((module) => [...module.cases, ...module.suites.flatMap(collectSuiteCases)]
5
- .filter((caseReport) => normalizedQuery === undefined ||
6
- caseReport.fullName.toLocaleLowerCase().includes(normalizedQuery))
7
- .map((caseReport) => ({
8
- caseReport,
9
- modulePath: module.path,
10
- }))
11
- .sort((left, right) => (left.caseReport.location?.line ?? Number.MAX_SAFE_INTEGER) -
12
- (right.caseReport.location?.line ?? Number.MAX_SAFE_INTEGER) ||
13
- (left.caseReport.location?.column ?? Number.MAX_SAFE_INTEGER) -
14
- (right.caseReport.location?.column ?? Number.MAX_SAFE_INTEGER)));
15
- }
16
- /** Renders a completed Test Report for terminal presentation. */
17
- export function renderTestsReport(report, options) {
18
- const palette = makePalette(options.color);
19
- const selected = selectedTestCases(report, options.nameQuery);
20
- const byModule = Map.groupBy(selected, ({ modulePath }) => modulePath);
21
- const lines = [];
22
- for (const [modulePath, cases] of byModule) {
23
- const status = aggregateStatus(cases.map(({ caseReport }) => caseReport.status));
24
- lines.push(`${statusLabel(status, palette)} ${modulePath}`, ...cases.flatMap(({ caseReport }) => options.detailed || caseReport.status === 'failed'
25
- ? renderDetailedCase(caseReport, modulePath, options, palette)
26
- : renderCompactCase(caseReport, palette)), '');
27
- }
28
- const hierarchyErrors = report.modules.flatMap((module) => [
29
- ...module.errors,
30
- ...module.suites.flatMap(collectSuiteErrors),
31
- ]);
32
- if (hierarchyErrors.length > 0) {
33
- lines.push(palette.red('Test collection errors'), ...hierarchyErrors.flatMap((error) => renderError(error, options.verbose, palette, ' ')), '');
34
- }
35
- if (report.unhandledErrors.length > 0) {
36
- lines.push(palette.red('Unhandled errors'), ...report.unhandledErrors.flatMap((error) => renderError(error, options.verbose, palette, ' ')), '');
37
- }
38
- lines.push(renderSummary(report, selected, palette));
39
- return `${lines.join('\n')}\n`;
40
- }
41
- function collectSuiteCases(suite) {
42
- return [...suite.cases, ...suite.suites.flatMap(collectSuiteCases)];
43
- }
44
- function collectSuiteErrors(suite) {
45
- return [...suite.errors, ...suite.suites.flatMap(collectSuiteErrors)];
46
- }
47
- function aggregateStatus(statuses) {
48
- if (statuses.some((status) => status === 'failed'))
49
- return 'failed';
50
- if (statuses.some((status) => status === 'passed'))
51
- return 'passed';
52
- if (statuses.some((status) => status === 'pending'))
53
- return 'pending';
54
- return 'skipped';
55
- }
56
- function renderCompactCase(report, palette) {
57
- const evidence = report.evidence;
58
- const details = [
59
- evidence === undefined
60
- ? undefined
61
- : `${evidence.assertions.length} ${plural(evidence.assertions.length, 'assertion')}`,
62
- evidence?.trace === undefined
63
- ? undefined
64
- : `${evidence.trace.spans.length} ${plural(evidence.trace.spans.length, 'span')}`,
65
- ].filter((detail) => detail !== undefined);
66
- const suffix = details.length === 0 ? '' : ` · ${details.join(' · ')}`;
67
- return [
68
- ` ${statusSymbol(report.status, palette)} ${report.fullName} ${palette.dim(formatDuration(report.duration))}${suffix}`,
69
- ];
70
- }
71
- function renderDetailedCase(report, modulePath, options, palette) {
72
- const location = report.location === undefined
73
- ? modulePath
74
- : `${modulePath}:${report.location.line}:${report.location.column}`;
75
- const lines = [
76
- '',
77
- ` ${statusSymbol(report.status, palette)} ${report.fullName}`,
78
- palette.dim(` ${location} · ${formatDuration(report.duration)}`),
79
- ];
80
- if (report.evidence?.description !== undefined) {
81
- lines.push('', ` ${report.evidence.description}`);
82
- }
83
- if (report.evidence !== undefined) {
84
- lines.push('', palette.dim(' Assertions'), ...report.evidence.assertions.flatMap((assertion) => renderAssertion(assertion, options.verbose, palette)));
85
- if (report.evidence.trace !== undefined) {
86
- lines.push('', palette.dim(' Trace'), ...renderTrace(report.evidence.trace.spans, report.evidence.trace.logs, options.verbose, palette));
87
- }
88
- }
89
- if (report.errors.length > 0) {
90
- lines.push('', palette.red(' Errors'), ...report.errors.flatMap((error) => renderError(error, options.verbose, palette, ' ')));
91
- }
92
- return lines;
93
- }
94
- function renderAssertion(assertion, verbose, palette) {
95
- const lines = [
96
- ` ${assertion.status === 'passed' ? palette.green('✓') : palette.red('✗')} ${assertion.name}`,
97
- ];
98
- if (assertion.expected !== undefined) {
99
- lines.push(` expected: ${formatValue(assertion.expected)}`);
100
- }
101
- if (assertion.actual !== undefined) {
102
- lines.push(` actual: ${formatValue(assertion.actual)}`);
103
- }
104
- if (verbose)
105
- lines.push(palette.dim(` matcher: ${assertion.matcher}`));
106
- if (assertion.error?.diff !== undefined) {
107
- lines.push('', ...assertion.error.diff.split('\n').map((line) => ` ${line}`));
108
- }
109
- else if (assertion.status === 'failed' &&
110
- assertion.error?.message !== undefined) {
111
- lines.push(palette.red(` ${assertion.error.message}`));
112
- }
113
- if (verbose && assertion.error?.stack !== undefined) {
114
- lines.push(...assertion.error.stack
115
- .split('\n')
116
- .map((line) => palette.dim(` ${line}`)));
117
- }
118
- return lines;
119
- }
120
- function renderTrace(spans, logs, verbose, palette) {
121
- const byId = new Map(spans.map((span) => [span.spanId, span]));
122
- const children = Map.groupBy(spans, (span) => span.parentSpanId !== null && byId.has(span.parentSpanId)
123
- ? span.parentSpanId
124
- : null);
125
- const logsBySpan = Map.groupBy(logs, ({ spanId }) => spanId);
126
- const lines = (children.get(null) ?? []).flatMap((span, index, roots) => renderSpan(span, children, logsBySpan, '', index === roots.length - 1, verbose, palette));
127
- const unscoped = logsBySpan.get(null) ?? [];
128
- if (verbose && unscoped.length > 0) {
129
- lines.push(' Unscoped logs', ...unscoped.map((log) => renderLog(log, ' ', palette)));
130
- }
131
- return lines;
132
- }
133
- function renderSpan(span, children, logs, prefix, last, verbose, palette) {
134
- const branch = last ? '└─' : '├─';
135
- const duration = span.endTime === null
136
- ? 'running'
137
- : formatDuration(span.endTime - span.startTime);
138
- const status = span.status === 'error' ? ` ${palette.red('[error]')}` : '';
139
- const lines = [
140
- ` ${prefix}${branch} ${span.name} ${palette.dim(duration)}${status}`,
141
- ];
142
- const detailPrefix = ` ${prefix}${last ? ' ' : '│ '}`;
143
- if (verbose) {
144
- const attributes = Object.entries(span.attributes);
145
- if (attributes.length > 0) {
146
- lines.push(`${detailPrefix}attributes:`, ...attributes.map(([key, value]) => `${detailPrefix} ${key}: ${formatValue(value)}`));
147
- }
148
- const spanLogs = logs.get(span.spanId) ?? [];
149
- if (spanLogs.length > 0) {
150
- lines.push(`${detailPrefix}logs:`, ...spanLogs.map((log) => renderLog(log, `${detailPrefix} `, palette)));
151
- }
152
- if (span.events.length > 0) {
153
- lines.push(`${detailPrefix}events:`, ...span.events.flatMap((event) => [
154
- `${detailPrefix} ${event.name} ${palette.dim(formatTimestampOffset(event.timestamp, span.startTime))}`,
155
- ...Object.entries(event.attributes).map(([key, value]) => `${detailPrefix} ${key}: ${formatValue(value)}`),
156
- ]));
157
- }
158
- }
159
- const childSpans = children.get(span.spanId) ?? [];
160
- for (const [index, child] of childSpans.entries()) {
161
- lines.push(...renderSpan(child, children, logs, `${prefix}${last ? ' ' : '│ '}`, index === childSpans.length - 1, verbose, palette));
162
- }
163
- return lines;
164
- }
165
- function renderLog(log, prefix, palette) {
166
- const level = log.level === 'Error' || log.level === 'Fatal'
167
- ? palette.red(log.level.toUpperCase())
168
- : log.level === 'Warn'
169
- ? palette.yellow('WARN')
170
- : palette.dim(log.level.toUpperCase());
171
- const annotations = Object.entries(log.annotations)
172
- .map(([key, value]) => `${key}=${formatValue(value)}`)
173
- .join(' ');
174
- return `${prefix}${level} ${formatValue(log.message)}${annotations === '' ? '' : ` ${palette.dim(annotations)}`}`;
175
- }
176
- function renderError(error, verbose, palette, prefix) {
177
- const lines = [palette.red(`${prefix}${error.name}: ${error.message}`)];
178
- if (error.diff !== undefined) {
179
- lines.push(...error.diff.split('\n').map((line) => `${prefix}${line}`));
180
- }
181
- if (verbose && error.stack !== undefined) {
182
- lines.push(...error.stack.split('\n').map((line) => palette.dim(`${prefix}${line}`)));
183
- }
184
- return lines;
185
- }
186
- function renderSummary(report, selected, palette) {
187
- const cases = selected.map(({ caseReport }) => caseReport);
188
- const passed = cases.filter(({ status }) => status === 'passed').length;
189
- const failed = cases.filter(({ status }) => status === 'failed').length;
190
- const skipped = cases.filter(({ status }) => status === 'skipped' || status === 'pending').length;
191
- const assertions = cases.reduce((total, caseReport) => total + (caseReport.evidence?.assertions.length ?? 0), 0);
192
- const spans = cases.reduce((total, caseReport) => total + (caseReport.evidence?.trace?.spans.length ?? 0), 0);
193
- return [
194
- passed === 0 ? undefined : palette.green(`${passed} passed`),
195
- failed === 0 ? undefined : palette.red(`${failed} failed`),
196
- skipped === 0 ? undefined : palette.yellow(`${skipped} skipped`),
197
- `${assertions} ${plural(assertions, 'assertion')}`,
198
- `${spans} ${plural(spans, 'span')}`,
199
- formatDuration(report.duration),
200
- ]
201
- .filter((part) => part !== undefined)
202
- .join(' · ');
203
- }
204
- function statusLabel(status, palette) {
205
- if (status === 'passed')
206
- return palette.green('PASS');
207
- if (status === 'failed')
208
- return palette.red('FAIL');
209
- if (status === 'pending')
210
- return palette.yellow('PENDING');
211
- return palette.yellow('SKIP');
212
- }
213
- function statusSymbol(status, palette) {
214
- if (status === 'passed')
215
- return palette.green('✓');
216
- if (status === 'failed')
217
- return palette.red('✗');
218
- return palette.yellow('○');
219
- }
220
- function formatDuration(milliseconds) {
221
- if (milliseconds < 1)
222
- return `${Math.round(milliseconds * 1000)} µs`;
223
- if (milliseconds < 1000)
224
- return `${milliseconds.toFixed(1)} ms`;
225
- return `${(milliseconds / 1000).toFixed(2)} s`;
226
- }
227
- function formatTimestampOffset(timestamp, startTime) {
228
- return `+${formatDuration(Math.max(0, timestamp - startTime))}`;
229
- }
230
- function formatValue(value) {
231
- return JSON.stringify(value);
232
- }
233
- function plural(count, singular) {
234
- return count === 1 ? singular : `${singular}s`;
235
- }
236
- function makePalette(color) {
237
- const paint = (code) => (text) => color ? `\x1b[${code}m${text}\x1b[0m` : text;
238
- return {
239
- dim: paint('2'),
240
- green: paint('32'),
241
- red: paint('31'),
242
- yellow: paint('33'),
243
- };
244
- }
@@ -1,24 +0,0 @@
1
- import { Effect } from 'effect';
2
- import { type AnalyzeProjectRequest } from '../../architecture/analyze-project/index.js';
3
- import type { LaymosError } from '../../architecture/errors.js';
4
- import { type ProjectNarrative } from '../../config/project-narrative.js';
5
- import type { LaymosReport } from '../../report/index.js';
6
- import type { TestsReport } from '../../report/tests.js';
7
- import { type TestRunInProgress, type TestRunnerError, type TestsRunOptions } from '../../tests/run-tests/index.js';
8
- export { ConfigImportError, ConfigNotFoundError, ConfigValidationError, } from '../../config/load-config/index.js';
9
- export { ExtractError } from '../../architecture/errors.js';
10
- export { TestRunInProgress, TestRunnerError, } from '../../tests/run-tests/index.js';
11
- export type { TestsRunOptions } from '../../tests/run-tests/index.js';
12
- export interface GetProjectNarrativeRequest {
13
- readonly projectDir: string;
14
- }
15
- export interface RunTestsRequest extends TestsRunOptions {
16
- readonly projectDir: string;
17
- }
18
- /** Runs the project's ordinary Vitest suite and returns a serializable report. */
19
- export declare function runTests(request: RunTestsRequest): Effect.Effect<TestsReport, TestRunInProgress | TestRunnerError>;
20
- /** Analyzes one project's declared and actual static architecture. */
21
- export declare function analyzeProject(request: AnalyzeProjectRequest): Effect.Effect<LaymosReport, LaymosError>;
22
- /** Loads the project narrative without waiting for project analysis. */
23
- export declare function getProjectNarrative({ projectDir, }: GetProjectNarrativeRequest): Effect.Effect<ProjectNarrative | undefined, import('../../config/load-config/index.js').LoadConfigError>;
24
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CACtB,OAAO,EAAE,eAAe,GACvB,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,GAAG,eAAe,CAAC,CAOjE;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,CAE1C;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,EAClC,UAAU,GACX,EAAE,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAC3C,gBAAgB,GAAG,SAAS,EAC5B,OAAO,mCAAmC,EAAE,eAAe,CAC5D,CAQA"}
@@ -1,27 +0,0 @@
1
- import { Effect } from 'effect';
2
- import { analyzeProject as analyzeProjectOperation, } from '../../architecture/analyze-project/index.js';
3
- import { loadConfig } from '../../config/load-config/index.js';
4
- import { serializeProjectNarrative, } from '../../config/project-narrative.js';
5
- import { executeTests, } from '../../tests/run-tests/index.js';
6
- export { ConfigImportError, ConfigNotFoundError, ConfigValidationError, } from '../../config/load-config/index.js';
7
- export { ExtractError } from '../../architecture/errors.js';
8
- export { TestRunInProgress, TestRunnerError, } from '../../tests/run-tests/index.js';
9
- /** Runs the project's ordinary Vitest suite and returns a serializable report. */
10
- export function runTests(request) {
11
- return executeTests(request.projectDir, {
12
- ...(request.files === undefined ? {} : { files: request.files }),
13
- ...(request.testNamePattern === undefined
14
- ? {}
15
- : { testNamePattern: request.testNamePattern }),
16
- });
17
- }
18
- /** Analyzes one project's declared and actual static architecture. */
19
- export function analyzeProject(request) {
20
- return analyzeProjectOperation(request);
21
- }
22
- /** Loads the project narrative without waiting for project analysis. */
23
- export function getProjectNarrative({ projectDir, }) {
24
- return loadConfig({ projectDir }).pipe(Effect.map((config) => config.project === undefined
25
- ? undefined
26
- : serializeProjectNarrative(config.project)));
27
- }
@@ -1,2 +0,0 @@
1
- export * from '../../report/index.js';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/report/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
@@ -1 +0,0 @@
1
- export * from '../../report/index.js';
@@ -1,3 +0,0 @@
1
- export { markdown } from './markdown.js';
2
- export type { MarkdownContent } from './markdown.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/markdown/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -1 +0,0 @@
1
- export { markdown } from './markdown.js';
@@ -1,7 +0,0 @@
1
- export interface MarkdownContent {
2
- readonly kind: 'markdown';
3
- readonly content: string;
4
- }
5
- /** Authors Markdown without introducing MDX or executable components. */
6
- export declare function markdown(strings: TemplateStringsArray, ...values: readonly (string | number)[]): MarkdownContent;
7
- //# sourceMappingURL=markdown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/markdown/markdown.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CACtB,OAAO,EAAE,oBAAoB,EAC7B,GAAG,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACtC,eAAe,CAMjB"}
@@ -1,13 +0,0 @@
1
- /** Authors Markdown without introducing MDX or executable components. */
2
- export function markdown(strings, ...values) {
3
- const content = strings.reduce((result, part, index) => result + part + (values[index] ?? ''), '');
4
- return { kind: 'markdown', content: dedent(content) };
5
- }
6
- function dedent(value) {
7
- const lines = value.replace(/^\n/, '').replace(/\s+$/, '').split('\n');
8
- const indents = lines
9
- .filter((line) => line.trim().length > 0)
10
- .map((line) => line.match(/^\s*/)?.[0].length ?? 0);
11
- const indent = indents.length === 0 ? 0 : Math.min(...indents);
12
- return lines.map((line) => line.slice(indent)).join('\n');
13
- }
@@ -1,3 +0,0 @@
1
- export { queryDependencies } from './query-dependencies.js';
2
- export { DependencyTargetNotFound } from './query-dependencies.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/query-dependencies/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -1,4 +0,0 @@
1
- // CLI and package consumers use this focused source Dependency query.
2
- export { queryDependencies } from './query-dependencies.js';
3
- // Error views use this to identify a Target outside the analysis universe.
4
- export { DependencyTargetNotFound } from './query-dependencies.js';
@@ -1,12 +0,0 @@
1
- import { Effect } from 'effect';
2
- import { type DependencyQueryOptions } from '../../domain/file-graph/index.js';
3
- declare const DependencyTargetNotFound_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
4
- readonly _tag: "DependencyTargetNotFound";
5
- } & Readonly<A>;
6
- export declare class DependencyTargetNotFound extends DependencyTargetNotFound_base<{
7
- readonly target: string;
8
- }> {
9
- }
10
- export declare function queryDependencies(configPath: string, target: string, options?: DependencyQueryOptions): Effect.Effect<readonly import("../../domain/file-graph/file-graph.js").DependencyEntry[], import("../../services/config/errors.js").ConfigError | import("../../services/file-cruiser/errors.js").CruiseError | DependencyTargetNotFound, never>;
11
- export {};
12
- //# sourceMappingURL=query-dependencies.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-dependencies.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/query-dependencies/query-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAGL,KAAK,sBAAsB,EAE5B,MAAM,kCAAkC,CAAC;;;;AAK1C,qBAAa,wBAAyB,SAAQ,8BAE5C;IACA,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG;AAEL,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,sBAA2B,oPAQrC"}
@@ -1,20 +0,0 @@
1
- import { Data, Effect } from 'effect';
2
- import { NodeServices } from '@effect/platform-node';
3
- import { fileDependencies, folderDependencies, } from '../../domain/file-graph/index.js';
4
- import { ConfigServiceLive } from '../../services/config/index.js';
5
- import { CruiserLive } from '../../services/file-cruiser/index.js';
6
- import { loadProject } from '../load-project/index.js';
7
- export class DependencyTargetNotFound extends Data.TaggedError('DependencyTargetNotFound') {
8
- }
9
- export function queryDependencies(configPath, target, options = {}) {
10
- return loadProject(configPath).pipe(Effect.flatMap(({ fileGraph }) => query(fileGraph, target, options)), Effect.provide(ConfigServiceLive), Effect.provide(CruiserLive), Effect.provide(NodeServices.layer));
11
- }
12
- function query(fileGraph, target, options) {
13
- if (fileGraph.has(target)) {
14
- return Effect.succeed(fileDependencies(fileGraph, target, options));
15
- }
16
- if ([...fileGraph.keys()].some((path) => path.startsWith(`${target}/`))) {
17
- return Effect.succeed(folderDependencies(fileGraph, target, options));
18
- }
19
- return new DependencyTargetNotFound({ target });
20
- }