@timiagama/ecr 0.0.1 → 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.
Files changed (138) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +411 -7
  4. package/dist/bin.d.ts +20 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +26 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/cli/corpus-loader.d.ts +198 -0
  9. package/dist/cli/corpus-loader.d.ts.map +1 -0
  10. package/dist/cli/corpus-loader.js +351 -0
  11. package/dist/cli/corpus-loader.js.map +1 -0
  12. package/dist/cli/corpus-statistics.d.ts +113 -0
  13. package/dist/cli/corpus-statistics.d.ts.map +1 -0
  14. package/dist/cli/corpus-statistics.js +119 -0
  15. package/dist/cli/corpus-statistics.js.map +1 -0
  16. package/dist/cli/diagnostic-reporter.d.ts +103 -0
  17. package/dist/cli/diagnostic-reporter.d.ts.map +1 -0
  18. package/dist/cli/diagnostic-reporter.js +254 -0
  19. package/dist/cli/diagnostic-reporter.js.map +1 -0
  20. package/dist/cli/project-ignore.d.ts +113 -0
  21. package/dist/cli/project-ignore.d.ts.map +1 -0
  22. package/dist/cli/project-ignore.js +199 -0
  23. package/dist/cli/project-ignore.js.map +1 -0
  24. package/dist/cli/safe-text.d.ts +25 -0
  25. package/dist/cli/safe-text.d.ts.map +1 -0
  26. package/dist/cli/safe-text.js +34 -0
  27. package/dist/cli/safe-text.js.map +1 -0
  28. package/dist/cli/supervisor.d.ts +108 -0
  29. package/dist/cli/supervisor.d.ts.map +1 -0
  30. package/dist/cli/supervisor.js +139 -0
  31. package/dist/cli/supervisor.js.map +1 -0
  32. package/dist/cli.d.ts +247 -0
  33. package/dist/cli.d.ts.map +1 -0
  34. package/dist/cli.js +591 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/corpus-validator.d.ts +183 -0
  37. package/dist/corpus-validator.d.ts.map +1 -0
  38. package/dist/corpus-validator.js +479 -0
  39. package/dist/corpus-validator.js.map +1 -0
  40. package/dist/document-identity-rule.d.ts +198 -0
  41. package/dist/document-identity-rule.d.ts.map +1 -0
  42. package/dist/document-identity-rule.js +244 -0
  43. package/dist/document-identity-rule.js.map +1 -0
  44. package/dist/ecr.d.ts +103 -0
  45. package/dist/ecr.d.ts.map +1 -0
  46. package/dist/ecr.js +216 -0
  47. package/dist/ecr.js.map +1 -0
  48. package/dist/glob-pattern.d.ts +94 -0
  49. package/dist/glob-pattern.d.ts.map +1 -0
  50. package/dist/glob-pattern.js +188 -0
  51. package/dist/glob-pattern.js.map +1 -0
  52. package/dist/heading-source-form.d.ts +77 -0
  53. package/dist/heading-source-form.d.ts.map +1 -0
  54. package/dist/heading-source-form.js +129 -0
  55. package/dist/heading-source-form.js.map +1 -0
  56. package/dist/identifier-grammar.d.ts +212 -0
  57. package/dist/identifier-grammar.d.ts.map +1 -0
  58. package/dist/identifier-grammar.js +273 -0
  59. package/dist/identifier-grammar.js.map +1 -0
  60. package/dist/index.d.ts +19 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +11 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/inline-reference-rule.d.ts +557 -0
  65. package/dist/inline-reference-rule.d.ts.map +1 -0
  66. package/dist/inline-reference-rule.js +802 -0
  67. package/dist/inline-reference-rule.js.map +1 -0
  68. package/dist/meta-documents.d.ts +91 -0
  69. package/dist/meta-documents.d.ts.map +1 -0
  70. package/dist/meta-documents.js +133 -0
  71. package/dist/meta-documents.js.map +1 -0
  72. package/dist/per-document-visitor.d.ts +510 -0
  73. package/dist/per-document-visitor.d.ts.map +1 -0
  74. package/dist/per-document-visitor.js +1032 -0
  75. package/dist/per-document-visitor.js.map +1 -0
  76. package/dist/references-section-rule.d.ts +482 -0
  77. package/dist/references-section-rule.d.ts.map +1 -0
  78. package/dist/references-section-rule.js +777 -0
  79. package/dist/references-section-rule.js.map +1 -0
  80. package/dist/section-hierarchy-rule.d.ts +299 -0
  81. package/dist/section-hierarchy-rule.d.ts.map +1 -0
  82. package/dist/section-hierarchy-rule.js +482 -0
  83. package/dist/section-hierarchy-rule.js.map +1 -0
  84. package/dist/source-alignment.d.ts +41 -0
  85. package/dist/source-alignment.d.ts.map +1 -0
  86. package/dist/source-alignment.js +166 -0
  87. package/dist/source-alignment.js.map +1 -0
  88. package/dist/source-lines.d.ts +69 -0
  89. package/dist/source-lines.d.ts.map +1 -0
  90. package/dist/source-lines.js +104 -0
  91. package/dist/source-lines.js.map +1 -0
  92. package/dist/spec-version.d.ts +19 -0
  93. package/dist/spec-version.d.ts.map +1 -0
  94. package/dist/spec-version.js +19 -0
  95. package/dist/spec-version.js.map +1 -0
  96. package/dist/types.d.ts +219 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +11 -0
  99. package/dist/types.js.map +1 -0
  100. package/examples/docs/0. Orientation/0.0 - System Overview.md +34 -0
  101. package/examples/docs/0. Orientation/0.0.1 - Glossary.md +21 -0
  102. package/examples/docs/0. Orientation/0.0.2 - Quality Gates.md +22 -0
  103. package/examples/docs/3. Ingestion/3.1 - Ingestion - Validation Rules.md +33 -0
  104. package/examples/docs/4. Payments/4.10 - Settlement.md +22 -0
  105. package/examples/docs/4. Payments/4.2 - Payment Processing Contract.md +33 -0
  106. package/examples/docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md +38 -0
  107. package/examples/docs/8. Orchestration/8.1.3 - Retry Policy.md +17 -0
  108. package/examples/docs/8. Orchestration/8.10 - Dead Letter Queue.md +20 -0
  109. package/examples/docs/README.md +7 -0
  110. package/package.json +65 -7
  111. package/protocol/navigation-protocol.md +223 -0
  112. package/spec/v2/1 - ECR - Structural Specification.md +1467 -0
  113. package/spec/v2/2 - ECR - User Guide.md +845 -0
  114. package/spec/v2/3 - Design Rationale - The Section Separator.md +243 -0
  115. package/src/bin.ts +30 -0
  116. package/src/cli/corpus-loader.ts +482 -0
  117. package/src/cli/corpus-statistics.ts +196 -0
  118. package/src/cli/diagnostic-reporter.ts +344 -0
  119. package/src/cli/project-ignore.ts +238 -0
  120. package/src/cli/safe-text.ts +39 -0
  121. package/src/cli/supervisor.ts +204 -0
  122. package/src/cli.ts +836 -0
  123. package/src/corpus-validator.ts +642 -0
  124. package/src/document-identity-rule.ts +422 -0
  125. package/src/ecr.ts +298 -0
  126. package/src/glob-pattern.ts +242 -0
  127. package/src/heading-source-form.ts +173 -0
  128. package/src/identifier-grammar.ts +380 -0
  129. package/src/index.ts +78 -0
  130. package/src/inline-reference-rule.ts +1235 -0
  131. package/src/meta-documents.ts +159 -0
  132. package/src/per-document-visitor.ts +1528 -0
  133. package/src/references-section-rule.ts +1182 -0
  134. package/src/section-hierarchy-rule.ts +705 -0
  135. package/src/source-alignment.ts +209 -0
  136. package/src/source-lines.ts +123 -0
  137. package/src/spec-version.ts +19 -0
  138. package/src/types.ts +267 -0
package/dist/cli.js ADDED
@@ -0,0 +1,591 @@
1
+ /**
2
+ * ECR Command Line
3
+ *
4
+ * The executable entry point is `bin.ts`; this module only defines the
5
+ * commands, so that tests can drive them without spawning a process.
6
+ *
7
+ * Three commands, and deliberately no more:
8
+ *
9
+ * - `lint` validates a corpus against the ECR structural rules
10
+ * - `stats` measures the explicit structure a corpus already carries
11
+ * - `init` installs the ECR documentation, including the agent navigation
12
+ * protocol, beside a corpus
13
+ *
14
+ * There is no `backlinks` command, and there should never be one. ECR's claim
15
+ * is that a corpus is navigable with `grep` alone; a navigation command here
16
+ * would quietly make the tool a dependency of the thing it exists to prove
17
+ * unnecessary. Navigation belongs in the protocol `init` installs, not in this
18
+ * binary.
19
+ */
20
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from 'node:fs';
21
+ import { dirname, join, resolve } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { Ecr } from './ecr.js';
24
+ import { ECR_SPEC_VERSION } from './spec-version.js';
25
+ import { CorpusLoader } from './cli/corpus-loader.js';
26
+ import { PROJECT_IGNORE_FILENAME, ProjectIgnoreFile } from './cli/project-ignore.js';
27
+ import { CorpusStatistics } from './cli/corpus-statistics.js';
28
+ import { DiagnosticReporter } from './cli/diagnostic-reporter.js';
29
+ import { showControlCharacters } from './cli/safe-text.js';
30
+ import { DEFAULT_SUPERVISION_LIMITS, SUPERVISED_VARIABLE, Supervisor } from './cli/supervisor.js';
31
+ /** Process exit code signalling success. */
32
+ const EXIT_SUCCESS = 0;
33
+ /** Process exit code signalling that the corpus contains errors. */
34
+ const EXIT_VALIDATION_FAILED = 1;
35
+ /**
36
+ * Process exit code signalling that the command could not run: arguments it
37
+ * could not understand, or a corpus it could not find or fully read.
38
+ */
39
+ const EXIT_USAGE_ERROR = 2;
40
+ /**
41
+ * What `init` installs, from the package root, keeping each path as it is in
42
+ * the repository so the README's relative links work in the installed copy.
43
+ */
44
+ const INSTALLED_DOCUMENTATION = [
45
+ 'README.md',
46
+ 'LICENSE',
47
+ 'NOTICE',
48
+ 'protocol',
49
+ 'spec',
50
+ 'examples',
51
+ ];
52
+ /** Every exit code this command itself produces. */
53
+ const EXIT_CODES = [EXIT_SUCCESS, EXIT_VALIDATION_FAILED, EXIT_USAGE_ERROR];
54
+ /**
55
+ * How V8 says it has run out of heap. It says so differently depending on
56
+ * when it happens: "Reached heap limit" once running, "JavaScript heap out of
57
+ * memory" on an allocation, and "Fatal JavaScript out of memory" while it is
58
+ * still starting, which is what a limit of a megabyte or two produces.
59
+ */
60
+ const HEAP_EXHAUSTED = /Reached heap limit|out of memory/i;
61
+ /**
62
+ * The longest time limit that can be applied: `spawnSync` takes milliseconds
63
+ * as a 32-bit count, which is about twenty-five days.
64
+ */
65
+ const MAXIMUM_TIMEOUT_SECONDS = 2_147_483;
66
+ /** The largest heap limit that can be applied, in mebibytes: a tebibyte. */
67
+ const MAXIMUM_MEMORY_MIB = 1_048_576;
68
+ /** Where `lint` and `stats` look when no directory is given. */
69
+ const DEFAULT_CORPUS_DIRECTORY = 'docs';
70
+ /**
71
+ * Where `init` installs when no directory is given: beside the corpus, never
72
+ * in it, because the specification's own DocIDs would collide with the
73
+ * user's.
74
+ */
75
+ const DEFAULT_INSTALL_DIRECTORY = 'ecr';
76
+ /** Usage text shown for `--help` and on a usage error. */
77
+ const USAGE_TEXT = `
78
+ ecr - Explicit Constraint Referencing
79
+
80
+ Usage
81
+ ecr lint [directory] [options] validate a corpus
82
+ ecr stats [directory] [options] measure a corpus
83
+ ecr init [directory] install the ECR documentation
84
+
85
+ Options
86
+ --format <pretty|json> output format (default: pretty)
87
+ --ignore <glob> exclude paths; repeatable
88
+ --example lint or measure the example corpus bundled
89
+ with this package, instead of a directory
90
+ --timeout <seconds> stop lint or stats if it takes longer
91
+ (default: 120; 0 for no limit)
92
+ --max-memory <MiB> cap the heap lint or stats may use
93
+ (default: 2048; 0 for node's own default)
94
+ --version show the linter and spec versions
95
+ --help show this message
96
+
97
+ The directory defaults to ./docs, or to ./ecr for init.
98
+
99
+ lint and stats parse your documents in a separate process, so that a
100
+ document which takes unreasonably long to parse stops rather than hanging
101
+ the command. A run that has to be stopped prints nothing and exits 2,
102
+ because a report of a corpus that was never finished is not a report.
103
+
104
+ Patterns in .ecrignore, in the directory the command runs from, are
105
+ excluded too. They are relative to that directory; --ignore patterns are
106
+ relative to the directory being linted.
107
+
108
+ Exit codes
109
+ 0 no errors
110
+ 1 the corpus contains errors
111
+ 2 the command could not run
112
+ `;
113
+ /**
114
+ * Parses command-line arguments.
115
+ *
116
+ * Throws on anything it cannot understand rather than guessing, because a
117
+ * silently misread `--ignore` would quietly exclude documents from validation.
118
+ */
119
+ export class ArgumentParser {
120
+ /**
121
+ * Parses an argument list.
122
+ *
123
+ * @param argv - Arguments, excluding the node executable and script path
124
+ * @returns The parsed command line
125
+ * @throws Error when the arguments cannot be understood
126
+ */
127
+ parse(argv) {
128
+ const [commandCandidate, ...rest] = argv;
129
+ if (commandCandidate === undefined) {
130
+ throw new Error('No command given.');
131
+ }
132
+ if (!this.isCommandName(commandCandidate)) {
133
+ throw new Error(`Unknown command "${commandCandidate}".`);
134
+ }
135
+ let corpusRoot = undefined;
136
+ let useExample = false;
137
+ let format = 'pretty';
138
+ let timeoutSeconds = undefined;
139
+ let maxMemoryMib = undefined;
140
+ const ignorePatterns = [];
141
+ for (let index = 0; index < rest.length; index += 1) {
142
+ const argument = rest[index] ?? '';
143
+ if (argument === '--example') {
144
+ useExample = true;
145
+ continue;
146
+ }
147
+ if (argument === '--format') {
148
+ const value = rest[index + 1];
149
+ if (value !== 'pretty' && value !== 'json') {
150
+ throw new Error('--format expects "pretty" or "json".');
151
+ }
152
+ format = value;
153
+ index += 1;
154
+ continue;
155
+ }
156
+ if (argument === '--ignore') {
157
+ const value = rest[index + 1];
158
+ if (value === undefined || value.startsWith('--')) {
159
+ throw new Error('--ignore expects a glob pattern.');
160
+ }
161
+ ignorePatterns.push(value);
162
+ index += 1;
163
+ continue;
164
+ }
165
+ if (argument === '--timeout') {
166
+ timeoutSeconds = ArgumentParser.readWholeNumber(rest[index + 1], '--timeout', 'seconds', MAXIMUM_TIMEOUT_SECONDS);
167
+ index += 1;
168
+ continue;
169
+ }
170
+ if (argument === '--max-memory') {
171
+ maxMemoryMib = ArgumentParser.readWholeNumber(rest[index + 1], '--max-memory', 'mebibytes', MAXIMUM_MEMORY_MIB);
172
+ index += 1;
173
+ continue;
174
+ }
175
+ if (argument.startsWith('--')) {
176
+ throw new Error(`Unknown option "${argument}".`);
177
+ }
178
+ if (corpusRoot !== undefined) {
179
+ throw new Error('More than one directory given.');
180
+ }
181
+ corpusRoot = argument;
182
+ }
183
+ if (useExample && commandCandidate === 'init') {
184
+ throw new Error('--example works with lint and stats; init installs into your own project.');
185
+ }
186
+ if (useExample && corpusRoot !== undefined) {
187
+ throw new Error('Give a directory or --example, not both.');
188
+ }
189
+ return {
190
+ command: commandCandidate,
191
+ corpusRoot: corpusRoot ?? (commandCandidate === 'init' ? DEFAULT_INSTALL_DIRECTORY : DEFAULT_CORPUS_DIRECTORY),
192
+ useExample,
193
+ format,
194
+ ignorePatterns,
195
+ ...(timeoutSeconds !== undefined ? { timeoutSeconds } : {}),
196
+ ...(maxMemoryMib !== undefined ? { maxMemoryMib } : {}),
197
+ };
198
+ }
199
+ /**
200
+ * Reads an option's value as a whole number of some unit, where zero means
201
+ * no limit.
202
+ *
203
+ * @param value - The argument following the option
204
+ * @param option - The option's name, for the message
205
+ * @param unit - What the number counts, for the message
206
+ * @param maximum - The largest value the limit can be applied as
207
+ * @returns The number
208
+ * @throws When the value is missing, is not a whole number, or is beyond what can be applied
209
+ */
210
+ static readWholeNumber(value, option, unit, maximum) {
211
+ const parsed = value === undefined ? Number.NaN : Number(value);
212
+ if (!Number.isInteger(parsed) || parsed < 0) {
213
+ throw new Error(`${option} expects a whole number of ${unit}, or 0 for no limit.`);
214
+ }
215
+ // A limit too large to apply is not the same as no limit: passed on, it
216
+ // would fail inside the machinery that imposes it rather than here.
217
+ if (parsed > maximum) {
218
+ throw new Error(`${option} expects at most ${String(maximum)} ${unit}, or 0 for no limit.`);
219
+ }
220
+ return parsed;
221
+ }
222
+ /**
223
+ * Determines whether a string names a supported command.
224
+ *
225
+ * @param candidate - The string to test
226
+ * @returns `true` when the string is a command name
227
+ */
228
+ isCommandName(candidate) {
229
+ return candidate === 'lint' || candidate === 'stats' || candidate === 'init';
230
+ }
231
+ }
232
+ /**
233
+ * Runs the CLI commands.
234
+ *
235
+ * Output is returned rather than printed so that the commands can be exercised
236
+ * directly by tests without capturing a stream.
237
+ */
238
+ export class EcrCommandLine {
239
+ /** Parses the command line. */
240
+ argumentParser;
241
+ /**
242
+ * The directory the command runs from: relative directories resolve against
243
+ * it, and it is the project root whose `.ecrignore` applies.
244
+ */
245
+ workingDirectory;
246
+ /** The package's own root, holding `package.json` and what `init` installs. */
247
+ packageRoot;
248
+ /** How to run the parsing commands in a child process, when asked to. */
249
+ supervision;
250
+ /**
251
+ * Creates a command-line runner.
252
+ *
253
+ * @param options - Where the command runs from and where the package lives; both default to the real ones
254
+ */
255
+ constructor(options = {}) {
256
+ this.argumentParser = new ArgumentParser();
257
+ this.workingDirectory = options.workingDirectory ?? process.cwd();
258
+ // Resolved relative to this module, so it is correct whether the CLI runs
259
+ // from source, from `dist/`, or from an installed package.
260
+ this.packageRoot = options.packageRoot ?? resolve(dirname(fileURLToPath(import.meta.url)), '..');
261
+ this.supervision = options.supervision;
262
+ }
263
+ /**
264
+ * Runs one invocation.
265
+ *
266
+ * @param argv - Arguments, excluding the node executable and script path
267
+ * @returns The text to print and the process exit code
268
+ */
269
+ run(argv) {
270
+ if (argv.length === 0) {
271
+ return this.fail(USAGE_TEXT);
272
+ }
273
+ if (argv.includes('--help')) {
274
+ return this.succeed(USAGE_TEXT);
275
+ }
276
+ if (argv.includes('--version')) {
277
+ return this.succeed(`ecr ${this.showPackageVersion()} (ECR spec ${ECR_SPEC_VERSION})\n`);
278
+ }
279
+ let parsed;
280
+ try {
281
+ parsed = this.argumentParser.parse(argv);
282
+ }
283
+ catch (error) {
284
+ const message = error instanceof Error ? error.message : String(error);
285
+ return this.fail(` ${message}\n${USAGE_TEXT}`);
286
+ }
287
+ const corpusRoot = resolve(this.workingDirectory, parsed.corpusRoot);
288
+ // `init` installs the documentation, so it may create the directory; the
289
+ // other commands read a corpus that must already exist.
290
+ if (parsed.command === 'init') {
291
+ return this.runInit(corpusRoot, parsed.corpusRoot);
292
+ }
293
+ // Everything past this point parses documents, which is the work that
294
+ // cannot be bounded from the inside.
295
+ const supervision = this.readSupervision();
296
+ if (supervision !== undefined) {
297
+ return this.runSupervised(supervision, argv, parsed);
298
+ }
299
+ // The bundled example belongs to the package, not the project, so the
300
+ // project's .ecrignore does not apply to it; --ignore still does.
301
+ if (parsed.useExample) {
302
+ return this.runValidation(parsed, join(this.packageRoot, 'examples', 'docs'), 'the bundled example corpus', false);
303
+ }
304
+ return this.runValidation(parsed, corpusRoot, parsed.corpusRoot, true);
305
+ }
306
+ /**
307
+ * Runs `lint` or `stats` against a corpus.
308
+ *
309
+ * @param parsed - The parsed command line
310
+ * @param corpusRoot - Resolved corpus directory
311
+ * @param displayedRoot - How to name the corpus in messages
312
+ * @param applyProjectIgnore - Whether the project's `.ecrignore` applies
313
+ * @returns The text to print and the process exit code
314
+ */
315
+ runValidation(parsed, corpusRoot, displayedRoot, applyProjectIgnore) {
316
+ if (!existsSync(corpusRoot) || !statSync(corpusRoot).isDirectory()) {
317
+ return this.fail(` Directory not found: ${displayedRoot}\n`);
318
+ }
319
+ let projectIgnore = undefined;
320
+ if (applyProjectIgnore) {
321
+ const read = new ProjectIgnoreFile(this.workingDirectory).read();
322
+ if (read.kind === 'unreadable') {
323
+ return this.fail(` Could not read ${PROJECT_IGNORE_FILENAME} (${read.reason}).\n`);
324
+ }
325
+ if (read.kind === 'patterns') {
326
+ projectIgnore = { workingDirectory: this.workingDirectory, patterns: read.patterns };
327
+ }
328
+ }
329
+ const loader = new CorpusLoader(corpusRoot, parsed.ignorePatterns, projectIgnore);
330
+ const loaded = loader.load();
331
+ if (loaded.rootExcluded) {
332
+ return this.fail(` ${displayedRoot} is excluded by ${PROJECT_IGNORE_FILENAME}, so there is nothing to check.\n`);
333
+ }
334
+ // A corpus that was not fully read cannot pass or be summarised, so the
335
+ // command cannot run; the walk still finished, so every such path is named.
336
+ if (loaded.unreadablePaths.length > 0) {
337
+ return this.fail(' Could not read:\n' +
338
+ loaded.unreadablePaths.map((unreadable) => ` ${unreadable.path} (${unreadable.reason})\n`).join('') +
339
+ ' Fix these paths, or exclude them with --ignore.\n');
340
+ }
341
+ if (loaded.documents.length === 0) {
342
+ // Links are the likeliest reason a directory of documents yields none.
343
+ const links = DiagnosticReporter.listNotFollowed(loaded.notFollowedPaths);
344
+ return this.fail(` No Markdown documents found in ${displayedRoot}\n` +
345
+ links.map((line) => `${line}\n`).join('') +
346
+ (links.length > 0 ? ' Links are not followed, because `rg` and `grep -r` do not follow them either.\n' : ''));
347
+ }
348
+ const corpusResult = new Ecr().validateCorpus(loaded.documents);
349
+ const reporter = new DiagnosticReporter(parsed.format);
350
+ if (parsed.command === 'stats') {
351
+ const statistics = new CorpusStatistics(corpusResult);
352
+ return this.succeed(reporter.reportStatistics(statistics.summarise(), loaded.notFollowedPaths));
353
+ }
354
+ const output = reporter.reportValidation(corpusResult, loaded.excludedPaths, loaded.notFollowedPaths);
355
+ const hasErrors = this.tellCorpusHasErrors(corpusResult);
356
+ // A report of a failing corpus is still the command's result, so it goes
357
+ // to stdout; only the exit code signals the failure.
358
+ return {
359
+ output,
360
+ stream: 'stdout',
361
+ exitCode: hasErrors ? EXIT_VALIDATION_FAILED : EXIT_SUCCESS,
362
+ };
363
+ }
364
+ /**
365
+ * Installs the ECR documentation into a new or empty directory, keeping the
366
+ * repository's layout, and adds that directory to the project's
367
+ * `.ecrignore` so that linting the project does not validate it.
368
+ *
369
+ * Everything that could stop the installation is checked before anything is
370
+ * written, and a failure part-way removes what was copied.
371
+ *
372
+ * @param destination - Resolved installation directory
373
+ * @param displayedDestination - The directory as the user typed it, for messages
374
+ * @returns The text to print and the process exit code
375
+ */
376
+ runInit(destination, displayedDestination) {
377
+ const packageRoot = this.packageRoot;
378
+ const missing = INSTALLED_DOCUMENTATION.filter((path) => !existsSync(join(packageRoot, path)));
379
+ if (missing.length > 0) {
380
+ return this.fail(` The packaged documentation is incomplete; missing: ${missing.join(', ')}\n`);
381
+ }
382
+ const existed = existsSync(destination);
383
+ let isDirectory = false;
384
+ let isEmpty = true;
385
+ try {
386
+ isDirectory = existed && statSync(destination).isDirectory();
387
+ isEmpty = !isDirectory || readdirSync(destination).length === 0;
388
+ }
389
+ catch (error) {
390
+ return this.fail(` Could not examine ${displayedDestination} (${ProjectIgnoreFile.showReason(error)}), so nothing was installed.\n`);
391
+ }
392
+ if (existed && !isDirectory) {
393
+ return this.fail(` ${displayedDestination} exists but is not a directory.\n`);
394
+ }
395
+ // It may hold the user's own documents, so the advice is to choose
396
+ // another directory; deleting is only right for an earlier installation.
397
+ if (!isEmpty) {
398
+ return this.fail(` ${displayedDestination} already exists and is not empty.\n` +
399
+ ' init installs into a new or empty directory, so choose another one.\n' +
400
+ ' If this is an earlier ECR installation, delete it and run init again\n' +
401
+ ' to install this version.\n');
402
+ }
403
+ const exclusion = ProjectIgnoreFile.readInstallExclusion(this.workingDirectory, destination);
404
+ if (exclusion.kind === 'invalid') {
405
+ return this.fail(` Cannot install into ${displayedDestination}: ${exclusion.reason}.\n`);
406
+ }
407
+ const ignoreFile = new ProjectIgnoreFile(this.workingDirectory);
408
+ const currentIgnore = ignoreFile.read();
409
+ if (exclusion.kind === 'pattern' && currentIgnore.kind === 'unreadable') {
410
+ return this.fail(` Could not read ${PROJECT_IGNORE_FILENAME} (${currentIgnore.reason}), so nothing was installed.\n`);
411
+ }
412
+ try {
413
+ mkdirSync(destination, { recursive: true });
414
+ for (const path of INSTALLED_DOCUMENTATION) {
415
+ cpSync(join(packageRoot, path), join(destination, path), { recursive: true, errorOnExist: true, force: false });
416
+ }
417
+ }
418
+ catch (error) {
419
+ const reason = ProjectIgnoreFile.showReason(error);
420
+ const cleanupFailure = this.removePartialInstallation(destination, existed);
421
+ if (cleanupFailure !== undefined) {
422
+ return this.fail(` Could not install the documentation (${reason}), and could not remove\n` +
423
+ ` what was copied (${cleanupFailure}). Delete ${displayedDestination} before running init again.\n`);
424
+ }
425
+ return this.fail(` Could not install the documentation (${reason}), so nothing was installed.\n`);
426
+ }
427
+ let ignoreNote = ` ${displayedDestination} is outside this directory, so ${PROJECT_IGNORE_FILENAME} was not changed.\n`;
428
+ if (exclusion.kind === 'pattern') {
429
+ try {
430
+ ignoreNote = ignoreFile.addPattern(exclusion.pattern) === 'added'
431
+ ? ` Added ${exclusion.pattern} to ${PROJECT_IGNORE_FILENAME}, so linting this project skips it.\n`
432
+ : ` ${PROJECT_IGNORE_FILENAME} already excludes it (${exclusion.pattern}).\n`;
433
+ }
434
+ catch (error) {
435
+ return this.fail(` Installed the documentation in ${displayedDestination}, but could not update ` +
436
+ `${PROJECT_IGNORE_FILENAME} (${ProjectIgnoreFile.showReason(error)}).\n` +
437
+ ` Add this line to ${PROJECT_IGNORE_FILENAME} yourself: ${exclusion.pattern}\n`);
438
+ }
439
+ }
440
+ // Success says where the documentation went, in a name the user gave,
441
+ // so it is made safe to print for the same reason a failure is.
442
+ return this.succeed(showControlCharacters(`\n Installed the ECR documentation in ${displayedDestination}\n\n` +
443
+ ` Start with ${join(displayedDestination, 'README.md')}\n` +
444
+ ` Point your coding agent at ${join(displayedDestination, 'protocol', 'navigation-protocol.md')}\n` +
445
+ ' It is the half that does the navigating; the linter only checks structure.\n\n' +
446
+ `${ignoreNote}\n`));
447
+ }
448
+ /**
449
+ * Removes what a failed installation copied. The destination was new or
450
+ * empty, so nothing of the user's is inside it.
451
+ *
452
+ * @param destination - The installation directory
453
+ * @param existed - Whether it existed, empty, before installation began
454
+ * @returns Why removal failed, or `undefined` when everything copied was removed
455
+ */
456
+ removePartialInstallation(destination, existed) {
457
+ try {
458
+ if (!existed) {
459
+ rmSync(destination, { recursive: true, force: true });
460
+ return undefined;
461
+ }
462
+ for (const path of INSTALLED_DOCUMENTATION) {
463
+ rmSync(join(destination, path), { recursive: true, force: true });
464
+ }
465
+ return undefined;
466
+ }
467
+ catch (error) {
468
+ return ProjectIgnoreFile.showReason(error);
469
+ }
470
+ }
471
+ /**
472
+ * Reads how this invocation should bound its parsing, if at all.
473
+ *
474
+ * @returns The supervision settings, or `undefined` when this invocation does the work itself
475
+ */
476
+ readSupervision() {
477
+ // The child is this same executable, and must do the work rather than
478
+ // start a child of its own.
479
+ return process.env[SUPERVISED_VARIABLE] === '1' ? undefined : this.supervision;
480
+ }
481
+ /**
482
+ * Runs `lint` or `stats` in a child process with a time limit and a heap
483
+ * limit, and passes on what it produced.
484
+ *
485
+ * A child that had to be stopped produced no usable report, however much of
486
+ * one reached this process, so none of it is passed on: the invocation
487
+ * failed, and says why.
488
+ *
489
+ * @param settings - Where the child's script is, and any limits overriding the defaults
490
+ * @param argv - The arguments to pass on, exactly as they were given
491
+ * @param parsed - The same arguments, for the limits they carry
492
+ * @returns The child's output and exit code, or the reason it was stopped
493
+ */
494
+ runSupervised(settings, argv, parsed) {
495
+ // What the command line asked for wins; what the run was configured with
496
+ // stands where the command line said nothing; the defaults are the rest.
497
+ const limits = {
498
+ ...DEFAULT_SUPERVISION_LIMITS,
499
+ ...settings.limits,
500
+ ...(parsed.timeoutSeconds !== undefined ? { timeoutMs: parsed.timeoutSeconds * 1000 } : {}),
501
+ ...(parsed.maxMemoryMib !== undefined ? { memoryMib: parsed.maxMemoryMib } : {}),
502
+ };
503
+ const outcome = new Supervisor(settings.entryPoint, limits, this.workingDirectory).run(argv);
504
+ if (outcome.kind === 'stopped') {
505
+ return this.fail(` ecr did not finish: ${outcome.reason}.\n`);
506
+ }
507
+ // Every code this command exits with means something. A child that ended
508
+ // with any other did not end as this command ends: it ran out of heap, or
509
+ // the runtime beneath it stopped. Passing such a code on would offer it
510
+ // as a verdict on the corpus, and on Windows as a number no caller could
511
+ // read.
512
+ if (!EXIT_CODES.includes(outcome.exitCode)) {
513
+ return this.fail(` ecr did not finish: ${this.showAbnormalExit(outcome, limits)}.\n`);
514
+ }
515
+ // A verdict on a corpus comes with the report it is a verdict on. A child
516
+ // that exited 1 having printed nothing never got as far as validating,
517
+ // and passing that code on would read as a corpus full of errors.
518
+ if (outcome.stdout === '' && outcome.exitCode === EXIT_VALIDATION_FAILED) {
519
+ return this.fail(` ecr did not finish: the run failed without producing a report.\n${outcome.stderr}`);
520
+ }
521
+ // A command writes to one stream per invocation, so whichever the child
522
+ // used is the one this process writes to.
523
+ return outcome.stdout === ''
524
+ ? { output: outcome.stderr, stream: 'stderr', exitCode: outcome.exitCode }
525
+ : { output: outcome.stdout, stream: 'stdout', exitCode: outcome.exitCode };
526
+ }
527
+ /**
528
+ * Describes a child that ended in a way this command never ends.
529
+ *
530
+ * Running out of heap is worth naming, because it is the one such ending a
531
+ * user can do anything about, and the limit that caused it is one they set.
532
+ *
533
+ * @param outcome - What the child produced before it ended
534
+ * @param limits - The limits it was given
535
+ * @returns The reason, as a phrase completing "ecr did not finish..."
536
+ */
537
+ showAbnormalExit(outcome, limits) {
538
+ if (HEAP_EXHAUSTED.test(outcome.stderr)) {
539
+ return (`it ran out of heap, limited to ${String(limits.memoryMib)} MiB. ` +
540
+ `Raise the limit with --max-memory <MiB>, or 0 for node's own default`);
541
+ }
542
+ return `the run ended unexpectedly (exit ${String(outcome.exitCode)})`;
543
+ }
544
+ /**
545
+ * Builds a successful outcome, written to stdout.
546
+ *
547
+ * @param output - The text to print
548
+ * @returns The outcome
549
+ */
550
+ succeed(output) {
551
+ return { output, stream: 'stdout', exitCode: EXIT_SUCCESS };
552
+ }
553
+ /**
554
+ * Builds the outcome of an invocation that could not run, written to stderr.
555
+ *
556
+ * @param output - The message to print
557
+ * @returns The outcome
558
+ */
559
+ fail(output) {
560
+ // A message names paths that came from the disk, so it is made safe to
561
+ // print for the same reason a report of a document's text is.
562
+ return { output: showControlCharacters(output), stream: 'stderr', exitCode: EXIT_USAGE_ERROR };
563
+ }
564
+ /**
565
+ * Reads the published package version from `package.json`.
566
+ *
567
+ * @returns The package version
568
+ */
569
+ showPackageVersion() {
570
+ const manifestText = readFileSync(join(this.packageRoot, 'package.json'), 'utf8');
571
+ const manifest = JSON.parse(manifestText);
572
+ return manifest.version;
573
+ }
574
+ /**
575
+ * Determines whether a corpus result contains any error-severity diagnostic.
576
+ *
577
+ * @param corpusResult - The result to inspect
578
+ * @returns `true` when at least one error was reported
579
+ */
580
+ tellCorpusHasErrors(corpusResult) {
581
+ for (const entry of corpusResult.documents) {
582
+ for (const diagnostic of entry.result.diagnostics) {
583
+ if (diagnostic.severity === 'error') {
584
+ return true;
585
+ }
586
+ }
587
+ }
588
+ return corpusResult.diagnostics.some((diagnostic) => diagnostic.severity === 'error');
589
+ }
590
+ }
591
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAqFlG,4CAA4C;AAC5C,MAAM,YAAY,GAAW,CAAC,CAAC;AAE/B,oEAAoE;AACpE,MAAM,sBAAsB,GAAW,CAAC,CAAC;AAEzC;;;GAGG;AACH,MAAM,gBAAgB,GAAW,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,uBAAuB,GAAsB;IACjD,WAAW;IACX,SAAS;IACT,QAAQ;IACR,UAAU;IACV,MAAM;IACN,UAAU;CACX,CAAC;AAEF,oDAAoD;AACpD,MAAM,UAAU,GAAsB,CAAC,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,CAAC,CAAC;AAE/F;;;;;GAKG;AACH,MAAM,cAAc,GAAW,mCAAmC,CAAC;AAEnE;;;GAGG;AACH,MAAM,uBAAuB,GAAW,SAAS,CAAC;AAElD,4EAA4E;AAC5E,MAAM,kBAAkB,GAAW,SAAS,CAAC;AAE7C,gEAAgE;AAChE,MAAM,wBAAwB,GAAW,MAAM,CAAC;AAEhD;;;;GAIG;AACH,MAAM,yBAAyB,GAAW,KAAK,CAAC;AAEhD,0DAA0D;AAC1D,MAAM,UAAU,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmC1B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACzB;;;;;;OAMG;IACI,KAAK,CAAC,IAAuB;QAClC,MAAM,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAEzC,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,oBAAoB,gBAAgB,IAAI,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,UAAU,GAAuB,SAAS,CAAC;QAC/C,IAAI,UAAU,GAAY,KAAK,CAAC;QAChC,IAAI,MAAM,GAAiB,QAAQ,CAAC;QACpC,IAAI,cAAc,GAAuB,SAAS,CAAC;QACnD,IAAI,YAAY,GAAuB,SAAS,CAAC;QACjD,MAAM,cAAc,GAAa,EAAE,CAAC;QAEpC,KAAK,IAAI,KAAK,GAAW,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YAC5D,MAAM,QAAQ,GAAW,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAE3C,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,UAAU,GAAG,IAAI,CAAC;gBAClB,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAuB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBAElD,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;oBAC3C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;gBAC1D,CAAC;gBAED,MAAM,GAAG,KAAK,CAAC;gBACf,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAuB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBAElD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBACtD,CAAC;gBAED,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3B,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,cAAc,GAAG,cAAc,CAAC,eAAe,CAC7C,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,uBAAuB,CACjE,CAAC;gBACF,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;gBAChC,YAAY,GAAG,cAAc,CAAC,eAAe,CAC3C,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,CACjE,CAAC;gBACF,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,IAAI,CAAC,CAAC;YACnD,CAAC;YAED,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,CAAC;YAED,UAAU,GAAG,QAAQ,CAAC;QACxB,CAAC;QAED,IAAI,UAAU,IAAI,gBAAgB,KAAK,MAAM,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,UAAU,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO;YACL,OAAO,EAAE,gBAAgB;YACzB,UAAU,EAAE,UAAU,IAAI,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,wBAAwB,CAAC;YAC9G,UAAU;YACV,MAAM;YACN,cAAc;YACd,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3D,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxD,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACK,MAAM,CAAC,eAAe,CAC5B,KAAyB,EACzB,MAAc,EACd,IAAY,EACZ,OAAe;QAEf,MAAM,MAAM,GAAW,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAExE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,8BAA8B,IAAI,sBAAsB,CAAC,CAAC;QACrF,CAAC;QAED,wEAAwE;QACxE,oEAAoE;QACpE,IAAI,MAAM,GAAG,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,oBAAoB,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,sBAAsB,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACK,aAAa,CAAC,SAAiB;QACrC,OAAO,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,MAAM,CAAC;IAC/E,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACzB,+BAA+B;IACd,cAAc,CAAiB;IAEhD;;;OAGG;IACc,gBAAgB,CAAS;IAE1C,+EAA+E;IAC9D,WAAW,CAAS;IAErC,yEAAyE;IACxD,WAAW,CAAkC;IAE9D;;;;OAIG;IACH,YAAmB,UAAiC,EAAE;QACpD,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;QAC3C,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAClE,0EAA0E;QAC1E,2DAA2D;QAC3D,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACjG,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACI,GAAG,CAAC,IAAuB;QAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,kBAAkB,EAAE,cAAc,gBAAgB,KAAK,CAAC,CAAC;QAC3F,CAAC;QAED,IAAI,MAAuB,CAAC;QAE5B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAW,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/E,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,UAAU,GAAW,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAE7E,yEAAyE;QACzE,wDAAwD;QACxD,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QACrD,CAAC;QAED,sEAAsE;QACtE,qCAAqC;QACrC,MAAM,WAAW,GAAoC,IAAI,CAAC,eAAe,EAAE,CAAC;QAE5E,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACvD,CAAC;QAED,sEAAsE;QACtE,kEAAkE;QAClE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,aAAa,CACvB,MAAM,EACN,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,EAC1C,4BAA4B,EAC5B,KAAK,CACN,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC;IAED;;;;;;;;OAQG;IACK,aAAa,CACnB,MAAuB,EACvB,UAAkB,EAClB,aAAqB,EACrB,kBAA2B;QAE3B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACnE,OAAO,IAAI,CAAC,IAAI,CAAC,0BAA0B,aAAa,IAAI,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,aAAa,GAA8B,SAAS,CAAC;QAEzD,IAAI,kBAAkB,EAAE,CAAC;YACvB,MAAM,IAAI,GAAsB,IAAI,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,CAAC;YAEpF,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,oBAAoB,uBAAuB,KAAK,IAAI,CAAC,MAAM,MAAM,CAAC,CAAC;YACtF,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC7B,aAAa,GAAG,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvF,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAiB,IAAI,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;QAChG,MAAM,MAAM,GAAiB,MAAM,CAAC,IAAI,EAAE,CAAC;QAE3C,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,aAAa,mBAAmB,uBAAuB,mCAAmC,CAAC,CAAC;QACpH,CAAC;QAED,wEAAwE;QACxE,4EAA4E;QAC5E,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,IAAI,CACd,qBAAqB;gBACrB,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,UAA0B,EAAU,EAAE,CAChE,OAAO,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM,KAAK,CAClD,CAAC,IAAI,CAAC,EAAE,CAAC;gBACV,qDAAqD,CACtD,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,uEAAuE;YACvE,MAAM,KAAK,GAAsB,kBAAkB,CAAC,eAAe,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAE7F,OAAO,IAAI,CAAC,IAAI,CACd,oCAAoC,aAAa,IAAI;gBACrD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzD,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mFAAmF,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9G,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAiB,IAAI,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAuB,IAAI,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE3E,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,UAAU,GAAqB,IAAI,gBAAgB,CAAC,YAAY,CAAC,CAAC;YACxE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAClG,CAAC;QAED,MAAM,MAAM,GAAW,QAAQ,CAAC,gBAAgB,CAC9C,YAAY,EACZ,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,gBAAgB,CACxB,CAAC;QACF,MAAM,SAAS,GAAY,IAAI,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;QAElE,yEAAyE;QACzE,qDAAqD;QACrD,OAAO;YACL,MAAM;YACN,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,YAAY;SAC5D,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;OAWG;IACK,OAAO,CAAC,WAAmB,EAAE,oBAA4B;QAC/D,MAAM,WAAW,GAAW,IAAI,CAAC,WAAW,CAAC;QAC7C,MAAM,OAAO,GAAsB,uBAAuB,CAAC,MAAM,CAC/D,CAAC,IAAY,EAAW,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAChE,CAAC;QAEF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,IAAI,CAAC,wDAAwD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnG,CAAC;QAED,MAAM,OAAO,GAAY,UAAU,CAAC,WAAW,CAAC,CAAC;QACjD,IAAI,WAAW,GAAY,KAAK,CAAC;QACjC,IAAI,OAAO,GAAY,IAAI,CAAC;QAE5B,IAAI,CAAC;YACH,WAAW,GAAG,OAAO,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7D,OAAO,GAAG,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,IAAI,CACd,uBAAuB,oBAAoB,KAAK,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,gCAAgC,CACpH,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,oBAAoB,mCAAmC,CAAC,CAAC;QACjF,CAAC;QAED,mEAAmE;QACnE,yEAAyE;QACzE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,IAAI,CACd,KAAK,oBAAoB,qCAAqC;gBAC9D,yEAAyE;gBACzE,0EAA0E;gBAC1E,8BAA8B,CAC/B,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAqB,iBAAiB,CAAC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAE/G,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,IAAI,CAAC,yBAAyB,oBAAoB,KAAK,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC;QAC5F,CAAC;QAED,MAAM,UAAU,GAAsB,IAAI,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACnF,MAAM,aAAa,GAAsB,UAAU,CAAC,IAAI,EAAE,CAAC;QAE3D,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACxE,OAAO,IAAI,CAAC,IAAI,CACd,oBAAoB,uBAAuB,KAAK,aAAa,CAAC,MAAM,gCAAgC,CACrG,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE5C,KAAK,MAAM,IAAI,IAAI,uBAAuB,EAAE,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YAClH,CAAC;QACH,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,MAAM,GAAW,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC3D,MAAM,cAAc,GAAuB,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAEhG,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC,IAAI,CACd,0CAA0C,MAAM,2BAA2B;oBAC3E,sBAAsB,cAAc,aAAa,oBAAoB,+BAA+B,CACrG,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,CAAC,IAAI,CAAC,0CAA0C,MAAM,gCAAgC,CAAC,CAAC;QACrG,CAAC;QAED,IAAI,UAAU,GAAW,KAAK,oBAAoB,kCAAkC,uBAAuB,qBAAqB,CAAC;QAEjI,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,OAAO;oBAC/D,CAAC,CAAC,WAAW,SAAS,CAAC,OAAO,OAAO,uBAAuB,uCAAuC;oBACnG,CAAC,CAAC,KAAK,uBAAuB,yBAAyB,SAAS,CAAC,OAAO,MAAM,CAAC;YACnF,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC,IAAI,CACd,oCAAoC,oBAAoB,yBAAyB;oBACjF,GAAG,uBAAuB,KAAK,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM;oBACxE,sBAAsB,uBAAuB,cAAc,SAAS,CAAC,OAAO,IAAI,CACjF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,gEAAgE;QAChE,OAAO,IAAI,CAAC,OAAO,CACjB,qBAAqB,CACnB,0CAA0C,oBAAoB,MAAM;YACpE,gBAAgB,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,IAAI;YAC3D,gCAAgC,IAAI,CAAC,oBAAoB,EAAE,UAAU,EAAE,wBAAwB,CAAC,IAAI;YACpG,kFAAkF;YAClF,GAAG,UAAU,IAAI,CAClB,CACF,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACK,yBAAyB,CAAC,WAAmB,EAAE,OAAgB;QACrE,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtD,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,KAAK,MAAM,IAAI,IAAI,uBAAuB,EAAE,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,eAAe;QACrB,sEAAsE;QACtE,4BAA4B;QAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IACjF,CAAC;IAED;;;;;;;;;;;;OAYG;IACK,aAAa,CACnB,QAA6B,EAC7B,IAAuB,EACvB,MAAuB;QAEvB,yEAAyE;QACzE,yEAAyE;QACzE,MAAM,MAAM,GAAsB;YAChC,GAAG,0BAA0B;YAC7B,GAAG,QAAQ,CAAC,MAAM;YAClB,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,cAAc,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjF,CAAC;QAEF,MAAM,OAAO,GAAsB,IAAI,UAAU,CAC/C,QAAQ,CAAC,UAAU,EACnB,MAAM,EACN,IAAI,CAAC,gBAAgB,CACtB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEZ,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACjE,CAAC;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,wEAAwE;QACxE,yEAAyE;QACzE,QAAQ;QACR,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACzF,CAAC;QAED,0EAA0E;QAC1E,uEAAuE;QACvE,kEAAkE;QAClE,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,IAAI,OAAO,CAAC,QAAQ,KAAK,sBAAsB,EAAE,CAAC;YACzE,OAAO,IAAI,CAAC,IAAI,CACd,qEAAqE,OAAO,CAAC,MAAM,EAAE,CACtF,CAAC;QACJ,CAAC;QAED,wEAAwE;QACxE,0CAA0C;QAC1C,OAAO,OAAO,CAAC,MAAM,KAAK,EAAE;YAC1B,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;YAC1E,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC/E,CAAC;IAED;;;;;;;;;OASG;IACK,gBAAgB,CAAC,OAAqB,EAAE,MAAyB;QACvE,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,OAAO,CACL,kCAAkC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ;gBAClE,sEAAsE,CACvE,CAAC;QACJ,CAAC;QAED,OAAO,oCAAoC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;IACzE,CAAC;IAED;;;;;OAKG;IACK,OAAO,CAAC,MAAc;QAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC9D,CAAC;IAED;;;;;OAKG;IACK,IAAI,CAAC,MAAc;QACzB,uEAAuE;QACvE,8DAA8D;QAC9D,OAAO,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IACjG,CAAC;IAED;;;;OAIG;IACK,kBAAkB;QACxB,MAAM,YAAY,GAAW,YAAY,CACvC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EACtC,MAAM,CACP,CAAC;QACF,MAAM,QAAQ,GAAoB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAoB,CAAC;QAC9E,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;IAED;;;;;OAKG;IACK,mBAAmB,CAAC,YAA0B;QACpD,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;YAC3C,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBAClD,IAAI,UAAU,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBACpC,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,YAAY,CAAC,WAAW,CAAC,IAAI,CAClC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAChD,CAAC;IACJ,CAAC;CACF"}