@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,101 +0,0 @@
1
- import { readFileSync } from '../../integrations/disk.ts'
2
- import { resolve } from 'node:path'
3
-
4
- import type { Slopnator } from '../slopnator.ts'
5
- import { atsIn } from './sl_unthreaded.ts'
6
- import { reached } from '../../core/descend.ts'
7
-
8
- export interface Derivation {
9
- readonly at: string
10
- readonly by?: string
11
- readonly runs?: string
12
- }
13
-
14
- export function derivations(root: string): readonly Derivation[] {
15
- const found: Derivation[] = []
16
- for (const at of reached()) {
17
- let text: string
18
- try {
19
- text = readFileSync(resolve(root, at), 'utf8')
20
- } catch {
21
- continue
22
- }
23
- const threadedDerives = new Set(atsIn(text, new Set(['derives'])))
24
- for (const opens of text.matchAll(/^\s*derives:\s*\[/gm)) {
25
- const from = opens.index ?? 0
26
- let depth = 1
27
- let cursor = from + opens[0].length
28
- while (cursor < text.length && depth > 0) {
29
- const one = text[cursor]
30
- if (one === '[') depth += 1
31
- else if (one === ']') depth -= 1
32
- cursor += 1
33
- }
34
- const own: string[] = []
35
- let nesting = 0
36
- for (const line of text.slice(from, cursor).split('\n')) {
37
- if (nesting === 1) own.push(line)
38
- for (const one of line) {
39
- if (one === '[') nesting += 1
40
- else if (one === ']') nesting -= 1
41
- }
42
- }
43
- const block = own.join('\n')
44
- for (const row of block.split(/^\s*\{$/m)) {
45
- const at = /^\s*at:\s*'([^']+)'/m.exec(row)?.[1]
46
- const by = /^\s*by:\s*'([^']+)'/m.exec(row)?.[1]
47
- const runs = /^\s*runs:\s*'([^']+)'/m.exec(row)?.[1]
48
- if (at !== undefined && threadedDerives.has(at)) found.push({ at, by, runs })
49
- }
50
- }
51
- }
52
- return found
53
- }
54
-
55
- export const slopnator: Slopnator = {
56
- checks: (root) => {
57
- const findings: string[] = []
58
- const all = derivations(root)
59
- const complete = all.filter((one) => one.by !== undefined && one.runs !== undefined)
60
- const covered = new Set(complete.map((one) => one.at))
61
-
62
- for (const at of new Set(all.map((one) => one.at))) {
63
- if (covered.has(at)) continue
64
- findings.push(
65
- `${at} sits in a \`derives\` list and no row naming it states both \`by\` and \`runs\` — a byproduct nothing can re-run is a claim, and this check used to drop such a row in silence`,
66
- )
67
- }
68
-
69
- return findings
70
- },
71
- proves: {
72
- wrong: [
73
- {
74
- files: [
75
- { 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" },
76
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_drift_probe.ts',\n },\n ],\n}\n" },
77
- { at: 'threads/_drift_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n derives: [\n {\n at: 'scripts/_generated/gate.mjs',\n by: 'pnpm gate:generate',\n },\n ],\n}\n" },
78
- ],
79
- at: 'threads/_drift_probe.ts',
80
- },
81
- {
82
- files: [
83
- { 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" },
84
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_drift_probe.ts',\n },\n ],\n}\n" },
85
- { at: 'threads/_drift_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n derives: [\n {\n at: 'scripts/finding.ts',\n },\n ],\n}\n" },
86
- ],
87
- at: 'threads/_drift_probe.ts',
88
- },
89
- ],
90
- right: [
91
- {
92
- files: [
93
- { 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" },
94
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_drift_probe.ts',\n },\n ],\n}\n" },
95
- { at: 'threads/_drift_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n derives: [\n {\n at: 'scripts/_generated/gate.mjs',\n by: 'pnpm gate:generate',\n runs: 'pnpm gate:check',\n },\n ],\n}\n" },
96
- ],
97
- at: 'threads/_drift_probe.ts',
98
- },
99
- ],
100
- },
101
- }
@@ -1,250 +0,0 @@
1
- import { resolve } from 'node:path'
2
-
3
- import ts from 'typescript'
4
-
5
- import { ROOT, configured, hosting } from '../../core/descend.ts'
6
- import { kind, readFileSync } from '../../integrations/disk.ts'
7
- import { OPENS } from '../../integrations/target.ts'
8
-
9
- import type { Slopnator } from '../slopnator.ts'
10
- import { here } from './sl_unthreaded.ts'
11
-
12
- const IMPORTED = 'import '
13
-
14
- const MADE = 'new '
15
-
16
- const RUNTIME = 'node:'
17
-
18
- const ANYWHERE = 'globalThis'
19
-
20
- const REQUIRED = 'require'
21
-
22
- const DECLARED = /\.d\.([cm]?)ts$/
23
-
24
- const READABLE = /\.(?:[cm]?[jt]s|[jt]sx)$/
25
-
26
- const plain = (specifier: string): string => (specifier.startsWith(RUNTIME) ? specifier.slice(RUNTIME.length) : specifier)
27
-
28
- interface Door {
29
- readonly reach: string
30
- readonly spelling: string
31
- }
32
-
33
- interface Doors {
34
- readonly modules: ReadonlyMap<string, Door>
35
- readonly globals: ReadonlyMap<string, Door>
36
- readonly properties: ReadonlyMap<string, Door>
37
- }
38
-
39
- function doors(): Doors {
40
- const modules = new Map<string, Door>()
41
- const globals = new Map<string, Door>()
42
- const properties = new Map<string, Door>()
43
- for (const [reach, spellings] of Object.entries(OPENS)) {
44
- for (const spelling of spellings) {
45
- const door = { reach, spelling }
46
- if (spelling.startsWith(IMPORTED)) {
47
- const rest = spelling.slice(IMPORTED.length)
48
- const dot = rest.lastIndexOf('.')
49
- modules.set(plain(dot === -1 || rest.slice(dot).includes('/') ? rest : rest.slice(0, dot)), door)
50
- continue
51
- }
52
- if (spelling.startsWith(MADE)) {
53
- globals.set(spelling.slice(MADE.length), door)
54
- continue
55
- }
56
- if (spelling.includes('.')) properties.set(spelling, door)
57
- else globals.set(spelling, door)
58
- }
59
- }
60
- return { modules, globals, properties }
61
- }
62
-
63
- const DOORS = doors()
64
-
65
- interface Brought {
66
- readonly specifier: string
67
- readonly line: number
68
- }
69
-
70
- const files = new Map<string, ts.SourceFile>()
71
-
72
- function parsed(at: string, text: string): ts.SourceFile {
73
- const held = files.get(text)
74
- if (held !== undefined) return held
75
- const file = ts.createSourceFile(at, text, ts.ScriptTarget.Latest, true, at.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS)
76
- files.set(text, file)
77
- return file
78
- }
79
-
80
- function brought(file: ts.SourceFile): readonly Brought[] {
81
- const found: Brought[] = []
82
- const line = (node: ts.Node): number => file.getLineAndCharacterOfPosition(node.getStart(file)).line + 1
83
- const visit = (node: ts.Node): void => {
84
- if (ts.isImportDeclaration(node) && node.importClause?.isTypeOnly !== true && ts.isStringLiteral(node.moduleSpecifier)) {
85
- found.push({ specifier: node.moduleSpecifier.text, line: line(node) })
86
- }
87
- if (ts.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && ts.isStringLiteral(node.moduleSpecifier)) {
88
- found.push({ specifier: node.moduleSpecifier.text, line: line(node) })
89
- }
90
- if (ts.isCallExpression(node)) {
91
- const first = node.arguments[0]
92
- const loads = node.expression.kind === ts.SyntaxKind.ImportKeyword || (ts.isIdentifier(node.expression) && node.expression.text === REQUIRED)
93
- if (loads && first !== undefined && ts.isStringLiteral(first)) found.push({ specifier: first.text, line: line(node) })
94
- }
95
- ts.forEachChild(node, visit)
96
- }
97
- visit(file)
98
- return found
99
- }
100
-
101
- const binds = (node: ts.Identifier): boolean => {
102
- const parent = node.parent
103
- return (
104
- (ts.isVariableDeclaration(parent) ||
105
- ts.isParameter(parent) ||
106
- ts.isBindingElement(parent) ||
107
- ts.isFunctionDeclaration(parent) ||
108
- ts.isClassDeclaration(parent) ||
109
- ts.isImportSpecifier(parent) ||
110
- ts.isImportClause(parent) ||
111
- ts.isNamespaceImport(parent)) &&
112
- parent.name === node
113
- )
114
- }
115
-
116
- const named = (node: ts.Node): boolean => (node.parent as { readonly name?: ts.Node } | undefined)?.name === node
117
-
118
- const opened = new Map<string, Door | undefined>()
119
-
120
- function opening(at: string, text: string): Door | undefined {
121
- if (opened.has(text)) return opened.get(text)
122
- const file = parsed(at, text)
123
- let found: Door | undefined
124
- for (const one of brought(file)) found ??= DOORS.modules.get(plain(one.specifier))
125
- const bound = new Set<string>()
126
- const collect = (node: ts.Node): void => {
127
- if (ts.isIdentifier(node) && binds(node)) bound.add(node.text)
128
- ts.forEachChild(node, collect)
129
- }
130
- collect(file)
131
- const visit = (node: ts.Node): void => {
132
- if (found !== undefined) return
133
- if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && !ts.isPartOfTypeNode(node)) {
134
- const object = node.expression.text
135
- found = DOORS.properties.get(object + '.' + node.name.text) ?? (object === ANYWHERE ? DOORS.globals.get(node.name.text) : undefined)
136
- }
137
- if (found === undefined && ts.isIdentifier(node) && !named(node) && !ts.isPartOfTypeNode(node) && !bound.has(node.text)) {
138
- found = DOORS.globals.get(node.text)
139
- }
140
- ts.forEachChild(node, visit)
141
- }
142
- visit(file)
143
- opened.set(text, found)
144
- return found
145
- }
146
-
147
- let options: ts.CompilerOptions | undefined
148
-
149
- let host: ts.CompilerHost | undefined
150
-
151
- function resolvedOf(specifier: string, from: string): string | undefined {
152
- options ??= configured().options
153
- host ??= hosting(options)
154
- const found = ts.resolveModuleName(specifier, from, options, host).resolvedModule
155
- if (found === undefined) return undefined
156
- const at = found.resolvedFileName
157
- if (!DECLARED.test(at)) return at
158
- const emitted = at.replace(DECLARED, '.$1js')
159
- return kind(emitted) === 'file' ? emitted : undefined
160
- }
161
-
162
- const readable = (at: string): string | undefined => (READABLE.test(at) && kind(at) === 'file' ? readFileSync(at, 'utf8') : undefined)
163
-
164
- const shown = (chain: readonly string[], door: Door): string =>
165
- chain.map((one) => '`' + one + '`').join(', which imports ') +
166
- (door.spelling.startsWith(IMPORTED) ? ', which imports ' + door.spelling.slice(IMPORTED.length) : ', which reaches ' + door.spelling) +
167
- ' — the ' +
168
- door.reach +
169
- ' reach, and no target declares it. Nothing prices that reach, replays it in a trial or refuses it. Declare the place with `thread create target`, require it on the operation, and call what the node is handed instead'
170
-
171
- function through(at: string, chain: readonly string[], seen: Set<string>): string | undefined {
172
- const text = readable(at)
173
- if (text === undefined) return undefined
174
- const door = opening(at, text)
175
- if (door !== undefined) return shown(chain, door)
176
- for (const one of brought(parsed(at, text))) {
177
- const next = resolvedOf(one.specifier, at)
178
- if (next === undefined || seen.has(next)) continue
179
- seen.add(next)
180
- const found = through(next, [...chain, one.specifier], seen)
181
- if (found !== undefined) return found
182
- }
183
- return undefined
184
- }
185
-
186
- export const slopnator: Slopnator = {
187
- holds: (_node, at) => {
188
- const path = here(at.filename)
189
- if (!READABLE.test(path)) return false
190
- const from = resolve(ROOT, path)
191
- const seen = new Set<string>([from])
192
- for (const one of brought(parsed(from, at.text))) {
193
- const next = resolvedOf(one.specifier, from)
194
- if (next === undefined || seen.has(next)) continue
195
- seen.add(next)
196
- const found = through(next, [one.specifier], seen)
197
- if (found !== undefined) return 'line ' + String(one.line) + ': imports ' + found
198
- }
199
- return false
200
- },
201
- proves: {
202
- wrong: [
203
- {
204
- files: [
205
- { at: 'thread/integrations/cli.ts', source: "import { spawn } from 'node:child_process'\n\nexport const starts = (program: string): void => {\n spawn(program)\n}\n" },
206
- { at: 'operations/_probe_node.ts', source: "export { starts } from '../thread/integrations/cli.ts'\n" },
207
- ],
208
- at: 'operations/_probe_node.ts',
209
- },
210
- {
211
- files: [
212
- { at: 'thread/integrations/https.ts', source: "export const sendingHttp = async (address: string): Promise<number> => (await fetch(address)).status\n" },
213
- { at: 'src/_probe_helper.ts', source: "import { sendingHttp } from '../thread/integrations/https.ts'\n\nexport const status = (address: string): Promise<number> => sendingHttp(address)\n" },
214
- { at: 'operations/_probe_node.ts', source: "import { status } from '../src/_probe_helper.ts'\n\nexport const node = (address: string): Promise<number> => status(address)\n" },
215
- ],
216
- at: 'operations/_probe_node.ts',
217
- },
218
- {
219
- files: [
220
- { at: 'thread/integrations/disk.ts', source: "import * as disk from 'node:fs'\n\nexport const read = (at: string): string => disk.readFileSync(at, 'utf8')\n" },
221
- { at: 'operations/_probe_node.ts', source: "export const node = async (at: string): Promise<string> => (await import('../thread/integrations/disk.ts')).read(at)\n" },
222
- ],
223
- at: 'operations/_probe_node.ts',
224
- },
225
- ],
226
- right: [
227
- {
228
- files: [
229
- { at: 'thread/operations/nodes.ts', source: "export const nd_action = <T>(run: T): T => run\n" },
230
- { at: 'operations/_probe_node.ts', source: "import { nd_action } from '../thread/operations/nodes.ts'\n\nexport const node = nd_action(async () => 1)\n" },
231
- ],
232
- at: 'operations/_probe_node.ts',
233
- },
234
- {
235
- files: [
236
- { at: 'thread/integrations/cli.ts', source: "import { spawn } from 'node:child_process'\n\nexport interface Ran {\n readonly out: string\n}\n\nexport const starts = (program: string): void => {\n spawn(program)\n}\n" },
237
- { at: 'operations/_probe_node.ts', source: "import type { Ran } from '../thread/integrations/cli.ts'\n\nexport const node = (ran: Ran): string => ran.out\n" },
238
- ],
239
- at: 'operations/_probe_node.ts',
240
- },
241
- {
242
- files: [
243
- { at: 'src/_probe_helper.ts', source: "const fetch = (said: string): string => said\n\nexport const shout = (said: string): string => fetch(said).toUpperCase()\n" },
244
- { at: 'operations/_probe_node.ts', source: "import { shout } from '../src/_probe_helper.ts'\n\nexport const node = (): string => shout('a')\n" },
245
- ],
246
- at: 'operations/_probe_node.ts',
247
- },
248
- ],
249
- },
250
- }
@@ -1,55 +0,0 @@
1
- import ts from 'typescript'
2
-
3
-
4
- import type { Slopnator } from '../slopnator.ts'
5
-
6
- const ALONE = /^\s*([a-z][a-z0-9]*(?:-[a-z0-9]+)*)\s*:\s*([^;{}\n]+);\s*$/
7
-
8
- const NAMED = /var\(\s*--/
9
-
10
- const PIECES = new Set([
11
- ts.SyntaxKind.StringLiteral,
12
- ts.SyntaxKind.NoSubstitutionTemplateLiteral,
13
- ts.SyntaxKind.TemplateHead,
14
- ts.SyntaxKind.TemplateMiddle,
15
- ts.SyntaxKind.TemplateTail,
16
- ])
17
-
18
- export const slopnator: Slopnator = {
19
- holds: (_node, at) => {
20
- const scanner = ts.createScanner(ts.ScriptTarget.Latest, false, ts.LanguageVariant.JSX, at.text)
21
- let token = scanner.scan()
22
- while (token !== ts.SyntaxKind.EndOfFileToken) {
23
- if (PIECES.has(token)) {
24
- const said = scanner.getTokenValue()
25
- const found = ALONE.exec(said)
26
- if (found !== null) {
27
- const property = found[1] ?? ''
28
- const value = (found[2] ?? '').trim()
29
- if (value !== '' && !NAMED.test(value)) {
30
- return (
31
- `\`${property}\` is written into the compiler with \`${value}\` typed into it, so a ` +
32
- 'stylesheet carries a decision nothing declared — no rebrand moves it, no mode or theme reaches it, and no sheet knows it is there'
33
- )
34
- }
35
- }
36
- }
37
- token = scanner.scan()
38
- }
39
- return false
40
- },
41
- proves: {
42
- wrong: [
43
- "lines.push(' body {', ' background: #f8fbfa;', ' }')",
44
- "classes.push(' padding: 8px 16px;')",
45
- "return [' :where(*) {', ' text-box-trim: trim-both;', ' }']",
46
- "held.push(' color-scheme: light dark;')",
47
- ],
48
- right: [
49
- "lines.push(' body {', ' background: var(--colour-page);', ' }')",
50
- 'lines.push(...block(selector, made, indent))',
51
- 'held.push(` ${nameOf(id)}: ${made[id] ?? String()};`)',
52
- 'const held: readonly string[] = [];',
53
- ],
54
- },
55
- }
@@ -1,84 +0,0 @@
1
- import { existsSync, readFileSync } from '../../integrations/disk.ts'
2
- import { resolve } from 'node:path'
3
-
4
- import type { Slopnator } from '../slopnator.ts'
5
- import { declaresIsland, here, rowsIn } from './sl_unthreaded.ts'
6
- import { findTree } from '../../core/tree.ts'
7
-
8
- const ROOT = findTree().at
9
- const TREE = `${findTree().name}/`
10
-
11
- function schemaAt(at: string): string | undefined {
12
- const path = resolve(ROOT, at)
13
- if (!existsSync(path)) return undefined
14
- try {
15
- return declaresIsland(readFileSync(path, 'utf8'))
16
- } catch {
17
- return undefined
18
- }
19
- }
20
-
21
- export const slopnator: Slopnator = {
22
- holds: (_node, at) => {
23
- const path = here(at.filename)
24
- if (!path.startsWith(TREE)) return false
25
-
26
- let rows
27
- try {
28
- rows = rowsIn(at.text)
29
- } catch {
30
- return 'this file cannot be parsed, so the islands it declares were never read and nothing about what they govern was measured'
31
- }
32
-
33
- for (const row of rows) {
34
- if (row.at === undefined || row.id === undefined) continue
35
- const schema = schemaAt(row.at)
36
- if (schema === undefined) continue
37
- if ((row.governs ?? []).length > 0) continue
38
- return (
39
- `island "${row.id}" states nothing it governs, so ${schema}IslandSchema is a shape nothing is held to — ` +
40
- 'no file is the place its kind is declared, which makes every file the place, and the island is inert'
41
- )
42
- }
43
-
44
- return false
45
- },
46
- proves: {
47
- wrong: [
48
- {
49
- files: [
50
- { at: 'threads/_inert_probe.ts', source: "export const M: Threaded = {\n declares: [\n { id: 'entities', at: 'src/islands/entities.ts' },\n ],\n}\n" },
51
- { at: 'src/islands/entities.ts', source: 'export const EntitiesIslandSchema = {}\n' },
52
- ],
53
- at: 'threads/_inert_probe.ts',
54
- },
55
- {
56
- files: [
57
- { at: 'threads/_inert_probe.ts', source: "export const M: Threaded = {\n declares: [\n { id: 'events', at: 'src/islands/events.ts', governs: [] },\n ],\n}\n" },
58
- { at: 'src/islands/events.ts', source: 'export const EventsIslandSchema = {}\n' },
59
- ],
60
- at: 'threads/_inert_probe.ts',
61
- },
62
- ],
63
- right: [
64
- {
65
- files: [
66
- { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly governs?: readonly string[]\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
67
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_inert_probe.ts',\n },\n ],\n}\n" },
68
- { at: 'threads/_inert_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n { id: 'events', at: 'src/islands/events.ts', governs: ['app/_declare/events.ts'] },\n ],\n}\n" },
69
- { at: 'src/islands/events.ts', source: 'export const EventsIslandSchema = {}\n' },
70
- ],
71
- at: 'threads/_inert_probe.ts',
72
- },
73
- {
74
- files: [
75
- { 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" },
76
- { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_inert_probe.ts',\n },\n ],\n}\n" },
77
- { at: 'threads/_inert_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n { id: 'a-file', at: 'threads/_plain.ts' },\n ],\n}\n" },
78
- { at: 'threads/_plain.ts', source: 'export const PLAIN = 1\n' },
79
- ],
80
- at: 'threads/_inert_probe.ts',
81
- },
82
- ],
83
- },
84
- }
@@ -1,93 +0,0 @@
1
- import type { Slopnator } from '../slopnator.ts'
2
-
3
- interface Node {
4
- readonly type?: string
5
- readonly name?: string
6
- readonly key?: { readonly name?: string; readonly value?: unknown }
7
- readonly value?: unknown
8
- readonly body?: unknown
9
- readonly properties?: readonly Node[]
10
- readonly elements?: readonly unknown[]
11
- }
12
-
13
- const keyOf = (node: Node): string | undefined =>
14
- node.key?.name ?? (typeof node.key?.value === 'string' ? node.key.value : undefined)
15
-
16
- const answersUnwritten = (held: unknown): boolean => {
17
- const fn = held as { type?: string; body?: { type?: string; name?: string } } | undefined
18
- if (fn?.type !== 'ArrowFunctionExpression') return false
19
- return fn.body?.type === 'Identifier' && fn.body.name === 'NOT_WRITTEN'
20
- }
21
-
22
- const statesNothing = (held: unknown): boolean => {
23
- const proves = held as Node | undefined
24
- if (proves?.type !== 'ObjectExpression') return false
25
- return (proves.properties ?? []).some((one) => {
26
- const key = keyOf(one)
27
- if (key !== 'wrong' && key !== 'right') return false
28
- const list = one.value as Node | undefined
29
- return list?.type === 'ArrayExpression' && (list.elements ?? []).length === 0
30
- })
31
- }
32
-
33
- export const slopnator: Slopnator = {
34
- on: ['Property'],
35
- holds: (node) => {
36
- const held = node as Node
37
- const key = keyOf(held)
38
-
39
- if (key === 'holds' && answersUnwritten(held.value)) {
40
- return 'this is still the scaffold — it answers `NOT_WRITTEN` to everything, so the rule that names it registers, loads, reports nothing, and reads from outside exactly like a rule being obeyed'
41
- }
42
-
43
- if (key === 'on') {
44
- const list = held.value as Node | undefined
45
- if (list?.type === 'ArrayExpression' && (list.elements ?? []).length === 0) {
46
- return 'it says it visits syntax and then names no node type, so it is handed nothing and governs nothing inside the files its rule governs'
47
- }
48
- }
49
-
50
- if (key === 'proves' && statesNothing(held.value)) {
51
- return 'its `proves` states nothing — with no form it refuses and none it accepts, no trial is derived from it, so nothing anywhere shows the slopnator does what its row claims'
52
- }
53
-
54
- return false
55
- },
56
- proves: {
57
- wrong: [
58
- {
59
- files: [
60
- {
61
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
62
- source: 'export const slopnator = {\n on: [],\n holds: () => NOT_WRITTEN,\n proves: { wrong: [], right: [] },\n}\n',
63
- },
64
- ],
65
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
66
- },
67
- {
68
- files: [
69
- {
70
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
71
- source: "export const slopnator = {\n holds: (_node, at) => at.text.includes('nope') && 'found',\n proves: { wrong: [], right: ['const held = 1'] },\n}\n",
72
- },
73
- ],
74
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
75
- },
76
- ],
77
- right: [
78
- {
79
- files: [
80
- {
81
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
82
- source: "export const slopnator = {\n holds: (_node, at) => at.text.includes('nope') && 'found',\n proves: { wrong: ['nope'], right: ['const held = 1'] },\n}\n",
83
- },
84
- ],
85
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
86
- },
87
- {
88
- files: [{ at: 'thread/integrity/slopnators/sl_probe_inert.ts', source: 'export const held = 1\n' }],
89
- at: 'thread/integrity/slopnators/sl_probe_inert.ts',
90
- },
91
- ],
92
- },
93
- }