@ttsc/evidence 0.30.4 → 0.31.1

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 (66) hide show
  1. package/README.md +14 -6
  2. package/lib/index.d.ts +2 -3
  3. package/lib/index.js +2 -3
  4. package/lib/internal/canonicalDigest.js +12 -6
  5. package/lib/internal/loadPrismaModels.js +52 -7
  6. package/lib/internal/loadSwaggerOperations.js +253 -59
  7. package/lib/internal/normalizeSwaggerDocument.js +320 -2
  8. package/lib/structures/ITtscEvidenceDocumentedConfig.d.ts +16 -8
  9. package/lib/structures/ITtscEvidenceGraphClaim.d.ts +6 -0
  10. package/lib/structures/ITtscEvidenceGraphClaimBase.d.ts +8 -2
  11. package/lib/structures/ITtscEvidenceGraphConfig.d.ts +6 -0
  12. package/lib/structures/ITtscEvidenceGraphMarkdownClaim.d.ts +7 -1
  13. package/lib/structures/ITtscEvidenceGraphMarkdownReference.d.ts +7 -1
  14. package/lib/structures/ITtscEvidenceGraphPrismaClaim.d.ts +7 -1
  15. package/lib/structures/ITtscEvidenceGraphPrismaReference.d.ts +7 -1
  16. package/lib/structures/ITtscEvidenceGraphReference.d.ts +10 -4
  17. package/lib/structures/ITtscEvidenceGraphReferenceBase.d.ts +6 -0
  18. package/lib/structures/ITtscEvidenceGraphSwaggerReference.d.ts +6 -0
  19. package/lib/structures/ITtscEvidenceGraphTypeScriptClaim.d.ts +7 -1
  20. package/lib/structures/ITtscEvidenceGraphTypeScriptReference.d.ts +11 -3
  21. package/lib/structures/ITtscEvidenceRules.d.ts +93 -0
  22. package/lib/structures/TtscEvidenceGraphMarkdownSymbol.d.ts +39 -0
  23. package/lib/{typings → structures}/TtscEvidenceGraphPrismaSymbol.d.ts +6 -0
  24. package/lib/{typings → structures}/TtscEvidenceGraphTypeScriptSymbol.d.ts +6 -0
  25. package/lib/structures/index.d.ts +4 -0
  26. package/lib/structures/index.js +4 -0
  27. package/native/base.go +25 -23
  28. package/native/bridge_trace.go +348 -0
  29. package/native/comments.go +1 -1
  30. package/native/config.go +6 -3
  31. package/native/declaration.go +17 -43
  32. package/native/documentation_regions.go +214 -0
  33. package/native/documented.go +5 -4
  34. package/native/exports.go +1 -1
  35. package/native/fingerprint.go +2 -8
  36. package/native/glob.go +4 -1
  37. package/native/graph.go +59 -23
  38. package/native/graph_nodes.go +2 -1
  39. package/native/hints.go +22 -18
  40. package/native/imports.go +7 -6
  41. package/native/input_reader.go +83 -0
  42. package/native/inputs.go +13 -12
  43. package/native/loader.go +36 -24
  44. package/native/markdown.go +587 -177
  45. package/native/markdown_capture.go +223 -0
  46. package/native/model.go +2 -1
  47. package/native/prisma.go +110 -25
  48. package/native/prisma_cache.go +12 -8
  49. package/native/prisma_locator.go +70 -33
  50. package/native/review.go +8 -7
  51. package/native/rooted_typescript.go +3 -4
  52. package/native/swagger.go +123 -15
  53. package/native/swagger_cache.go +16 -12
  54. package/native/todo.go +12 -0
  55. package/native/typescript.go +129 -25
  56. package/package.json +9 -7
  57. package/lib/typings/ITtscLintContributorRules.d.ts +0 -57
  58. package/lib/typings/ITtscLintRuleOptionsMap.d.ts +0 -20
  59. package/lib/typings/ITtscLintRuleOptionsMap.js +0 -2
  60. package/lib/typings/TtscEvidenceGraphMarkdownSymbol.d.ts +0 -32
  61. package/lib/typings/index.d.ts +0 -5
  62. package/lib/typings/index.js +0 -21
  63. /package/lib/{typings/ITtscLintContributorRules.js → structures/ITtscEvidenceRules.js} +0 -0
  64. /package/lib/{typings → structures}/TtscEvidenceGraphMarkdownSymbol.js +0 -0
  65. /package/lib/{typings → structures}/TtscEvidenceGraphPrismaSymbol.js +0 -0
  66. /package/lib/{typings → structures}/TtscEvidenceGraphTypeScriptSymbol.js +0 -0
@@ -1,6 +1,7 @@
1
1
  package evidence
2
2
 
3
3
  import (
4
+ "os"
4
5
  "path/filepath"
5
6
  "sort"
6
7
  "strings"
@@ -32,7 +33,7 @@ func extendTypeScriptInventories(
32
33
  inventories map[string]*artifactInventory,
33
34
  governed map[string]bool,
34
35
  ) {
35
- bases := typeScriptMatchBases(config)
36
+ bases := typeScriptMatchBases(config, root)
36
37
  for _, file := range sources {
37
38
  if file == nil || !isTypeScriptPath(file.FileName()) {
38
39
  continue
@@ -129,51 +130,154 @@ func isTypeScriptPath(path string) bool {
129
130
  // typeScriptMatchBase pairs a configured base with the directory a Program
130
131
  // source path is measured against.
131
132
  //
132
- // This kind walks nothing, so the link asymmetry #1258 removed from the two
133
- // walkers looked like a walk problem and was left here. It is not: `os.Stat`
133
+ // This kind walks nothing, so link resolution can look like a problem for the
134
+ // walkers alone. It is not: `os.Stat`
134
135
  // accepts a linked root as a directory, and a Program reports whatever path its
135
136
  // tsconfig resolved, so when the two disagree about the link every source fails
136
137
  // the comparison, the claim selects nothing, and it deactivates without a word.
137
138
  // Measured before the repair: a claim rooted at a junction over its own project
138
139
  // produced no diagnostic at all.
139
140
  //
140
- // Both spellings are tried, because the Program may report either, and the
141
- // address is composed from the declared base in both cases, so a source reached
142
- // through a link is identified exactly as it would be without one. The
143
- // resolution is per base and the comparison is per source, so the extra spelling
144
- // costs nothing where no link is involved.
141
+ // A Program may report a source through a link at the project root, at a
142
+ // configured base, or inside it. Resolve the source and base through the same
143
+ // filesystem rule, then compare once. Addresses still use the declared base.
144
+ // Source directories are memoized for the whole population pass, so multiple
145
+ // configured bases do not each traverse the same chain for every source.
145
146
  type typeScriptMatchBase struct {
146
147
  base populationBase
147
148
  resolved string
149
+ paths *typeScriptSourcePaths
148
150
  }
149
151
 
150
- func typeScriptMatchBases(config graphConfig) []typeScriptMatchBase {
152
+ func typeScriptMatchBases(
153
+ config graphConfig,
154
+ root string,
155
+ ) []typeScriptMatchBase {
151
156
  bases := configuredBases(config, artifactTypeScript)
152
157
  entries := make([]typeScriptMatchBase, 0, len(bases))
158
+ paths := &typeScriptSourcePaths{
159
+ inputs: config.inputs,
160
+ directories: map[string]string{},
161
+ files: map[string]string{},
162
+ }
163
+ if root != "" {
164
+ paths.directories[filepath.Clean(root)] = canonicalTypeScriptDirectory(root, config.inputs)
165
+ }
153
166
  for _, base := range bases {
154
- // An unresolved chain is reported by the gate for a declared root, and this
155
- // comparison then has only the declared spelling to offer: keeping the link
156
- // the resolver stopped on would spend a second comparison against a path no
157
- // source can sit under, and the guard in `relativeOf` reads exactly this
158
- // equality to skip it. For the default base nothing reports it here, which is
159
- // the trade the gate's own comment states.
167
+ // The declared-root gate reports a chain it cannot finish. A partial
168
+ // resolution is not a comparison base, so keep the declared spelling when
169
+ // the resolver stops short.
160
170
  resolved, ok := resolvedBaseDirectory(base)
161
171
  if !ok {
162
172
  resolved = base.Absolute
163
173
  }
164
- entries = append(entries, typeScriptMatchBase{base: base, resolved: resolved})
174
+ entries = append(entries, typeScriptMatchBase{
175
+ base: base,
176
+ resolved: canonicalTypeScriptDirectory(resolved, config.inputs),
177
+ paths: paths,
178
+ })
165
179
  }
166
180
  return entries
167
181
  }
168
182
 
169
183
  func (entry typeScriptMatchBase) relativeOf(name string) (string, bool) {
170
- if relative, ok := relativeProjectPath(entry.base.Absolute, name); ok {
171
- return relative, true
172
- }
173
- if entry.resolved == entry.base.Absolute {
174
- return "", false
184
+ return relativeProjectPath(entry.resolved, entry.paths.resolve(name))
185
+ }
186
+
187
+ // typeScriptSourcePaths resolves each Program path once and each parent
188
+ // directory once per population pass. The Program may spell the same file
189
+ // through another link, while a base has already resolved to its target.
190
+ type typeScriptSourcePaths struct {
191
+ inputs evidenceInputReader
192
+ directories map[string]string
193
+ files map[string]string
194
+ }
195
+
196
+ func (paths *typeScriptSourcePaths) resolve(name string) string {
197
+ cleaned := filepath.Clean(filepath.FromSlash(name))
198
+ if resolved, ok := paths.files[cleaned]; ok {
199
+ return resolved
200
+ }
201
+ directory := filepath.Dir(cleaned)
202
+ physical, ok := paths.directories[directory]
203
+ if !ok {
204
+ physical = canonicalTypeScriptDirectory(directory, paths.inputs)
205
+ paths.directories[directory] = physical
206
+ }
207
+ candidate := filepath.Join(filepath.FromSlash(physical), filepath.Base(cleaned))
208
+ if evaluated, err := paths.inputs.EvalSymlinks(candidate); err == nil {
209
+ candidate = evaluated
210
+ }
211
+ resolved := filepath.ToSlash(candidate)
212
+ paths.files[cleaned] = resolved
213
+ return resolved
214
+ }
215
+
216
+ // canonicalTypeScriptDirectory follows every linked ancestor as the base
217
+ // resolver does. EvalSymlinks then expands native aliases such as Windows 8.3
218
+ // spelling. A host may open a long link chain while refusing EvalSymlinks of a
219
+ // descendant; in that case an ancestor's successful native expansion supplies
220
+ // the prefix and the unchanged suffix keeps the unresolved lexical path. This
221
+ // does not claim that the bounded resolver followed the entire link chain.
222
+ // A missing directory likewise keeps its existing prefix and missing suffix,
223
+ // which lets an unsaved Program source still match its base.
224
+ func canonicalTypeScriptDirectory(directory string, readers ...evidenceInputReader) string {
225
+ inputs := inputReader(readers)
226
+ current := filepath.Clean(filepath.FromSlash(directory))
227
+ missing := []string{}
228
+ for {
229
+ info, err := inputs.Stat(current)
230
+ if err == nil {
231
+ if !info.IsDir() {
232
+ return filepath.ToSlash(directory)
233
+ }
234
+ resolved, settled := resolveLinkedPath(current, inputs)
235
+ if !settled {
236
+ // The bounded resolver protects declared roots, but a Program base
237
+ // can still be reached through a longer chain the host itself opens.
238
+ // Ask the host to resolve that full chain before falling back to the
239
+ // declared spelling.
240
+ resolved = current
241
+ }
242
+ if evaluated, err := inputs.EvalSymlinks(filepath.FromSlash(resolved)); err == nil {
243
+ resolved = evaluated
244
+ } else if !settled {
245
+ // Native expansion may succeed for the base but fail below the same
246
+ // chain. Normalize the prefix through that successful observation so
247
+ // one Program's base and sources do not disagree only about aliases.
248
+ prefix := filepath.Dir(current)
249
+ suffix := []string{filepath.Base(current)}
250
+ for {
251
+ if evaluated, err := inputs.EvalSymlinks(prefix); err == nil {
252
+ resolved = filepath.Join(append([]string{evaluated}, suffix...)...)
253
+ break
254
+ }
255
+ parent := filepath.Dir(prefix)
256
+ if parent == prefix {
257
+ return filepath.ToSlash(directory)
258
+ }
259
+ suffix = append([]string{filepath.Base(prefix)}, suffix...)
260
+ prefix = parent
261
+ }
262
+ }
263
+ parts := append([]string{filepath.FromSlash(resolved)}, missing...)
264
+ return filepath.ToSlash(filepath.Join(parts...))
265
+ }
266
+ if !os.IsNotExist(err) {
267
+ return filepath.ToSlash(directory)
268
+ }
269
+ // A broken link is present but does not name a directory. Do not treat it
270
+ // as a missing segment that can be placed below another physical parent.
271
+ if _, linkErr := inputs.Lstat(current); linkErr == nil || !os.IsNotExist(linkErr) {
272
+ return filepath.ToSlash(directory)
273
+ }
274
+ parent := filepath.Dir(current)
275
+ if parent == current {
276
+ return filepath.ToSlash(directory)
277
+ }
278
+ missing = append([]string{filepath.Base(current)}, missing...)
279
+ current = parent
175
280
  }
176
- return relativeProjectPath(entry.resolved, name)
177
281
  }
178
282
 
179
283
  func relativeProjectPath(root string, absolute string) (string, bool) {
@@ -800,8 +904,7 @@ func collectClassDeclarationNames(
800
904
  // Its own withdrawal tag is read here for a separate fault rather than the same
801
905
  // one: the statement wrapper's tag was taken for every declarator it holds, so
802
906
  // `@internal` written on an inner declarator withdrew nothing. Recording the
803
- // node closes the first two and leaves this one standing, which is why #1126
804
- // states them apart.
907
+ // node closes the first two and leaves this one standing, which is why they are stated apart.
805
908
  func collectTypeScriptVariables(
806
909
  file *shimast.SourceFile,
807
910
  statement *shimast.Node,
@@ -1937,6 +2040,7 @@ func matchesConfiguredTypeScriptFile(
1937
2040
  // silenced a file whose declarations were all commented out, which is exactly
1938
2041
  // the shape the diagnostic's second repair clause exists for.
1939
2042
  func recordGovernedTypeScriptFiles(
2043
+ root string,
1940
2044
  sources []*shimast.SourceFile,
1941
2045
  declared graphConfig,
1942
2046
  governed map[string]bool,
@@ -1944,7 +2048,7 @@ func recordGovernedTypeScriptFiles(
1944
2048
  if governed == nil {
1945
2049
  return
1946
2050
  }
1947
- bases := typeScriptMatchBases(declared)
2051
+ bases := typeScriptMatchBases(declared, root)
1948
2052
  for _, file := range sources {
1949
2053
  if file == nil || !isTypeScriptPath(file.FileName()) {
1950
2054
  continue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/evidence",
3
- "version": "0.30.4",
3
+ "version": "0.31.1",
4
4
  "description": "Evidence-graph lint contributor for @ttsc/lint: declare provenance with a JSDoc @evidence tag and fail the build when it is missing or dangling.",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -42,23 +42,25 @@
42
42
  "url": "https://github.com/samchon/ttsc/issues"
43
43
  },
44
44
  "peerDependencies": {
45
- "@ttsc/lint": ">0.28.6"
45
+ "@ttsc/lint": ">=0.31.0"
46
46
  },
47
47
  "devDependencies": {
48
+ "@wrtnlabs/evidence": "^0.3.1",
48
49
  "@types/node": "^25.3.0",
49
50
  "rimraf": "^6.1.2",
50
51
  "typescript": "^7.0.2",
51
- "@ttsc/lint": "0.30.4",
52
- "ttsc": "0.30.4"
52
+ "@ttsc/lint": "0.31.1",
53
+ "ttsc": "0.31.1"
53
54
  },
54
55
  "dependencies": {
55
56
  "@prisma/prisma-schema-wasm": "7.10.0-2.d0368e25c88e68caa4d283b5f2d88d1b76ed9356",
56
- "@typia/interface": "^14.0.6",
57
- "@typia/utils": "^14.0.6",
57
+ "@typia/interface": "^15.1.0",
58
+ "@typia/utils": "^15.1.0",
58
59
  "yaml": "^2.9.0"
59
60
  },
60
61
  "homepage": "https://ttsc.dev",
61
62
  "scripts": {
62
- "build": "rimraf lib && tsc"
63
+ "build": "rimraf lib && tsc",
64
+ "evidence": "evidence"
63
65
  }
64
66
  }
@@ -1,57 +0,0 @@
1
- import type { TtscLintRuleSetting } from "@ttsc/lint";
2
- declare module "@ttsc/lint" {
3
- interface ITtscLintContributorRules {
4
- /**
5
- * Requires one public identity per TypeScript file, named after the file.
6
- *
7
- * The counted unit is an identity rather than an export, so declaration
8
- * merging of a single name stays legal: `export interface ISomething`
9
- * beside `export namespace ISomething`, `export class Something` beside
10
- * `export namespace Something`, and `export const something` beside `export
11
- * default something` are each one identity.
12
- *
13
- * A file that only re-exports owns no identity and is never reported, and
14
- * an `index` file is exempt from the name match while still limited to one
15
- * identity.
16
- *
17
- * The rule takes no options; per-directory scoping belongs in the outer
18
- * `files` setting of `lint.config.ts`.
19
- */
20
- "evidence/singular"?: TtscLintRuleSetting;
21
- /**
22
- * Reports every JSDoc `@todo` tag in a checked file.
23
- *
24
- * A remaining `@todo` is a contract the declaration has not realized yet,
25
- * so each tag fails the build with its own text until the declaration is
26
- * realized and the tag removed. Every declaration's block is read, exported
27
- * or not, on any symbol kind.
28
- *
29
- * The rule takes no options; per-directory scoping belongs in the outer
30
- * `files` setting of `lint.config.ts`.
31
- */
32
- "evidence/todo"?: TtscLintRuleSetting;
33
- /**
34
- * Requires a review beside every acknowledgement.
35
- *
36
- * Every `@evidence` and `@evidenceExclude` on a public identity must be
37
- * answered by an `@evidenceReview` naming the same target. The citation
38
- * states why this declaration answers for that target; the review states
39
- * what was verified. Those are different questions, and only the first one
40
- * is written unless something asks for the second.
41
- *
42
- * A review is an annotation of a citation, never an acknowledgement of a
43
- * unit. It discharges no coverage, contributes no host to `uniqueEvidence`,
44
- * and counts toward no `singleEvidencePerSymbol` total, so enabling this
45
- * rule cannot change a single `evidence/graph` diagnostic.
46
- *
47
- * The optional `#`-prefixed fingerprint token is carried without being
48
- * interpreted here. `evidence/graph` validates it against the cited content
49
- * under a reference's `requireReview`, which is what makes a review expire
50
- * when the thing it reviewed moves.
51
- *
52
- * The rule takes no options; per-directory scoping belongs in the outer
53
- * `files` setting of `lint.config.ts`.
54
- */
55
- "evidence/review"?: TtscLintRuleSetting;
56
- }
57
- }
@@ -1,20 +0,0 @@
1
- import type { ITtscEvidenceDocumentedConfig } from "../structures/ITtscEvidenceDocumentedConfig";
2
- import type { ITtscEvidenceGraphConfig } from "../structures/ITtscEvidenceGraphConfig";
3
- declare module "@ttsc/lint" {
4
- interface ITtscLintRuleOptionsMap {
5
- /**
6
- * Declares this project's evidence graph.
7
- *
8
- * The claims define the citing populations and the independently complete
9
- * evidence references each one must acknowledge.
10
- */
11
- "evidence/graph": ITtscEvidenceGraphConfig;
12
- /**
13
- * Requires a JSDoc block on every selected export.
14
- *
15
- * A JSDoc block is the only place an `@evidence` tag is read from, so an
16
- * export without one cannot participate in the graph at all.
17
- */
18
- "evidence/documented": ITtscEvidenceDocumentedConfig;
19
- }
20
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,32 +0,0 @@
1
- /**
2
- * A Markdown node kind that can become an evidence unit or host an evidence
3
- * declaration.
4
- *
5
- * `"file"` is the document root. `"h1"` through `"h4"` select ATX heading
6
- * sections at that exact level; Setext headings and H5/H6 headings are outside
7
- * this contract.
8
- *
9
- * These nodes form the Markdown outline: the file contains every heading, and a
10
- * heading contains the lower-level headings before the next heading of equal or
11
- * higher level. An `@evidence` target, or an `@evidenceExclude` target allowed
12
- * by its reference policy, acknowledges its selected node and every selected
13
- * descendant. A reference selector still defines which descendants are
14
- * obligations; an unselected ancestor remains addressable as their aggregate
15
- * scope.
16
- *
17
- * A file evidence target is its project-relative path with `/` separators. A
18
- * declaration may spell those separators as `/` or `\`. A heading target
19
- * appends its anchor, such as `docs/orders.md#create-order`. An explicit
20
- * `{#anchor}` suffix wins. Its anchor must start with an ASCII letter or digit
21
- * and may then contain ASCII letters, digits, `.`, `_`, `:`, and `-`.
22
- *
23
- * Without an explicit anchor, the heading becomes a lowercase slug: letters,
24
- * numbers, and `_` remain; whitespace and `-` collapse to `-`; other
25
- * punctuation is removed. Two selected headings that produce the same target
26
- * are ambiguous and need distinct explicit anchors.
27
- *
28
- * Targets are one whitespace-delimited declaration token. A Markdown source
29
- * path therefore cannot contain whitespace; the rule reports such a file with a
30
- * rename diagnostic instead of creating an impossible obligation.
31
- */
32
- export type TtscEvidenceGraphMarkdownSymbol = "file" | "h1" | "h2" | "h3" | "h4";
@@ -1,5 +0,0 @@
1
- import "./ITtscLintContributorRules";
2
- import "./ITtscLintRuleOptionsMap";
3
- export * from "./TtscEvidenceGraphMarkdownSymbol";
4
- export * from "./TtscEvidenceGraphPrismaSymbol";
5
- export * from "./TtscEvidenceGraphTypeScriptSymbol";
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- require("./ITtscLintContributorRules");
18
- require("./ITtscLintRuleOptionsMap");
19
- __exportStar(require("./TtscEvidenceGraphMarkdownSymbol"), exports);
20
- __exportStar(require("./TtscEvidenceGraphPrismaSymbol"), exports);
21
- __exportStar(require("./TtscEvidenceGraphTypeScriptSymbol"), exports);