@conformetry/languages 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { Injectable as e, Module as t } from "@nestjs/common";
2
- import { ConfigurationModule as n, ConfigurationService as r } from "@conformetry/configuration";
3
- import i from "node:fs";
4
- import a from "node:path";
5
- import { parse as o } from "jsonc-parser";
6
- import { toString as s } from "mdast-util-to-string";
7
- import { remark as c } from "remark";
8
- import l from "remark-gfm";
9
- import { spawnSync as ee } from "node:child_process";
10
- import { fileURLToPath as te } from "node:url";
11
- import { ScriptKind as u, ScriptTarget as ne, SyntaxKind as d, createSourceFile as re, forEachChild as ie, getLeadingCommentRanges as ae, isBigIntLiteral as f, isCallExpression as p, isDecorator as m, isExportDeclaration as oe, isExpressionStatement as se, isIdentifier as h, isImportDeclaration as ce, isNoSubstitutionTemplateLiteral as le, isNumericLiteral as g, isPrivateIdentifier as ue, isPropertyAccessExpression as de, isStringLiteral as _ } from "typescript";
2
+ import { ConfigurationModule as n, ConfigurationService as r, capturePlaceholderValues as i } from "@conformetry/configuration";
3
+ import a from "node:fs";
4
+ import o from "node:path";
5
+ import { parse as s } from "jsonc-parser";
6
+ import { toString as c } from "mdast-util-to-string";
7
+ import { remark as l } from "remark";
8
+ import ee from "remark-gfm";
9
+ import { spawnSync as te } from "node:child_process";
10
+ import { fileURLToPath as ne } from "node:url";
11
+ import { ScriptKind as u, ScriptTarget as re, SyntaxKind as d, createSourceFile as ie, forEachChild as ae, getLeadingCommentRanges as f, isBigIntLiteral as p, isCallExpression as m, isDecorator as h, isExportDeclaration as oe, isExpressionStatement as se, isIdentifier as g, isImportDeclaration as ce, isNoSubstitutionTemplateLiteral as le, isNumericLiteral as _, isPrivateIdentifier as ue, isPropertyAccessExpression as de, isStringLiteral as v } from "typescript";
12
12
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/differences/differences.constants.ts
13
13
  var fe = [
14
14
  "javascript",
@@ -17,21 +17,22 @@ var fe = [
17
17
  "python",
18
18
  "text",
19
19
  "typescript"
20
- ], v = [
20
+ ], y = [
21
21
  "code",
22
22
  "comment",
23
23
  "directory",
24
24
  "file",
25
- "instance"
25
+ "instance",
26
+ "placeholder"
26
27
  ];
27
28
  //#endregion
28
29
  //#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorateMetadata.js
29
- function y(e, t) {
30
+ function b(e, t) {
30
31
  if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
31
32
  }
32
33
  //#endregion
33
34
  //#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorate.js
34
- function b(e, t, n, r) {
35
+ function x(e, t, n, r) {
35
36
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
36
37
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
37
38
  else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
@@ -39,7 +40,7 @@ function b(e, t, n, r) {
39
40
  }
40
41
  //#endregion
41
42
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/differences/differences.service.ts
42
- var x = class {
43
+ var S = class {
43
44
  constructor() {}
44
45
  buildMissingDirectoryDifference(e) {
45
46
  return {
@@ -56,62 +57,62 @@ var x = class {
56
57
  };
57
58
  }
58
59
  resolveDifferenceType(e) {
59
- return v.find((t) => t === e) ?? "code";
60
+ return y.find((t) => t === e) ?? "code";
60
61
  }
61
62
  resolveErrorLanguage(e) {
62
63
  return fe.find((t) => t === e);
63
64
  }
64
65
  };
65
- x = b([e(), y("design:paramtypes", [])], x);
66
+ S = x([e(), b("design:paramtypes", [])], S);
66
67
  //#endregion
67
68
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/differences/differences.module.ts
68
- var S = class {};
69
- S = b([t({
69
+ var C = class {};
70
+ C = x([t({
70
71
  controllers: [],
71
- exports: [x],
72
+ exports: [S],
72
73
  imports: [],
73
- providers: [x]
74
- })], S);
74
+ providers: [S]
75
+ })], C);
75
76
  //#endregion
76
77
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/files/files.service.ts
77
- var C = class {
78
+ var w = class {
78
79
  configurationService;
79
80
  errorsService;
80
81
  constructor(e, t) {
81
82
  this.configurationService = e, this.errorsService = t;
82
83
  }
83
84
  buildMissingDifference(e) {
84
- let t = a.dirname(e.instanceFilePath);
85
- return i.existsSync(t) ? {
85
+ let t = o.dirname(e.instanceFilePath);
86
+ return a.existsSync(t) ? {
86
87
  ...this.errorsService.buildMissingFileDifference(e),
87
88
  weight: 1
88
89
  } : {
89
90
  ...this.errorsService.buildMissingDirectoryDifference({
90
91
  instanceDirectoryPath: t,
91
- templateDirectoryPath: a.dirname(e.templateFilePath)
92
+ templateDirectoryPath: o.dirname(e.templateFilePath)
92
93
  }),
93
94
  weight: e.expectedFileCount
94
95
  };
95
96
  }
96
97
  countExpectedFiles(e) {
97
- return e.expectedFiles.filter((t) => a.dirname(t.instanceFilePath) === e.parentDirectoryPath).length;
98
+ return e.expectedFiles.filter((t) => o.dirname(t.instanceFilePath) === e.parentDirectoryPath).length;
98
99
  }
99
100
  checkInstanceFiles(e) {
100
101
  let t = this.configurationService.resolveInstanceFiles(e.instances), n = /* @__PURE__ */ new Set(), r = [];
101
102
  for (let e of t) {
102
- if (i.existsSync(e.instanceFilePath)) continue;
103
- let o = a.dirname(e.instanceFilePath);
104
- if (n.has(o)) continue;
103
+ if (a.existsSync(e.instanceFilePath)) continue;
104
+ let i = o.dirname(e.instanceFilePath);
105
+ if (n.has(i)) continue;
105
106
  let s = this.buildMissingDifference({
106
107
  expectedFileCount: this.countExpectedFiles({
107
108
  expectedFiles: t,
108
- parentDirectoryPath: o
109
+ parentDirectoryPath: i
109
110
  }),
110
111
  ...e
111
112
  });
112
- s.differenceType === "directory" && n.add(o), r.push({
113
+ s.differenceType === "directory" && n.add(i), r.push({
113
114
  differences: [s],
114
- filename: a.basename(e.instanceFilePath),
115
+ filename: o.basename(e.instanceFilePath),
115
116
  instanceFilePath: e.instanceFilePath,
116
117
  templateFilePath: e.templateFilePath,
117
118
  totalWeight: s.weight
@@ -123,19 +124,19 @@ var C = class {
123
124
  };
124
125
  }
125
126
  };
126
- C = b([e(), y("design:paramtypes", [r === void 0 ? Object : r, x === void 0 ? Object : x])], C);
127
+ w = x([e(), b("design:paramtypes", [r === void 0 ? Object : r, S === void 0 ? Object : S])], w);
127
128
  //#endregion
128
129
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/files/files.module.ts
129
- var w = class {};
130
- w = b([t({
130
+ var T = class {};
131
+ T = x([t({
131
132
  controllers: [],
132
- exports: [C],
133
- imports: [n, S],
134
- providers: [C]
135
- })], w);
133
+ exports: [w],
134
+ imports: [n, C],
135
+ providers: [w]
136
+ })], T);
136
137
  //#endregion
137
138
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/scoring/scoring.constants.ts
138
- var T = 1, E = 1, pe = 1, D = class {
139
+ var E = 1, pe = 1, me = 1, D = class {
139
140
  constructor() {}
140
141
  calculateScore(e) {
141
142
  if (e.totalWeight <= 0) return 1;
@@ -146,7 +147,7 @@ var T = 1, E = 1, pe = 1, D = class {
146
147
  return e.reduce((e, t) => e + (t.weight ?? 1), 0);
147
148
  }
148
149
  };
149
- D = b([e(), y("design:paramtypes", [])], D);
150
+ D = x([e(), b("design:paramtypes", [])], D);
150
151
  //#endregion
151
152
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/json/json-comparison.service.ts
152
153
  var O = class {
@@ -167,8 +168,18 @@ var O = class {
167
168
  weight: e.weight
168
169
  };
169
170
  }
171
+ captureString(e) {
172
+ if (typeof e.templateValue == "string" && typeof e.instanceValue == "string") return i({
173
+ instanceText: e.instanceValue,
174
+ templateText: e.templateValue
175
+ });
176
+ }
170
177
  combine(e) {
171
178
  return e.reduce((e, t) => ({
179
+ captures: {
180
+ ...t.captures,
181
+ ...e.captures
182
+ },
172
183
  differences: [...e.differences, ...t.differences],
173
184
  totalWeight: e.totalWeight + t.totalWeight
174
185
  }), {
@@ -178,20 +189,28 @@ var O = class {
178
189
  }
179
190
  compareArrayItem(e) {
180
191
  let t = this.formatPath(e.pathSegments), n = this.countNodes(e.templateItem);
181
- return this.isJsonPrimitive(e.templateItem) ? e.instanceArray.includes(e.templateItem) ? {
182
- differences: [],
183
- totalWeight: n
184
- } : {
185
- differences: [this.buildError({
186
- expected: JSON.stringify(e.templateItem),
187
- fix: `Add ${JSON.stringify(e.templateItem)} to the array at "${t}".`,
188
- language: e.language,
189
- message: `Missing required array value ${JSON.stringify(e.templateItem)} at "${t}"`,
190
- pathValue: t,
191
- weight: n
192
- })],
193
- totalWeight: n
194
- } : e.instanceArray.length === 0 ? {
192
+ if (this.isJsonPrimitive(e.templateItem)) {
193
+ let { templateItem: r } = e, i = e.instanceArray.includes(r) ? {} : e.instanceArray.map((e) => this.captureString({
194
+ instanceValue: e,
195
+ templateValue: r
196
+ })).find((e) => e !== void 0);
197
+ return i === void 0 ? {
198
+ differences: [this.buildError({
199
+ expected: JSON.stringify(e.templateItem),
200
+ fix: `Add ${JSON.stringify(e.templateItem)} to the array at "${t}".`,
201
+ language: e.language,
202
+ message: `Missing required array value ${JSON.stringify(e.templateItem)} at "${t}"`,
203
+ pathValue: t,
204
+ weight: n
205
+ })],
206
+ totalWeight: n
207
+ } : {
208
+ captures: i,
209
+ differences: [],
210
+ totalWeight: n
211
+ };
212
+ }
213
+ return e.instanceArray.length === 0 ? {
195
214
  differences: [this.buildError({
196
215
  fix: `Add the required entry to the array at "${t}".`,
197
216
  language: e.language,
@@ -273,37 +292,38 @@ var O = class {
273
292
  pathSegments: t,
274
293
  templateObject: e.templateValue
275
294
  }));
276
- let n = this.countNodes(e.templateValue);
277
- if (e.templateValue === e.instanceValue) return {
295
+ let n = this.countNodes(e.templateValue), r = e.templateValue === e.instanceValue ? {} : this.captureString(e);
296
+ if (r !== void 0) return {
297
+ captures: r,
278
298
  differences: [],
279
299
  totalWeight: n
280
300
  };
281
- let r = this.formatPath(t);
301
+ let i = this.formatPath(t);
282
302
  return {
283
303
  differences: [this.buildError({
284
304
  actual: JSON.stringify(e.instanceValue),
285
305
  expected: JSON.stringify(e.templateValue),
286
- fix: `Set "${r}" to ${JSON.stringify(e.templateValue)}.`,
306
+ fix: `Set "${i}" to ${JSON.stringify(e.templateValue)}.`,
287
307
  language: e.language,
288
- message: `Expected ${JSON.stringify(e.templateValue)} at "${r}" but found ${JSON.stringify(e.instanceValue)}`,
289
- pathValue: r,
308
+ message: `Expected ${JSON.stringify(e.templateValue)} at "${i}" but found ${JSON.stringify(e.instanceValue)}`,
309
+ pathValue: i,
290
310
  weight: n
291
311
  })],
292
312
  totalWeight: n
293
313
  };
294
314
  }
295
315
  };
296
- O = b([e(), y("design:paramtypes", [D === void 0 ? Object : D])], O);
316
+ O = x([e(), b("design:paramtypes", [D === void 0 ? Object : D])], O);
297
317
  //#endregion
298
318
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/scoring/scoring.module.ts
299
319
  var k = class {};
300
- k = b([t({
320
+ k = x([t({
301
321
  controllers: [],
302
322
  exports: [D],
303
323
  imports: [],
304
324
  providers: [D]
305
325
  })], k);
306
- var me = {
326
+ var he = {
307
327
  description: "Checks JSON and JSONC structural conformance",
308
328
  fileExtensions: [".json", ".jsonc"],
309
329
  name: "json"
@@ -312,20 +332,20 @@ var me = {
312
332
  constructor(e) {
313
333
  this.jsonComparisonService = e;
314
334
  }
315
- descriptor = me;
335
+ descriptor = he;
316
336
  validateDocument(e) {
317
337
  return this.jsonComparisonService.compare({
318
- instanceValue: o(e.instance),
338
+ instanceValue: s(e.instance),
319
339
  language: "json",
320
- templateValue: o(e.renderedTemplate)
340
+ templateValue: s(e.renderedTemplate)
321
341
  });
322
342
  }
323
343
  };
324
- A = b([e(), y("design:paramtypes", [O === void 0 ? Object : O])], A);
344
+ A = x([e(), b("design:paramtypes", [O === void 0 ? Object : O])], A);
325
345
  //#endregion
326
346
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/json/json.module.ts
327
347
  var j = class {};
328
- j = b([t({
348
+ j = x([t({
329
349
  controllers: [],
330
350
  exports: [O, A],
331
351
  imports: [k],
@@ -368,14 +388,14 @@ var M = class {
368
388
  };
369
389
  }
370
390
  parseNotebook(e) {
371
- let t = o(e);
391
+ let t = s(e);
372
392
  if (typeof t != "object" || !t) return { cells: [] };
373
393
  let n = t.cells;
374
394
  return Array.isArray(n) ? { cells: n.filter((e) => typeof e == "object" && !!e) } : { cells: [] };
375
395
  }
376
396
  };
377
- M = b([e(), y("design:paramtypes", [])], M);
378
- var he = {
397
+ M = x([e(), b("design:paramtypes", [])], M);
398
+ var ge = {
379
399
  description: "Checks markdown structural conformance using mdast",
380
400
  fileExtensions: [".md"],
381
401
  name: "markdown"
@@ -410,6 +430,15 @@ var he = {
410
430
  sameField(e, t) {
411
431
  return (e ?? "") === (t ?? "");
412
432
  }
433
+ capture(e) {
434
+ let { instanceNode: t, templateNode: n } = e;
435
+ if (n.type !== t.type) return;
436
+ let r = this.matchersByType[n.type];
437
+ return (r === void 0 ? this.readText(n) === this.readText(t) : r(n, t)) ? {} : n.depth === t.depth ? i({
438
+ instanceText: this.readText(t),
439
+ templateText: this.readText(n)
440
+ }) : void 0;
441
+ }
413
442
  countSubtree(e) {
414
443
  return P.has(e.type) ? 0 : this.readChildren(e).reduce((e, t) => e + this.countSubtree(t), 1);
415
444
  }
@@ -417,19 +446,16 @@ var he = {
417
446
  return e.filter((e) => typeof e == "object" && !!e && "type" in e);
418
447
  }
419
448
  matches(e) {
420
- let { instanceNode: t, templateNode: n } = e;
421
- if (n.type !== t.type) return !1;
422
- let r = this.matchersByType[n.type];
423
- return r === void 0 ? this.readText(n) === this.readText(t) : r(n, t);
449
+ return this.capture(e) !== void 0;
424
450
  }
425
451
  readChildren(e) {
426
452
  return e.children ?? [];
427
453
  }
428
454
  readText(e) {
429
- return s(e);
455
+ return c(e);
430
456
  }
431
457
  };
432
- F = b([e(), y("design:paramtypes", [])], F);
458
+ F = x([e(), b("design:paramtypes", [])], F);
433
459
  //#endregion
434
460
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/markdown/markdown-tree.service.ts
435
461
  var I = class {
@@ -447,6 +473,13 @@ var I = class {
447
473
  weight: this.markdownNodesService.countSubtree(e.templateChild)
448
474
  };
449
475
  }
476
+ captureFirst(e) {
477
+ let [t] = e.candidates;
478
+ return t === void 0 ? {} : this.markdownNodesService.capture({
479
+ instanceNode: t,
480
+ templateNode: e.templateChild
481
+ }) ?? {};
482
+ }
450
483
  compareContainer(e) {
451
484
  let t = this.findCandidates(e);
452
485
  if (t.length === 0) {
@@ -459,18 +492,29 @@ var I = class {
459
492
  }
460
493
  let n = this.markdownNodesService.readChildren(e.templateChild);
461
494
  return n.length === 0 ? {
495
+ captures: this.captureFirst({
496
+ ...e,
497
+ candidates: t
498
+ }),
462
499
  differences: [],
463
500
  lastMatchedNode: t.at(-1),
464
501
  totalWeight: 1
465
- } : t.map((e) => {
466
- let t = this.compareChildren({
467
- instanceChildren: this.markdownNodesService.readChildren(e),
502
+ } : t.map((t) => {
503
+ let r = this.compareChildren({
504
+ instanceChildren: this.markdownNodesService.readChildren(t),
468
505
  templateChildren: n
469
506
  });
470
507
  return {
471
- differences: t.differences,
472
- lastMatchedNode: e,
473
- totalWeight: t.totalWeight + 1
508
+ captures: {
509
+ ...r.captures,
510
+ ...this.captureFirst({
511
+ ...e,
512
+ candidates: [t]
513
+ })
514
+ },
515
+ differences: r.differences,
516
+ lastMatchedNode: t,
517
+ totalWeight: r.totalWeight + 1
474
518
  };
475
519
  }).reduce((e, t) => this.scoringService.sumWeights(t.differences) < this.scoringService.sumWeights(e.differences) ? t : e);
476
520
  }
@@ -481,39 +525,47 @@ var I = class {
481
525
  lastMatchedNode: e.lastMatchedNode,
482
526
  totalWeight: n
483
527
  } : {
528
+ captures: this.captureFirst({
529
+ ...e,
530
+ candidates: t
531
+ }),
484
532
  differences: [],
485
533
  lastMatchedNode: t.at(-1),
486
534
  totalWeight: n
487
535
  };
488
536
  }
489
537
  findCandidates(e) {
490
- return e.instanceChildren.filter((t) => this.markdownNodesService.matches({
538
+ return e.instanceChildren.filter((t) => this.markdownNodesService.capture({
491
539
  instanceNode: t,
492
540
  templateNode: e.templateChild
493
- }));
541
+ }) !== void 0);
494
542
  }
495
543
  compareChildren(e) {
496
- let t = [], n, r = 0;
497
- for (let i of e.templateChildren) {
498
- if (P.has(i.type)) continue;
499
- let a = N.has(i.type) ? this.compareContainer({
544
+ let t = {}, n = [], r, i = 0;
545
+ for (let a of e.templateChildren) {
546
+ if (P.has(a.type)) continue;
547
+ let o = N.has(a.type) ? this.compareContainer({
500
548
  instanceChildren: e.instanceChildren,
501
- lastMatchedNode: n,
502
- templateChild: i
549
+ lastMatchedNode: r,
550
+ templateChild: a
503
551
  }) : this.compareLeaf({
504
552
  instanceChildren: e.instanceChildren,
505
- lastMatchedNode: n,
506
- templateChild: i
553
+ lastMatchedNode: r,
554
+ templateChild: a
507
555
  });
508
- t.push(...a.differences), n = a.lastMatchedNode, r += a.totalWeight;
556
+ t = {
557
+ ...o.captures,
558
+ ...t
559
+ }, n.push(...o.differences), r = o.lastMatchedNode, i += o.totalWeight;
509
560
  }
510
561
  return {
511
- differences: t,
512
- totalWeight: r
562
+ captures: t,
563
+ differences: n,
564
+ totalWeight: i
513
565
  };
514
566
  }
515
567
  };
516
- I = b([e(), y("design:paramtypes", [F === void 0 ? Object : F, D === void 0 ? Object : D])], I);
568
+ I = x([e(), b("design:paramtypes", [F === void 0 ? Object : F, D === void 0 ? Object : D])], I);
517
569
  //#endregion
518
570
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/markdown/markdown.service.ts
519
571
  var L = class {
@@ -522,32 +574,33 @@ var L = class {
522
574
  constructor(e, t) {
523
575
  this.markdownNodesService = e, this.markdownTreeService = t;
524
576
  }
525
- processor = c().use(l);
526
- descriptor = he;
577
+ processor = l().use(ee);
578
+ descriptor = ge;
527
579
  validateDocument(e) {
528
580
  let t = this.processor.parse(e.renderedTemplate), n = this.processor.parse(e.instance), r = this.markdownTreeService.compareChildren({
529
581
  instanceChildren: this.markdownNodesService.filterNodes(n.children),
530
582
  templateChildren: this.markdownNodesService.filterNodes(t.children)
531
- });
583
+ }), i = r.differences.map((e) => ({
584
+ differenceType: "code",
585
+ expected: e.text,
586
+ fix: `Add the ${e.nodeType} "${e.text}" to the instance file.`,
587
+ ...e.instanceLine === void 0 ? {} : { instanceLine: e.instanceLine },
588
+ language: "markdown",
589
+ message: `Missing markdown ${e.nodeType}: "${e.text}"`,
590
+ weight: e.weight
591
+ }));
532
592
  return {
533
- differences: r.differences.map((e) => ({
534
- differenceType: "code",
535
- expected: e.text,
536
- fix: `Add the ${e.nodeType} "${e.text}" to the instance file.`,
537
- ...e.instanceLine === void 0 ? {} : { instanceLine: e.instanceLine },
538
- language: "markdown",
539
- message: `Missing markdown ${e.nodeType}: "${e.text}"`,
540
- weight: e.weight
541
- })),
593
+ ...r.captures === void 0 ? {} : { captures: r.captures },
594
+ differences: i,
542
595
  totalWeight: r.totalWeight
543
596
  };
544
597
  }
545
598
  };
546
- L = b([e(), y("design:paramtypes", [F === void 0 ? Object : F, I === void 0 ? Object : I])], L);
599
+ L = x([e(), b("design:paramtypes", [F === void 0 ? Object : F, I === void 0 ? Object : I])], L);
547
600
  //#endregion
548
601
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/markdown/markdown.module.ts
549
602
  var R = class {};
550
- R = b([t({
603
+ R = x([t({
551
604
  controllers: [],
552
605
  exports: [L],
553
606
  imports: [k],
@@ -557,22 +610,22 @@ R = b([t({
557
610
  I
558
611
  ]
559
612
  })], R);
560
- var ge = {
613
+ var _e = {
561
614
  description: "Checks Python structure and comments against templates",
562
615
  fileExtensions: [".py"],
563
616
  name: "python"
564
- }, z = "python3", _e = "python.bridge", ve = "Install Python 3 and ensure `python3` is on PATH; conformetry validates Python files through the interpreter's own ast module.", B = class {
617
+ }, z = "python3", ve = "python.bridge", ye = "Install Python 3 and ensure `python3` is on PATH; conformetry validates Python files through the interpreter's own ast module.", B = class {
565
618
  errorsService;
566
619
  scoringService;
567
620
  constructor(e, t) {
568
621
  this.errorsService = e, this.scoringService = t;
569
622
  }
570
- pythonRootPath = a.resolve(a.dirname(te(import.meta.url)), "..", "..");
623
+ pythonRootPath = o.resolve(o.dirname(ne(import.meta.url)), "..", "..");
571
624
  buildBridgeError(e) {
572
625
  return {
573
626
  differences: [{
574
627
  differenceType: "code",
575
- fix: ve,
628
+ fix: ye,
576
629
  language: "python",
577
630
  message: e
578
631
  }],
@@ -615,7 +668,7 @@ var ge = {
615
668
  };
616
669
  }
617
670
  validatePythonSource(e) {
618
- let t = ee(z, ["-m", _e], {
671
+ let t = te(z, ["-m", ve], {
619
672
  cwd: this.pythonRootPath,
620
673
  encoding: "utf8",
621
674
  env: {
@@ -637,7 +690,7 @@ var ge = {
637
690
  }
638
691
  }
639
692
  };
640
- B = b([e(), y("design:paramtypes", [x === void 0 ? Object : x, D === void 0 ? Object : D])], B);
693
+ B = x([e(), b("design:paramtypes", [S === void 0 ? Object : S, D === void 0 ? Object : D])], B);
641
694
  //#endregion
642
695
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/python/python.service.ts
643
696
  var V = class {
@@ -645,7 +698,7 @@ var V = class {
645
698
  constructor(e) {
646
699
  this.pythonBridgeService = e;
647
700
  }
648
- descriptor = ge;
701
+ descriptor = _e;
649
702
  validateDocument(e) {
650
703
  return this.pythonBridgeService.validatePythonSource({
651
704
  filename: e.filename,
@@ -654,21 +707,21 @@ var V = class {
654
707
  });
655
708
  }
656
709
  };
657
- V = b([e(), y("design:paramtypes", [B === void 0 ? Object : B])], V);
710
+ V = x([e(), b("design:paramtypes", [B === void 0 ? Object : B])], V);
658
711
  //#endregion
659
712
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/python/python.module.ts
660
713
  var H = class {};
661
- H = b([t({
714
+ H = x([t({
662
715
  controllers: [],
663
716
  exports: [B, V],
664
- imports: [S, k],
717
+ imports: [C, k],
665
718
  providers: [B, V]
666
719
  })], H);
667
- var ye = {
720
+ var be = {
668
721
  description: "Checks Jupyter notebook structure, markdown cells, and code cells",
669
722
  fileExtensions: [".ipynb"],
670
723
  name: "jupyter"
671
- }, be = [
724
+ }, xe = [
672
725
  "metadata",
673
726
  "nbformat",
674
727
  "nbformat_minor"
@@ -680,7 +733,7 @@ var ye = {
680
733
  constructor(e, t, n, r) {
681
734
  this.jsonComparisonService = e, this.jupyterNotebookService = t, this.markdownService = n, this.pythonBridgeService = r;
682
735
  }
683
- descriptor = ye;
736
+ descriptor = be;
684
737
  attributeToCell(e) {
685
738
  return e.differences.map((t) => ({
686
739
  ...t,
@@ -688,10 +741,10 @@ var ye = {
688
741
  }));
689
742
  }
690
743
  readEnvelope(e) {
691
- let t = o(e);
744
+ let t = s(e);
692
745
  if (typeof t != "object" || !t || Array.isArray(t)) return {};
693
746
  let n = {};
694
- for (let e of be) {
747
+ for (let e of xe) {
695
748
  let r = t[e];
696
749
  r !== void 0 && (n[e] = r);
697
750
  }
@@ -783,7 +836,7 @@ var ye = {
783
836
  };
784
837
  }
785
838
  };
786
- U = b([e(), y("design:paramtypes", [
839
+ U = x([e(), b("design:paramtypes", [
787
840
  O === void 0 ? Object : O,
788
841
  M === void 0 ? Object : M,
789
842
  L === void 0 ? Object : L,
@@ -792,7 +845,7 @@ U = b([e(), y("design:paramtypes", [
792
845
  //#endregion
793
846
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/jupyter/jupyter.module.ts
794
847
  var W = class {};
795
- W = b([t({
848
+ W = x([t({
796
849
  controllers: [],
797
850
  exports: [U],
798
851
  imports: [
@@ -802,32 +855,57 @@ W = b([t({
802
855
  ],
803
856
  providers: [M, U]
804
857
  })], W);
805
- var xe = {
858
+ var Se = {
806
859
  description: "Checks text files using duplicate-aware line conformance",
807
860
  fileExtensions: [".txt"],
808
861
  name: "text"
809
862
  }, G = class {
810
863
  constructor() {}
811
- descriptor = xe;
864
+ descriptor = Se;
865
+ captureLine(e) {
866
+ for (let [t, n] of e.remainingLines) {
867
+ let r = n === 0 ? void 0 : i({
868
+ instanceText: t,
869
+ templateText: e.line
870
+ });
871
+ if (r !== void 0) return e.remainingLines.set(t, n - 1), r;
872
+ }
873
+ }
812
874
  countLines(e) {
813
875
  let t = /* @__PURE__ */ new Map();
814
876
  for (let n of e.split("\n")) t.set(n, (t.get(n) ?? 0) + 1);
815
877
  return t;
816
878
  }
817
879
  findMissingLines(e) {
818
- let t = this.countLines(e.instance), n = [];
819
- for (let [r, i] of e.renderedTemplate.split("\n").entries()) {
820
- let e = t.get(i) ?? 0;
821
- e === 0 ? n.push({
822
- line: i,
823
- templateLine: r + 1
824
- }) : t.set(i, e - 1);
880
+ let t = this.countLines(e.instance), n = [], r = {};
881
+ for (let [i, a] of e.renderedTemplate.split("\n").entries()) {
882
+ let e = t.get(a) ?? 0;
883
+ if (e > 0) {
884
+ t.set(a, e - 1);
885
+ continue;
886
+ }
887
+ let o = this.captureLine({
888
+ line: a,
889
+ remainingLines: t
890
+ });
891
+ o === void 0 ? n.push({
892
+ line: a,
893
+ templateLine: i + 1
894
+ }) : r = {
895
+ ...o,
896
+ ...r
897
+ };
825
898
  }
826
- return n;
899
+ return {
900
+ captures: r,
901
+ missingLines: n
902
+ };
827
903
  }
828
904
  validateDocument(e) {
905
+ let { captures: t, missingLines: n } = this.findMissingLines(e);
829
906
  return {
830
- differences: this.findMissingLines(e).map((e) => ({
907
+ captures: t,
908
+ differences: n.map((e) => ({
831
909
  differenceType: "code",
832
910
  expected: e.line,
833
911
  fix: `Add the line \`${e.line}\` to the instance file.`,
@@ -839,26 +917,26 @@ var xe = {
839
917
  };
840
918
  }
841
919
  };
842
- G = b([e(), y("design:paramtypes", [])], G);
920
+ G = x([e(), b("design:paramtypes", [])], G);
843
921
  //#endregion
844
922
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/text/text.module.ts
845
923
  var K = class {};
846
- K = b([t({
924
+ K = x([t({
847
925
  controllers: [],
848
926
  exports: [G],
849
927
  imports: [],
850
928
  providers: [G]
851
929
  })], K);
852
- var Se = {
930
+ var Ce = {
853
931
  description: "Checks TypeScript AST structure and required comments",
854
932
  fileExtensions: [".ts", ".tsx"],
855
933
  name: "typescript"
856
- }, Ce = /\bTODO\b/u, q = class {
934
+ }, we = /\bTODO\b/u, q = class {
857
935
  constructor() {}
858
936
  compareComments(e) {
859
937
  let t = this.extractComments(e.instanceSourceFile), n = this.extractComments(e.templateSourceFile), r = [], i = 0;
860
938
  for (let e of n) {
861
- let n = Ce.test(e.text), a = t.slice(i).findIndex((t) => n || t.text === e.text);
939
+ let n = we.test(e.text), a = t.slice(i).findIndex((t) => n || t.text === e.text);
862
940
  if (a === -1) {
863
941
  r.push(e);
864
942
  continue;
@@ -874,7 +952,7 @@ var Se = {
874
952
  let t = /* @__PURE__ */ new Map(), n = (r) => {
875
953
  let i = r.getChildren(e);
876
954
  if (i.length === 0) {
877
- for (let n of ae(e.text, r.getFullStart()) ?? []) t.set(n.pos, {
955
+ for (let n of f(e.text, r.getFullStart()) ?? []) t.set(n.pos, {
878
956
  position: n.pos,
879
957
  text: e.text.slice(n.pos, n.end).trim()
880
958
  });
@@ -885,7 +963,7 @@ var Se = {
885
963
  return n(e), [...t.values()].toSorted((e, t) => e.position - t.position);
886
964
  }
887
965
  };
888
- q = b([e(), y("design:paramtypes", [])], q);
966
+ q = x([e(), b("design:paramtypes", [])], q);
889
967
  //#endregion
890
968
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/typescript/typescript-nodes.service.ts
891
969
  var J = class {
@@ -893,49 +971,49 @@ var J = class {
893
971
  buildDottedName(e) {
894
972
  let t = [], n = e;
895
973
  for (; de(n);) t.unshift(n.name.text), n = n.expression;
896
- return h(n) ? (t.unshift(n.text), t.join(".")) : null;
974
+ return g(n) ? (t.unshift(n.text), t.join(".")) : null;
897
975
  }
898
976
  isNode(e) {
899
977
  return typeof e == "object" && !!e && "kind" in e && typeof e.kind == "number";
900
978
  }
901
979
  readDecoratorKey(e) {
902
- return this.buildDottedName(p(e.expression) ? e.expression.expression : e.expression);
980
+ return this.buildDottedName(m(e.expression) ? e.expression.expression : e.expression);
903
981
  }
904
982
  readExportKey(e) {
905
983
  let { moduleSpecifier: t } = e;
906
- return t === void 0 || !_(t) ? null : t.text;
984
+ return t === void 0 || !v(t) ? null : t.text;
907
985
  }
908
986
  readExpressionStatementKey(e) {
909
- if (!p(e)) return null;
987
+ if (!m(e)) return null;
910
988
  let t = this.buildDottedName(e.expression);
911
989
  if (t === null) return null;
912
990
  let n = e.arguments[0], r = n === void 0 ? void 0 : this.readLiteralKey(n);
913
991
  return r === void 0 ? t : `${t}:${r}`;
914
992
  }
915
993
  readImportKey(e) {
916
- return _(e.moduleSpecifier) ? e.moduleSpecifier.text : null;
994
+ return v(e.moduleSpecifier) ? e.moduleSpecifier.text : null;
917
995
  }
918
996
  readLiteralKey(e) {
919
- if (h(e) || _(e) || g(e) || f(e) || le(e)) return e.text;
997
+ if (g(e) || v(e) || _(e) || p(e) || le(e)) return e.text;
920
998
  }
921
999
  readNamedKey(e) {
922
1000
  if (!("name" in e)) return null;
923
1001
  let t = e.name;
924
- return this.isNode(t) && (h(t) || ue(t) || _(t) || g(t)) ? t.text : null;
1002
+ return this.isNode(t) && (g(t) || ue(t) || v(t) || _(t)) ? t.text : null;
925
1003
  }
926
1004
  countSubtree(e) {
927
1005
  return this.readChildren(e).reduce((e, t) => e + this.countSubtree(t), 1);
928
1006
  }
929
1007
  readChildren(e) {
930
1008
  let t = [];
931
- return ie(e, (e) => {
1009
+ return ae(e, (e) => {
932
1010
  e.kind !== d.EndOfFileToken && t.push(e);
933
1011
  }), t;
934
1012
  }
935
1013
  readKey(e) {
936
1014
  if (ce(e)) return this.readImportKey(e);
937
1015
  if (oe(e)) return this.readExportKey(e);
938
- if (m(e)) return this.readDecoratorKey(e);
1016
+ if (h(e)) return this.readDecoratorKey(e);
939
1017
  if (se(e)) {
940
1018
  let t = this.readExpressionStatementKey(e.expression);
941
1019
  if (t !== null) return t;
@@ -946,7 +1024,7 @@ var J = class {
946
1024
  return d[e.kind];
947
1025
  }
948
1026
  };
949
- J = b([e(), y("design:paramtypes", [])], J);
1027
+ J = x([e(), b("design:paramtypes", [])], J);
950
1028
  //#endregion
951
1029
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/typescript/typescript-tree.service.ts
952
1030
  var Y = class {
@@ -965,13 +1043,35 @@ var Y = class {
965
1043
  };
966
1044
  }
967
1045
  compareBestCandidate(e) {
968
- return e.candidates.map((t) => this.compareTree({
969
- instanceNode: t,
970
- templateNode: e.templateChild
971
- })).reduce((e, t) => this.scoringService.sumWeights(t.differences) < this.scoringService.sumWeights(e.differences) ? t : e);
1046
+ return e.candidates.map((t) => {
1047
+ let n = this.compareTree({
1048
+ instanceNode: t.node,
1049
+ templateNode: e.templateChild
1050
+ });
1051
+ return {
1052
+ ...n,
1053
+ captures: {
1054
+ ...n.captures,
1055
+ ...t.captures
1056
+ }
1057
+ };
1058
+ }).reduce((e, t) => this.scoringService.sumWeights(t.differences) < this.scoringService.sumWeights(e.differences) ? t : e);
972
1059
  }
973
1060
  compareChild(e) {
974
- let t = this.typeScriptNodesService.readKey(e.templateChild), n = t === null ? e.instanceChildren.filter((t) => t.kind === e.templateChild.kind) : e.instanceChildren.filter((e) => this.typeScriptNodesService.readKey(e) === t);
1061
+ let t = this.typeScriptNodesService.readKey(e.templateChild), n = e.instanceChildren.flatMap((n) => {
1062
+ let r = t === null ? this.matchKind({
1063
+ instanceChild: n,
1064
+ templateChild: e.templateChild
1065
+ }) : this.matchKey({
1066
+ instanceChild: n,
1067
+ nodeKey: t,
1068
+ templateChild: e.templateChild
1069
+ });
1070
+ return r === void 0 ? [] : [{
1071
+ captures: r,
1072
+ node: n
1073
+ }];
1074
+ });
975
1075
  if (n.length === 0) {
976
1076
  let n = this.buildError({
977
1077
  instanceNode: e.instanceNode,
@@ -988,6 +1088,17 @@ var Y = class {
988
1088
  templateChild: e.templateChild
989
1089
  });
990
1090
  }
1091
+ matchKey(e) {
1092
+ let t = this.typeScriptNodesService.readKey(e.instanceChild);
1093
+ if (t === e.nodeKey) return {};
1094
+ if (t !== null && e.instanceChild.kind === e.templateChild.kind) return i({
1095
+ instanceText: t,
1096
+ templateText: e.nodeKey
1097
+ });
1098
+ }
1099
+ matchKind(e) {
1100
+ return e.instanceChild.kind === e.templateChild.kind ? {} : void 0;
1101
+ }
991
1102
  compareTree(e) {
992
1103
  let t = this.typeScriptNodesService.readChildren(e.instanceNode);
993
1104
  return this.typeScriptNodesService.readChildren(e.templateNode).map((n) => this.compareChild({
@@ -995,6 +1106,10 @@ var Y = class {
995
1106
  instanceNode: e.instanceNode,
996
1107
  templateChild: n
997
1108
  })).reduce((e, t) => ({
1109
+ captures: {
1110
+ ...t.captures,
1111
+ ...e.captures
1112
+ },
998
1113
  differences: [...e.differences, ...t.differences],
999
1114
  totalWeight: e.totalWeight + t.totalWeight
1000
1115
  }), {
@@ -1003,7 +1118,7 @@ var Y = class {
1003
1118
  });
1004
1119
  }
1005
1120
  };
1006
- Y = b([e(), y("design:paramtypes", [D === void 0 ? Object : D, J === void 0 ? Object : J])], Y);
1121
+ Y = x([e(), b("design:paramtypes", [D === void 0 ? Object : D, J === void 0 ? Object : J])], Y);
1007
1122
  //#endregion
1008
1123
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/typescript/typescript.service.ts
1009
1124
  var X = class {
@@ -1012,9 +1127,9 @@ var X = class {
1012
1127
  constructor(e, t) {
1013
1128
  this.typeScriptCommentsService = e, this.typeScriptTreeService = t;
1014
1129
  }
1015
- descriptor = Se;
1130
+ descriptor = Ce;
1016
1131
  parseSourceFile(e) {
1017
- return re(e.filename, e.content, ne.Latest, !0, e.filename.endsWith(".tsx") ? u.TSX : u.TS);
1132
+ return ie(e.filename, e.content, re.Latest, !0, e.filename.endsWith(".tsx") ? u.TSX : u.TS);
1018
1133
  }
1019
1134
  readLocation(e) {
1020
1135
  if (e.position === void 0 || e.position < 0) return;
@@ -1051,32 +1166,33 @@ var X = class {
1051
1166
  let t = this.typeScriptTreeService.compareTree({
1052
1167
  instanceNode: e.instanceSourceFile,
1053
1168
  templateNode: e.templateSourceFile
1169
+ }), n = t.differences.map((t) => {
1170
+ let n = t.nodeKey === void 0 ? t.kindLabel : `${t.kindLabel} "${t.nodeKey}"`, r = this.readLocation({
1171
+ position: t.instancePosition,
1172
+ sourceFile: e.instanceSourceFile
1173
+ }), i = this.readLocation({
1174
+ position: t.templatePosition,
1175
+ sourceFile: e.templateSourceFile
1176
+ });
1177
+ return {
1178
+ differenceType: "code",
1179
+ fix: `Add the missing ${n} to the instance file. See the template for the expected structure.`,
1180
+ ...r === void 0 ? {} : {
1181
+ instanceColumn: r.column,
1182
+ instanceLine: r.line
1183
+ },
1184
+ language: "typescript",
1185
+ message: `Missing ${n}`,
1186
+ ...i === void 0 ? {} : {
1187
+ templateColumn: i.column,
1188
+ templateLine: i.line
1189
+ },
1190
+ weight: t.weight
1191
+ };
1054
1192
  });
1055
1193
  return {
1056
- differences: t.differences.map((t) => {
1057
- let n = t.nodeKey === void 0 ? t.kindLabel : `${t.kindLabel} "${t.nodeKey}"`, r = this.readLocation({
1058
- position: t.instancePosition,
1059
- sourceFile: e.instanceSourceFile
1060
- }), i = this.readLocation({
1061
- position: t.templatePosition,
1062
- sourceFile: e.templateSourceFile
1063
- });
1064
- return {
1065
- differenceType: "code",
1066
- fix: `Add the missing ${n} to the instance file. See the template for the expected structure.`,
1067
- ...r === void 0 ? {} : {
1068
- instanceColumn: r.column,
1069
- instanceLine: r.line
1070
- },
1071
- language: "typescript",
1072
- message: `Missing ${n}`,
1073
- ...i === void 0 ? {} : {
1074
- templateColumn: i.column,
1075
- templateLine: i.line
1076
- },
1077
- weight: t.weight
1078
- };
1079
- }),
1194
+ ...t.captures === void 0 ? {} : { captures: t.captures },
1195
+ differences: n,
1080
1196
  totalWeight: t.totalWeight
1081
1197
  };
1082
1198
  }
@@ -1092,16 +1208,17 @@ var X = class {
1092
1208
  })
1093
1209
  }, n = this.validateStructure(t), r = this.validateComments(t);
1094
1210
  return {
1211
+ ...n.captures === void 0 ? {} : { captures: n.captures },
1095
1212
  differences: [...n.differences, ...r.differences],
1096
1213
  totalWeight: n.totalWeight + r.totalWeight
1097
1214
  };
1098
1215
  }
1099
1216
  };
1100
- X = b([e(), y("design:paramtypes", [q === void 0 ? Object : q, Y === void 0 ? Object : Y])], X);
1217
+ X = x([e(), b("design:paramtypes", [q === void 0 ? Object : q, Y === void 0 ? Object : Y])], X);
1101
1218
  //#endregion
1102
1219
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/typescript/typescript.module.ts
1103
1220
  var Z = class {};
1104
- Z = b([t({
1221
+ Z = x([t({
1105
1222
  controllers: [],
1106
1223
  exports: [X],
1107
1224
  imports: [k],
@@ -1148,7 +1265,7 @@ var Q = class {
1148
1265
  return r.length === 0 ? t : [...t, this.widenFallback(r)];
1149
1266
  }
1150
1267
  };
1151
- Q = b([e(), y("design:paramtypes", [
1268
+ Q = x([e(), b("design:paramtypes", [
1152
1269
  A === void 0 ? Object : A,
1153
1270
  U === void 0 ? Object : U,
1154
1271
  L === void 0 ? Object : L,
@@ -1159,7 +1276,7 @@ Q = b([e(), y("design:paramtypes", [
1159
1276
  //#endregion
1160
1277
  //#region packages/ic-suite/conformetry/conformetry-languages/src/modules/languages/languages.module.ts
1161
1278
  var $ = class {};
1162
- $ = b([t({
1279
+ $ = x([t({
1163
1280
  controllers: [],
1164
1281
  exports: [
1165
1282
  j,
@@ -1181,4 +1298,4 @@ $ = b([t({
1181
1298
  providers: [Q]
1182
1299
  })], $);
1183
1300
  //#endregion
1184
- export { T as DEFAULT_ERROR_WEIGHT, S as DifferencesModule, x as DifferencesService, E as EMPTY_TEMPLATE_SCORE, w as FilesModule, C as FilesService, O as JsonComparisonService, j as JsonModule, A as JsonService, W as JupyterModule, M as JupyterNotebookService, U as JupyterService, $ as LanguagesModule, Q as LanguagesService, R as MarkdownModule, F as MarkdownNodesService, L as MarkdownService, I as MarkdownTreeService, pe as PERFECT_SCORE, B as PythonBridgeService, H as PythonModule, V as PythonService, k as ScoringModule, D as ScoringService, K as TextModule, G as TextService, q as TypescriptCommentsService, Z as TypescriptModule, J as TypescriptNodesService, X as TypescriptService, Y as TypescriptTreeService };
1301
+ export { E as DEFAULT_ERROR_WEIGHT, C as DifferencesModule, S as DifferencesService, pe as EMPTY_TEMPLATE_SCORE, T as FilesModule, w as FilesService, O as JsonComparisonService, j as JsonModule, A as JsonService, W as JupyterModule, M as JupyterNotebookService, U as JupyterService, $ as LanguagesModule, Q as LanguagesService, R as MarkdownModule, F as MarkdownNodesService, L as MarkdownService, I as MarkdownTreeService, me as PERFECT_SCORE, B as PythonBridgeService, H as PythonModule, V as PythonService, k as ScoringModule, D as ScoringService, K as TextModule, G as TextService, q as TypescriptCommentsService, Z as TypescriptModule, J as TypescriptNodesService, X as TypescriptService, Y as TypescriptTreeService };