@prestack/thread 0.1.21 → 0.1.23

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/CHANGELOG.md +227 -0
  2. package/dist/core/attach.js +21 -0
  3. package/dist/core/descend.js +6 -3
  4. package/dist/core/generators/commit.js +55 -3
  5. package/dist/core/generators/dev.d.ts +1 -0
  6. package/dist/core/generators/dev.js +69 -0
  7. package/dist/derivation/generators/build.d.ts +3 -1
  8. package/dist/derivation/generators/build.js +104 -22
  9. package/dist/derivation/generators/release.js +74 -25
  10. package/dist/derivation/release.js +3 -3
  11. package/dist/integrations/cli.d.ts +0 -1
  12. package/dist/integrations/cli.js +69 -11
  13. package/dist/integrations/declared.d.ts +2 -0
  14. package/dist/integrations/declared.js +6 -1
  15. package/dist/integrations/pglite.js +13 -3
  16. package/dist/integrations/target.d.ts +3 -0
  17. package/dist/integrity/attach.js +1 -5
  18. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  19. package/dist/operations/access.js +3 -2
  20. package/dist/operations/capabilities.d.ts +2 -0
  21. package/dist/operations/capabilities.js +2 -0
  22. package/dist/operations/generators/capability.js +237 -24
  23. package/dist/operations/generators/compile.js +150 -50
  24. package/dist/operations/generators/seed.d.ts +3 -0
  25. package/dist/operations/generators/seed.js +25 -3
  26. package/dist/operations/nodes.d.ts +2 -2
  27. package/package.json +1 -1
  28. package/dist/core/actor.ts +0 -21
  29. package/dist/core/attach.ts +0 -613
  30. package/dist/core/chain.ts +0 -145
  31. package/dist/core/condition.ts +0 -227
  32. package/dist/core/descend.ts +0 -1185
  33. package/dist/core/errors/catalogue.ts +0 -314
  34. package/dist/core/errors/classes.ts +0 -51
  35. package/dist/core/errors/error.ts +0 -152
  36. package/dist/core/errors/namespaces.ts +0 -19
  37. package/dist/core/finding.ts +0 -37
  38. package/dist/core/generators/commit.ts +0 -157
  39. package/dist/core/init.ts +0 -222
  40. package/dist/core/invoked.ts +0 -52
  41. package/dist/core/round.ts +0 -74
  42. package/dist/core/rows.ts +0 -506
  43. package/dist/core/scope.ts +0 -20
  44. package/dist/core/thread.ts +0 -29
  45. package/dist/core/tree.ts +0 -90
  46. package/dist/core/types.ts +0 -351
  47. package/dist/derivation/attach.ts +0 -57
  48. package/dist/derivation/generators/build.ts +0 -371
  49. package/dist/derivation/generators/check.ts +0 -118
  50. package/dist/derivation/generators/determinism.ts +0 -145
  51. package/dist/derivation/generators/release.ts +0 -236
  52. package/dist/derivation/release.ts +0 -43
  53. package/dist/integrations/attach.ts +0 -187
  54. package/dist/integrations/cli.ts +0 -606
  55. package/dist/integrations/declared.ts +0 -34
  56. package/dist/integrations/disk.ts +0 -466
  57. package/dist/integrations/generators/read.ts +0 -127
  58. package/dist/integrations/generators/vault.ts +0 -210
  59. package/dist/integrations/https.ts +0 -216
  60. package/dist/integrations/pglite.ts +0 -206
  61. package/dist/integrations/secret.ts +0 -54
  62. package/dist/integrations/target.ts +0 -672
  63. package/dist/integrations/vault.ts +0 -148
  64. package/dist/integrity/attach.ts +0 -150
  65. package/dist/integrity/check-threads.ts +0 -166
  66. package/dist/integrity/constraint.ts +0 -1246
  67. package/dist/integrity/generators/compiler.ts +0 -138
  68. package/dist/integrity/generators/gate.ts +0 -227
  69. package/dist/integrity/generators/issues.ts +0 -160
  70. package/dist/integrity/generators/publish.ts +0 -233
  71. package/dist/integrity/generators/trial.ts +0 -359
  72. package/dist/integrity/lint.ts +0 -214
  73. package/dist/integrity/lsp/bin.ts +0 -44
  74. package/dist/integrity/lsp/diagnostics.ts +0 -92
  75. package/dist/integrity/lsp/findings.ts +0 -63
  76. package/dist/integrity/lsp/lint.ts +0 -124
  77. package/dist/integrity/lsp/protocol.ts +0 -78
  78. package/dist/integrity/lsp/server.ts +0 -224
  79. package/dist/integrity/slopnator.ts +0 -324
  80. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  81. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  82. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  83. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  84. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  85. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  86. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  87. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  88. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  89. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  90. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  91. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  92. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  93. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  94. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  95. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  96. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  97. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  98. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  99. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  100. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  101. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  102. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  103. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  104. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  105. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  106. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  107. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  108. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  109. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  110. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  111. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  112. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  113. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  114. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  115. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  116. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  117. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  118. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  119. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  120. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  121. package/dist/integrity/sweep.ts +0 -395
  122. package/dist/knowledge/attach.ts +0 -327
  123. package/dist/knowledge/generators/docsgen.ts +0 -186
  124. package/dist/knowledge/generators/glossary.ts +0 -73
  125. package/dist/knowledge/glossary.ts +0 -6
  126. package/dist/operations/access.ts +0 -131
  127. package/dist/operations/attach.ts +0 -408
  128. package/dist/operations/capabilities.ts +0 -88
  129. package/dist/operations/dispatch.ts +0 -294
  130. package/dist/operations/error-results.ts +0 -31
  131. package/dist/operations/generators/capability.ts +0 -1054
  132. package/dist/operations/generators/compile.ts +0 -701
  133. package/dist/operations/generators/permits.ts +0 -229
  134. package/dist/operations/generators/seed.ts +0 -359
  135. package/dist/operations/generators/trial.ts +0 -666
  136. package/dist/operations/nodes.ts +0 -53
  137. package/dist/operations/operations.ts +0 -91
  138. package/dist/operations/result.ts +0 -28
@@ -1,152 +0,0 @@
1
- import type { Slopnator } from '../slopnator.ts'
2
-
3
- import { descend, read, reached } from '../../core/descend.ts'
4
-
5
- import { rowsIn } from './sl_unthreaded.ts'
6
-
7
- const ELEMENT = 'element'
8
-
9
- const VARIANT = 'variant'
10
-
11
- interface Worn {
12
- readonly elements: ReadonlySet<string>
13
- readonly variants: ReadonlyMap<string, readonly string[]>
14
- }
15
-
16
- function nameOf(id: string): string {
17
- return id
18
- .split('-')
19
- .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
20
- .join('')
21
- }
22
-
23
- function idOf(name: string): string {
24
- return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
25
- }
26
-
27
- function memberOf(id: string): string {
28
- const [first = '', ...rest] = id.split('-')
29
- return first + rest.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join('')
30
- }
31
-
32
- function declared(): Worn {
33
- const elements = new Set<string>()
34
- const variants = new Map<string, readonly string[]>()
35
-
36
- descend()
37
-
38
- for (const at of reached()) {
39
- const text = read(at)
40
- if (text === undefined) continue
41
-
42
- let waiting: { readonly id: string; readonly wears?: readonly string[] }[] = []
43
- for (const one of rowsIn(text)) {
44
- if (one.id === undefined) continue
45
- if (one.list === 'declares') {
46
- waiting.push(one.wears === undefined ? { id: one.id } : { id: one.id, wears: one.wears })
47
- continue
48
- }
49
- if (one.list !== undefined) continue
50
- if (one.id === ELEMENT) for (const row of waiting) elements.add(nameOf(row.id))
51
- if (one.id === VARIANT) for (const row of waiting) variants.set(row.id, row.wears ?? [])
52
- waiting = []
53
- }
54
- }
55
-
56
- return { elements, variants }
57
- }
58
-
59
- interface Tag {
60
- readonly type?: string
61
- readonly object?: { readonly type?: string; readonly name?: string }
62
- readonly property?: { readonly type?: string; readonly name?: string }
63
- }
64
-
65
- export const slopnator: Slopnator = {
66
- on: ['JSXOpeningElement'],
67
- holds: (node) => {
68
- const name = (node as { name?: Tag } | undefined)?.name
69
- if (name?.type !== 'JSXMemberExpression') return false
70
-
71
- const element = name.object?.type === 'JSXIdentifier' ? name.object.name : undefined
72
- const member = name.property?.type === 'JSXIdentifier' ? name.property.name : undefined
73
- if (element === undefined || member === undefined) return false
74
-
75
- const { elements, variants } = declared()
76
- if (!elements.has(element)) return false
77
-
78
- const id = idOf(member)
79
- const wears = variants.get(id)
80
-
81
- const worn = [...variants]
82
- .filter(([, all]) => all.includes(element))
83
- .map(([one]) => `${element}.${memberOf(one)}`)
84
- .sort()
85
-
86
- const offered =
87
- worn.length === 0
88
- ? `nothing declares itself worn by \`${element}\`, so no member of it would have been accepted — a variant row has to name \`${element}\` first`
89
- : `\`${element}\` wears ${worn.join(', ')}`
90
-
91
- if (wears === undefined) {
92
- return (
93
- `\`${element}.${member}\` names the variant \`${id}\` and nothing declares it — so it renders carrying a class ` +
94
- 'the stylesheet never writes, which reads on screen as an element that lost its styling and is reported ' +
95
- `nowhere. ${offered}`
96
- )
97
- }
98
-
99
- if (!wears.includes(element)) {
100
- return (
101
- `\`${element}.${member}\` pairs \`${element}\` with the variant \`${id}\`, and that variant's row does not name ` +
102
- `\`${element}\` among the elements that wear it — so the pairing is nobody's declaration. ${offered}`
103
- )
104
- }
105
-
106
- return false
107
- },
108
- proves: {
109
- wrong: [
110
- {
111
- files: [
112
- { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
113
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_probe_worn.ts',\n },\n ],\n}\n" },
114
- {
115
- at: 'threads/_probe_worn.ts',
116
- source:
117
- "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const ELEMENTS: Threaded = {\n id: 'element',\n declares: [\n {\n id: 'button',\n at: 'app/_probe_button.tsx',\n },\n ],\n}\n\nexport const VARIANTS: Threaded = {\n id: 'variant',\n declares: [\n {\n id: 'button-primary',\n at: 'app/_probe_variant.ts',\n wears: ['Button'],\n },\n ],\n}\n",
118
- },
119
- { at: 'app/_probe_undeclared.tsx', source: 'export const HELD = <Button.primary />\n' },
120
- ],
121
- at: 'app/_probe_undeclared.tsx',
122
- },
123
- {
124
- files: [
125
- { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
126
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_probe_worn.ts',\n },\n ],\n}\n" },
127
- {
128
- at: 'threads/_probe_worn.ts',
129
- source:
130
- "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const ELEMENTS: Threaded = {\n id: 'element',\n declares: [\n {\n id: 'button',\n at: 'app/_probe_button.tsx',\n },\n {\n id: 'badge',\n at: 'app/_probe_badge.tsx',\n },\n ],\n}\n\nexport const VARIANTS: Threaded = {\n id: 'variant',\n declares: [\n {\n id: 'chip',\n at: 'app/_probe_chip.ts',\n wears: ['Badge'],\n },\n ],\n}\n",
131
- },
132
- { at: 'app/_probe_mispaired.tsx', source: 'export const HELD = <Button.chip />\n' },
133
- ],
134
- at: 'app/_probe_mispaired.tsx',
135
- },
136
- ],
137
- right: [
138
- {
139
- files: [
140
- {
141
- at: 'threads/_probe_worn.ts',
142
- source:
143
- "export const ELEMENTS: Threaded = {\n id: 'element',\n declares: [\n {\n id: 'button',\n at: 'app/_probe_button.tsx',\n },\n ],\n}\n\nexport const VARIANTS: Threaded = {\n id: 'variant',\n declares: [\n {\n id: 'button-primary',\n at: 'app/_probe_variant.ts',\n wears: ['Button'],\n },\n ],\n}\n",
144
- },
145
- { at: 'app/_probe_declared.tsx', source: 'export const HELD = <Button.buttonPrimary />\n' },
146
- ],
147
- at: 'app/_probe_declared.tsx',
148
- },
149
- '<Unknown.anything />',
150
- ],
151
- },
152
- }
@@ -1,108 +0,0 @@
1
- import ts from 'typescript'
2
-
3
- import { descend } from '../../core/descend.ts'
4
-
5
- import type { Slopnator } from '../slopnator.ts'
6
-
7
- const said = (held: ts.Expression | undefined): string | undefined =>
8
- held !== undefined && ts.isStringLiteral(held) ? held.text : undefined
9
-
10
- const listed = (held: ts.Expression | undefined): readonly string[] =>
11
- held !== undefined && ts.isArrayLiteralExpression(held)
12
- ? held.elements.filter((one) => ts.isStringLiteral(one)).map((one) => (one as ts.StringLiteral).text)
13
- : []
14
-
15
- const yes = (held: ts.Expression | undefined): boolean =>
16
- held !== undefined && held.kind === ts.SyntaxKind.TrueKeyword
17
-
18
- interface Asking {
19
- readonly id: string
20
- readonly invokes: string
21
- readonly carries: boolean
22
- }
23
-
24
- function invoking(text: string): { readonly asking: readonly Asking[]; readonly rows: ReadonlyMap<string, ts.ObjectLiteralExpression> } {
25
- const file = ts.createSourceFile('row.ts', text, ts.ScriptTarget.Latest, true)
26
- const rows = new Map<string, ts.ObjectLiteralExpression>()
27
- const found: Asking[] = []
28
- const visit = (node: ts.Node): void => {
29
- if (ts.isObjectLiteralExpression(node)) {
30
- const of = (name: string): ts.Expression | undefined => {
31
- for (const one of node.properties) {
32
- if (ts.isPropertyAssignment(one) && ts.isIdentifier(one.name) && one.name.text === name) return one.initializer
33
- }
34
- return undefined
35
- }
36
- const id = said(of('id'))
37
- if (id !== undefined) rows.set(id, node)
38
- const invokes = said(of('invokes'))
39
- if (id !== undefined && invokes !== undefined) {
40
- found.push({ id, invokes, carries: said(of('arrives')) !== undefined && listed(of('requires')).length > 0 })
41
- }
42
- }
43
- ts.forEachChild(node, visit)
44
- }
45
- visit(file)
46
- return { asking: found, rows }
47
- }
48
-
49
- const fieldOf = (node: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined => {
50
- for (const one of node.properties) {
51
- if (ts.isPropertyAssignment(one) && ts.isIdentifier(one.name) && one.name.text === name) return one.initializer
52
- }
53
- return undefined
54
- }
55
-
56
- export const slopnator: Slopnator = {
57
- holds: (_node, at) => {
58
- const { asking, rows } = invoking(at.text)
59
- if (asking.length === 0) return false
60
- const found: string[] = []
61
- const pass = descend()
62
- for (const one of asking) {
63
- const here = rows.get(one.invokes)
64
- const named = here === undefined ? undefined : listed(fieldOf(here, 'webhooks'))
65
- const signs = here === undefined ? undefined : yes(fieldOf(here, 'signed'))
66
- const runs = pass.stated.get(one.invokes)
67
- if (here === undefined && runs === undefined) {
68
- found.push(one.id + ' invokes ' + one.invokes + ', and nothing in this tree declares an operation by that name')
69
- continue
70
- }
71
- if (!(named ?? listed(runs?.fields.get('webhooks'))).includes(one.id)) {
72
- found.push(
73
- one.id + ' invokes ' + one.invokes + ', and that operation names no webhook ' + one.id +
74
- ' back, so it is reachable from outside by something it never agreed to',
75
- )
76
- }
77
- if ((signs ?? yes(runs?.fields.get('signed'))) && !one.carries) {
78
- found.push(
79
- one.invokes + ' takes only a signed webhook, and ' + one.id +
80
- ' states no header a signature arrives on and no secret to check it against',
81
- )
82
- }
83
- }
84
- return found.length === 0 ? false : found.join('; ')
85
- },
86
- proves: {
87
- wrong: [
88
- {
89
- files: [
90
- { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly invokes?: string\n readonly webhooks?: readonly string[]\n readonly declares?: readonly Threaded[]\n}\n" },
91
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n { at: 'threads/_probe_webhook.ts' },\n ],\n}\n" },
92
- { at: 'threads/_probe_webhook.ts', source: "export const WEBHOOKS: Threaded = {\n id: 'webhooks',\n declares: [\n { id: 'wh_stripe', at: 'app/inbound/wh_stripe/route.ts', invokes: 'wf_charge' },\n { id: 'wf_charge', at: 'operations/wf_charge.ts' },\n ],\n}\n" },
93
- ],
94
- at: 'threads/_probe_webhook.ts',
95
- },
96
- ],
97
- right: [
98
- {
99
- files: [
100
- { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly version?: number\n readonly invokes?: string\n readonly webhooks?: readonly string[]\n readonly by?: string\n readonly runs?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n}\n" },
101
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n { at: 'threads/_probe_webhook.ts' },\n ],\n}\n" },
102
- { at: 'threads/_probe_webhook.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const WEBHOOKS: Threaded = {\n id: 'webhooks',\n version: 1,\n declares: [\n { id: 'wf_charge', at: 'operations/wf_charge.ts', webhooks: ['wh_stripe'] },\n ],\n derives: [\n { id: 'wh_stripe', at: 'app/inbound/wh_stripe/route.ts', invokes: 'wf_charge', by: 'thread capabilities', runs: 'thread capabilities --check' },\n ],\n}\n" },
103
- ],
104
- at: 'threads/_probe_webhook.ts',
105
- },
106
- ],
107
- },
108
- }
@@ -1,72 +0,0 @@
1
- import ts from 'typescript'
2
-
3
- import { LISTS as LINEAGE } from '../../core/descend.ts'
4
-
5
- import type { Slopnator } from '../slopnator.ts'
6
-
7
- const LISTS: ReadonlySet<string> = new Set(LINEAGE)
8
-
9
- const ROUTE = '/route.ts'
10
-
11
- const said = (held: ts.Expression | undefined): string | undefined =>
12
- held !== undefined && ts.isStringLiteral(held) ? held.text : undefined
13
-
14
- const fieldOf = (node: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined => {
15
- for (const one of node.properties) {
16
- if (ts.isPropertyAssignment(one) && ts.isIdentifier(one.name) && one.name.text === name) return one.initializer
17
- }
18
- return undefined
19
- }
20
-
21
- export const slopnator: Slopnator = {
22
- holds: (_node, at) => {
23
- const file = ts.createSourceFile('row.ts', at.text, ts.ScriptTarget.Latest, true)
24
- const routes = new Map<string, string>()
25
- const permitted = new Set<string>()
26
-
27
- const visit = (node: ts.Node): void => {
28
- if (
29
- ts.isPropertyAssignment(node) &&
30
- ts.isIdentifier(node.name) &&
31
- LISTS.has(node.name.text) &&
32
- ts.isArrayLiteralExpression(node.initializer)
33
- ) {
34
- const list = node.name.text
35
- for (const one of node.initializer.elements) {
36
- if (!ts.isObjectLiteralExpression(one)) continue
37
- const where = said(fieldOf(one, 'at'))
38
- if (where === undefined || !where.endsWith(ROUTE)) continue
39
- routes.set(where, list)
40
- if (list === 'derives' && said(fieldOf(one, 'by')) !== undefined && said(fieldOf(one, 'runs')) !== undefined) {
41
- permitted.add(where)
42
- }
43
- }
44
- }
45
- ts.forEachChild(node, visit)
46
- }
47
- visit(file)
48
-
49
- const found: string[] = []
50
- for (const [where, list] of routes) {
51
- if (permitted.has(where)) continue
52
- found.push(
53
- where + ' is named by a ' + list + ' row' +
54
- (list === 'derives' ? ' that states no by and no runs' : '') +
55
- ', and a route is only ever derived',
56
- )
57
- }
58
- return found.length === 0 ? false : found.join('; ')
59
- },
60
- proves: {
61
- wrong: ["const M = { seeds: [{ at: 'app/inbound/wh_stripe/route.ts' }] }"],
62
- right: [
63
- {
64
- files: [
65
- { at: 'threads/thread.ts', source: "export const THREAD = {\n declares: [\n { at: 'threads/_probe_route.ts' },\n ],\n}\n" },
66
- { at: 'threads/_probe_route.ts', source: "export const M = {\n derives: [\n { at: 'app/inbound/wh_stripe/route.ts', by: 'thread capabilities', runs: 'thread capabilities --check' },\n ],\n}\n" },
67
- ],
68
- at: 'threads/_probe_route.ts',
69
- },
70
- ],
71
- },
72
- }
@@ -1,65 +0,0 @@
1
- import type { Slopnator } from '../slopnator.ts'
2
-
3
- const COMMON = new Set([
4
- 'a', 'an', 'the', 'of', 'for', 'to', 'and', 'or', 'is', 'it', 'its', 'this', 'that',
5
- 'in', 'on', 'at', 'as', 'by', 'with', 'be', 'are', 'was', 'one', 'every', 'each',
6
- ])
7
-
8
- type Node = {
9
- type?: string
10
- name?: string
11
- key?: { type?: string; name?: string; value?: unknown }
12
- value?: { type?: string; value?: unknown }
13
- computed?: boolean
14
- properties?: readonly Node[]
15
- }
16
-
17
- const keyOf = (property: Node): string | undefined => {
18
- if (property.computed === true) return undefined
19
- const key = property.key
20
- if (key?.type === 'Identifier') return key.name
21
- if (key?.type === 'Literal' && typeof key.value === 'string') return key.value
22
- return undefined
23
- }
24
-
25
- const said = (property: Node | undefined): string | undefined => {
26
- const held = property?.value
27
- return held?.type === 'Literal' && typeof held.value === 'string' ? held.value : undefined
28
- }
29
-
30
- const words = (text: string): readonly string[] =>
31
- text.toLowerCase().split(/[^a-z]+/).filter((one) => one !== '' && !COMMON.has(one))
32
-
33
- export const slopnator: Slopnator = {
34
- on: ['Property'],
35
- holds: (node, at) => {
36
- const property = node as Node
37
- const key = keyOf(property)
38
- if (key !== 'describes' && key !== 'means') return false
39
-
40
- const sentence = said(property)
41
- if (sentence === undefined) return false
42
- if (sentence.trim() === '') return `\`${key}\` is empty, so the word arrived and the meaning never did`
43
-
44
- const owner = (at.ancestors() as readonly Node[]).at(-1)
45
- const id = said((owner?.properties ?? []).find((one) => keyOf(one) === 'id' || keyOf(one) === 'name'))
46
- if (id === undefined) return false
47
-
48
- const own = new Set(words(id))
49
- if (words(sentence).some((word) => !own.has(word))) return false
50
- return `\`${key}\` says "${sentence}", which adds no word its id \`${id}\` does not already carry`
51
- },
52
- proves: {
53
- wrong: [
54
- "const M = { id: 'law', describes: 'The law.' }",
55
- "const M = { id: 'law', describes: '' }",
56
- "const M = { id: 'term', means: '' }",
57
- "const M = { id: 'thread-check', describes: 'The thread check.' }",
58
- ],
59
- right: [
60
- "const M = { id: 'law', describes: 'A rule that must be guaranteed to be enforced.' }",
61
- "const M = { id: 'term', means: 'A word this repository coins, and what somebody reading it should understand.' }",
62
- "const M = { id: 'law', at: 'packages/core/integrity/src/constraint.ts' }",
63
- ],
64
- },
65
- }
@@ -1,60 +0,0 @@
1
- import type { Slopnator } from '../slopnator.ts'
2
- import { here, islandsDeclared } from './sl_unthreaded.ts'
3
- import { findTree } from '../../core/tree.ts'
4
-
5
- const TREE = `${findTree().name}/`
6
- const GOVERNS = /^\s*governs:\s*'([^']+)'/gm
7
-
8
- export const slopnator: Slopnator = {
9
- holds: (_node, at) => {
10
- const path = here(at.filename)
11
- if (!path.startsWith(TREE)) return false
12
-
13
- let islands: readonly string[]
14
- try {
15
- islands = islandsDeclared().map((one) => one.id)
16
- } catch {
17
- return 'this file cannot be parsed, so the islands the tree declares were never read and nothing a law threaded to govern was measured'
18
- }
19
-
20
- for (const match of at.text.matchAll(GOVERNS)) {
21
- const governed = match[1] ?? ''
22
- if (islands.includes(governed)) continue
23
- return `a law governs "${governed}" and the tree declares no island by that name, so the rule reads as coverage of a kind nobody can declare`
24
- }
25
-
26
- return false
27
- },
28
- proves: {
29
- wrong: [
30
- {
31
- files: [
32
- {
33
- at: 'threads/_governed_probe.ts',
34
- source: "export const L: Constraint = {\n id: 'a-law',\n governs: 'no-island-by-this-name',\n}\n",
35
- },
36
- ],
37
- at: 'threads/_governed_probe.ts',
38
- },
39
- ],
40
- right: [
41
- {
42
- files: [
43
- { at: 'threads/thread.ts', source: "export const THREAD: Threaded = {\n declares: [\n { id: 'entities', at: 'src/islands/entities.ts', governs: ['app/_declare/entities.ts'] },\n ],\n}\n" },
44
- { at: 'src/islands/entities.ts', source: 'export const EntitiesIslandSchema = {}\nexport function defineEntities() {}\n' },
45
- { at: 'threads/_governed_probe.ts', source: "export const L: Constraint = {\n id: 'a-law',\n governs: 'entities',\n}\n" },
46
- ],
47
- at: 'threads/_governed_probe.ts',
48
- },
49
- {
50
- files: [
51
- {
52
- at: 'threads/_governed_probe.ts',
53
- source: "export const M: Islanding = {\n declares: [\n { id: 'events', at: 'packages/core/spec/src/islands/events.ts', governs: ['operations/'] },\n ],\n}\n",
54
- },
55
- ],
56
- at: 'threads/_governed_probe.ts',
57
- },
58
- ],
59
- },
60
- }
@@ -1,46 +0,0 @@
1
- import { ROOT } from '../../core/descend.ts'
2
- import { valuesIn } from '../../core/rows.ts'
3
- import { kind, readFileSync } from '../../integrations/disk.ts'
4
- import { REACH, programOf, unlisted } from '../../integrations/target.ts'
5
-
6
- import type { Slopnator } from '../slopnator.ts'
7
-
8
- const TARGETS = 'TARGETS'
9
-
10
- const there = (path: string): boolean => kind(path) === 'file'
11
-
12
- export const slopnator: Slopnator = {
13
- holds: (_node, at) => {
14
- let held: { readonly TARGETS?: readonly { readonly id?: unknown }[] }
15
- try {
16
- held = valuesIn(at.text) as { readonly TARGETS?: readonly { readonly id?: unknown }[] }
17
- } catch (thrown) {
18
- if (!at.text.includes(TARGETS)) return false
19
- return 'this sheet names ' + TARGETS + ' and could not be read as values, so no target on it was checked — ' + (thrown instanceof Error ? thrown.message : String(thrown))
20
- }
21
- const found: string[] = []
22
- for (const one of held.TARGETS ?? []) {
23
- if (typeof one.id !== 'string' || !one.id.startsWith(REACH.cli)) continue
24
- const name = one.id.slice(REACH.cli.length)
25
- if (programOf(name, ROOT, there, (path) => readFileSync(path, 'utf8')) === undefined) found.push(unlisted(name))
26
- }
27
- return found.length === 0 ? false : found.join('. ')
28
- },
29
- proves: {
30
- wrong: [
31
- "export const TARGETS: readonly Target[] = [{ id: 'cli_bash', of: 'in_shell', describes: 'The shell on the machine a command runs on.', version: 1, takes: [], requires: [] }]",
32
- ],
33
- right: [
34
- {
35
- files: [
36
- { at: 'node_modules/.bin/tsc', source: '' },
37
- { at: 'threads/_probe_targets.ts', source: "export const TARGETS: readonly Target[] = [{ id: 'cli_tsc', of: 'in_typescript', describes: 'The compiler this tree is checked and built with.', version: 1, takes: [], requires: [] }]\n" },
38
- ],
39
- at: 'threads/_probe_targets.ts',
40
- },
41
- "export const TARGETS: readonly Target[] = [{ id: 'cli_packager', of: 'in_packager', describes: 'The package manager the lockfile beside this tree picks.', version: 1, takes: [], requires: [] }]",
42
- "export const TARGETS: readonly Target[] = [{ id: 'cli_node', of: 'in_node', describes: 'The runtime this framework runs on.', version: 1, takes: [], requires: [] }]",
43
- "export const TARGETS: readonly Target[] = [{ id: 'ht_registry', of: 'in_registry', describes: 'The registry every package goes to.', version: 1, takes: [], requires: [], address: 'https://registry.npmjs.org' }]",
44
- ],
45
- },
46
- }
@@ -1,41 +0,0 @@
1
- import type { Slopnator } from '../slopnator.ts'
2
- import { declaresIsland, here, islandsDeclared } from './sl_unthreaded.ts'
3
-
4
- export const slopnator: Slopnator = {
5
- holds: (_node, at) => {
6
- const schema = declaresIsland(at.text)
7
- if (schema === undefined) return false
8
-
9
- const path = here(at.filename)
10
- if (islandsDeclared().some((island) => island.at === path)) return false
11
-
12
- return (
13
- `${schema}IslandSchema is an island and no row in the tree names it, so nothing states what it governs and ` +
14
- 'no law can reach it — the kind is declarable and every rule about where it may be declared is absent'
15
- )
16
- },
17
- proves: {
18
- wrong: [
19
- {
20
- files: [
21
- {
22
- at: 'packages/core/spec/src/islands/_unnamed_probe.ts',
23
- source: 'export const ThingIslandSchema = z.strictObject({\n specVersion: z.literal(1),\n})\n',
24
- },
25
- ],
26
- at: 'packages/core/spec/src/islands/_unnamed_probe.ts',
27
- },
28
- ],
29
- right: [
30
- {
31
- files: [
32
- {
33
- at: 'packages/core/spec/src/islands/_unnamed_probe.ts',
34
- source: 'export const ThingSchema = z.strictObject({\n name: z.string(),\n})\n',
35
- },
36
- ],
37
- at: 'packages/core/spec/src/islands/_unnamed_probe.ts',
38
- },
39
- ],
40
- },
41
- }