@prestack/thread 0.1.20 → 0.1.22

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 (148) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/attach.js +21 -0
  3. package/dist/core/descend.d.ts +2 -0
  4. package/dist/core/descend.js +18 -3
  5. package/dist/core/generators/commit.js +55 -3
  6. package/dist/core/generators/dev.d.ts +1 -0
  7. package/dist/core/generators/dev.js +68 -0
  8. package/dist/core/rows.d.ts +5 -0
  9. package/dist/core/rows.js +45 -0
  10. package/dist/core/tree.d.ts +1 -0
  11. package/dist/core/tree.js +7 -1
  12. package/dist/derivation/generators/build.d.ts +3 -1
  13. package/dist/derivation/generators/build.js +103 -22
  14. package/dist/derivation/generators/release.js +74 -26
  15. package/dist/derivation/release.js +3 -3
  16. package/dist/integrations/cli.d.ts +3 -9
  17. package/dist/integrations/cli.js +96 -36
  18. package/dist/integrations/declared.d.ts +8 -0
  19. package/dist/integrations/declared.js +22 -0
  20. package/dist/integrations/pglite.js +13 -3
  21. package/dist/integrations/target.d.ts +4 -1
  22. package/dist/integrations/target.js +20 -6
  23. package/dist/integrity/attach.js +1 -5
  24. package/dist/integrity/generators/publish.js +2 -1
  25. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  26. package/dist/integrity/slopnators/sl_unlisted_program.js +2 -2
  27. package/dist/operations/access.js +3 -2
  28. package/dist/operations/capabilities.d.ts +2 -0
  29. package/dist/operations/capabilities.js +2 -0
  30. package/dist/operations/generators/capability.js +234 -24
  31. package/dist/operations/generators/compile.d.ts +21 -0
  32. package/dist/operations/generators/compile.js +151 -51
  33. package/dist/operations/generators/permits.d.ts +2 -1
  34. package/dist/operations/generators/permits.js +52 -47
  35. package/dist/operations/generators/seed.d.ts +3 -0
  36. package/dist/operations/generators/seed.js +25 -3
  37. package/dist/operations/nodes.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/dist/core/actor.ts +0 -21
  40. package/dist/core/attach.ts +0 -613
  41. package/dist/core/chain.ts +0 -145
  42. package/dist/core/condition.ts +0 -227
  43. package/dist/core/descend.ts +0 -1173
  44. package/dist/core/errors/catalogue.ts +0 -314
  45. package/dist/core/errors/classes.ts +0 -51
  46. package/dist/core/errors/error.ts +0 -152
  47. package/dist/core/errors/namespaces.ts +0 -19
  48. package/dist/core/finding.ts +0 -37
  49. package/dist/core/generators/commit.ts +0 -157
  50. package/dist/core/init.ts +0 -222
  51. package/dist/core/invoked.ts +0 -52
  52. package/dist/core/round.ts +0 -74
  53. package/dist/core/rows.ts +0 -459
  54. package/dist/core/scope.ts +0 -20
  55. package/dist/core/thread.ts +0 -29
  56. package/dist/core/tree.ts +0 -90
  57. package/dist/core/types.ts +0 -351
  58. package/dist/derivation/attach.ts +0 -57
  59. package/dist/derivation/generators/build.ts +0 -371
  60. package/dist/derivation/generators/check.ts +0 -118
  61. package/dist/derivation/generators/determinism.ts +0 -145
  62. package/dist/derivation/generators/release.ts +0 -236
  63. package/dist/derivation/release.ts +0 -43
  64. package/dist/integrations/attach.ts +0 -187
  65. package/dist/integrations/cli.ts +0 -615
  66. package/dist/integrations/disk.ts +0 -466
  67. package/dist/integrations/generators/read.ts +0 -127
  68. package/dist/integrations/generators/vault.ts +0 -210
  69. package/dist/integrations/https.ts +0 -216
  70. package/dist/integrations/pglite.ts +0 -206
  71. package/dist/integrations/secret.ts +0 -54
  72. package/dist/integrations/target.ts +0 -656
  73. package/dist/integrations/vault.ts +0 -148
  74. package/dist/integrity/attach.ts +0 -150
  75. package/dist/integrity/check-threads.ts +0 -166
  76. package/dist/integrity/constraint.ts +0 -1246
  77. package/dist/integrity/generators/compiler.ts +0 -138
  78. package/dist/integrity/generators/gate.ts +0 -227
  79. package/dist/integrity/generators/issues.ts +0 -160
  80. package/dist/integrity/generators/publish.ts +0 -232
  81. package/dist/integrity/generators/trial.ts +0 -359
  82. package/dist/integrity/lint.ts +0 -214
  83. package/dist/integrity/lsp/bin.ts +0 -44
  84. package/dist/integrity/lsp/diagnostics.ts +0 -92
  85. package/dist/integrity/lsp/findings.ts +0 -63
  86. package/dist/integrity/lsp/lint.ts +0 -124
  87. package/dist/integrity/lsp/protocol.ts +0 -78
  88. package/dist/integrity/lsp/server.ts +0 -224
  89. package/dist/integrity/slopnator.ts +0 -324
  90. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  91. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  92. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  93. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  94. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  95. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  96. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  97. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  98. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  99. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  100. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  101. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  102. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  103. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  104. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  105. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  106. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  107. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  108. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  109. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  110. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  111. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  112. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  113. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  114. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  115. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  116. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  117. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  118. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  119. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  120. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  121. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  122. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  123. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  124. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  125. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  126. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  127. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  128. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  129. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  130. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  131. package/dist/integrity/sweep.ts +0 -395
  132. package/dist/knowledge/attach.ts +0 -327
  133. package/dist/knowledge/generators/docsgen.ts +0 -186
  134. package/dist/knowledge/generators/glossary.ts +0 -73
  135. package/dist/knowledge/glossary.ts +0 -6
  136. package/dist/operations/access.ts +0 -131
  137. package/dist/operations/attach.ts +0 -408
  138. package/dist/operations/capabilities.ts +0 -88
  139. package/dist/operations/dispatch.ts +0 -294
  140. package/dist/operations/error-results.ts +0 -31
  141. package/dist/operations/generators/capability.ts +0 -1054
  142. package/dist/operations/generators/compile.ts +0 -701
  143. package/dist/operations/generators/permits.ts +0 -224
  144. package/dist/operations/generators/seed.ts +0 -359
  145. package/dist/operations/generators/trial.ts +0 -666
  146. package/dist/operations/nodes.ts +0 -53
  147. package/dist/operations/operations.ts +0 -91
  148. package/dist/operations/result.ts +0 -28
package/dist/core/rows.ts DELETED
@@ -1,459 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
-
3
- import ts from 'typescript'
4
-
5
- export interface Bounds {
6
- readonly open: number
7
- readonly close: number
8
- }
9
-
10
- const PARSED = new Map<string, ts.SourceFile>()
11
-
12
- function tree(text: string): ts.SourceFile {
13
- const held = PARSED.get(text)
14
- if (held !== undefined) return held
15
- const made = ts.createSourceFile('rows.ts', text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
16
- if (PARSED.size > 8) PARSED.clear()
17
- PARSED.set(text, made)
18
- return made
19
- }
20
-
21
- function walk(node: ts.Node, seen: (one: ts.Node) => void): void {
22
- seen(node)
23
- ts.forEachChild(node, (one) => {
24
- walk(one, seen)
25
- })
26
- }
27
-
28
- const keyed = (one: ts.PropertyAssignment): string | undefined =>
29
- ts.isIdentifier(one.name) || ts.isStringLiteral(one.name) ? one.name.text : undefined
30
-
31
- function stringy(node: ts.ObjectLiteralExpression, name: string): string | undefined {
32
- for (const one of node.properties) {
33
- if (!ts.isPropertyAssignment(one) || keyed(one) !== name) continue
34
- return ts.isStringLiteral(one.initializer) ? one.initializer.text : undefined
35
- }
36
- return undefined
37
- }
38
-
39
- function listy(node: ts.ObjectLiteralExpression, name: string): ts.ArrayLiteralExpression | undefined {
40
- for (const one of node.properties) {
41
- if (!ts.isPropertyAssignment(one) || keyed(one) !== name) continue
42
- return ts.isArrayLiteralExpression(one.initializer) ? one.initializer : undefined
43
- }
44
- return undefined
45
- }
46
-
47
- const spanned = (node: ts.Node): { readonly open: number; readonly close: number } => ({
48
- open: node.getStart(),
49
- close: node.getEnd() - 1,
50
- })
51
-
52
- export function inCode(text: string): readonly boolean[] {
53
- const held = new Array<boolean>(text.length).fill(true)
54
- let cursor = 0
55
- while (cursor < text.length) {
56
- const one = text[cursor]
57
- const next = text[cursor + 1]
58
- if (one === '/' && next === '/') {
59
- while (cursor < text.length && text[cursor] !== '\n') held[cursor++] = false
60
- continue
61
- }
62
- if (one === '/' && next === '*') {
63
- held[cursor++] = false
64
- held[cursor++] = false
65
- while (cursor < text.length && !(text[cursor] === '*' && text[cursor + 1] === '/')) held[cursor++] = false
66
- held[cursor++] = false
67
- held[cursor++] = false
68
- continue
69
- }
70
- if (one === "'" || one === '"' || one === '`') {
71
- held[cursor++] = false
72
- while (cursor < text.length && text[cursor] !== one) {
73
- if (text[cursor] === '\\') held[cursor++] = false
74
- held[cursor++] = false
75
- }
76
- held[cursor++] = false
77
- continue
78
- }
79
- cursor += 1
80
- }
81
- return held
82
- }
83
-
84
- export function matched(text: string, code: readonly boolean[], from: number, open: string, close: string): number {
85
- let depth = 0
86
- for (let cursor = from; cursor < text.length; cursor += 1) {
87
- if (code[cursor] !== true) continue
88
- if (text[cursor] === open) depth += 1
89
- if (text[cursor] === close) {
90
- depth -= 1
91
- if (depth === 0) return cursor
92
- }
93
- }
94
- return -1
95
- }
96
-
97
- export function listBounds(text: string, list: string): Bounds | undefined {
98
- const file = tree(text)
99
-
100
- let found: ts.ArrayLiteralExpression | undefined
101
- let held: ts.ObjectLiteralExpression | undefined
102
-
103
- walk(file, (node) => {
104
- if (found !== undefined || !ts.isVariableDeclaration(node) || node.initializer === undefined) return
105
-
106
- const unwrapped = (node2: ts.Expression): ts.Expression =>
107
- ts.isAsExpression(node2) || ts.isSatisfiesExpression(node2) ? unwrapped(node2.expression) : node2
108
- const one = unwrapped(node.initializer)
109
- if (ts.isIdentifier(node.name) && node.name.text === list && ts.isArrayLiteralExpression(one)) {
110
- found = one
111
- return
112
- }
113
- if (held === undefined && ts.isObjectLiteralExpression(one)) held = one
114
- })
115
-
116
- if (found !== undefined) return spanned(found)
117
- if (held === undefined) return undefined
118
- const inside = listy(held, list)
119
- return inside === undefined ? undefined : spanned(inside)
120
- }
121
-
122
- export function nestedBounds(text: string, where: Bounds, parent: string, list: string): Bounds | undefined {
123
- const row = rowAt(text, where, parent)
124
- if (row === undefined) return undefined
125
- const inside = listy(row, list)
126
- return inside === undefined ? undefined : spanned(inside)
127
- }
128
-
129
- function elements(text: string, where: Bounds): readonly ts.ObjectLiteralExpression[] {
130
- let found: ts.ArrayLiteralExpression | undefined
131
- walk(tree(text), (node) => {
132
- if (found !== undefined) return
133
- if (ts.isArrayLiteralExpression(node) && node.getStart() === where.open && node.getEnd() - 1 === where.close) {
134
- found = node
135
- }
136
- })
137
- if (found === undefined) return []
138
- return found.elements.filter((one): one is ts.ObjectLiteralExpression => ts.isObjectLiteralExpression(one))
139
- }
140
-
141
- function rowAt(text: string, where: Bounds, id: string): ts.ObjectLiteralExpression | undefined {
142
- return elements(text, where).find((one) => stringy(one, 'id') === id)
143
- }
144
-
145
- export function holdsRow(text: string, where: Bounds, id: string): boolean {
146
- return rowAt(text, where, id) !== undefined
147
- }
148
-
149
- export function seededAt(text: string, where: Bounds, id: string): string | undefined {
150
- const held = rowAt(text, where, id)
151
- if (held === undefined) return undefined
152
- const seeds = listy(held, 'seeds')
153
- const derives = listy(held, 'derives')
154
- if (seeds !== undefined && derives !== undefined) return undefined
155
- const first = (seeds ?? derives)?.elements[0]
156
- if (first === undefined || !ts.isObjectLiteralExpression(first)) return undefined
157
- return stringy(first, 'at')
158
- }
159
-
160
- export function rowsIn(
161
- text: string,
162
- where: Bounds,
163
- ): readonly { readonly id: string; readonly at: string | undefined; readonly source: string }[] {
164
- const found: { id: string; at: string | undefined; source: string }[] = []
165
- for (const one of elements(text, where)) {
166
- const id = stringy(one, 'id')
167
- if (id === undefined) continue
168
-
169
- const at = stringy(one, 'at')
170
- const from = one.getStart()
171
- const line = text.lastIndexOf('\n', from) + 1
172
- const pad = text.slice(line, from)
173
- found.push({ id, at, source: `${/^[ \t]*$/.test(pad) ? pad : ''}${text.slice(from, one.getEnd())},` })
174
- }
175
- return found
176
- }
177
-
178
- export function withRow(text: string, where: Bounds, row: string): string {
179
- const held = /[ \t]*$/.exec(text.slice(0, where.close))?.[0] ?? ''
180
- const before = text.slice(0, where.close - held.length)
181
- const empty = before.trimEnd().endsWith('[')
182
- const line = text.lastIndexOf('\n', where.open)
183
- const pad = empty ? (/^[ \t]*/.exec(text.slice(line + 1))?.[0] ?? '') : held
184
- return `${before}${empty ? '\n' : ''}${row}\n${pad}${text.slice(where.close)}`
185
- }
186
-
187
- export function withSeed(text: string, where: Bounds, id: string, seed: string): string {
188
- const held = rowAt(text, where, id)
189
- if (held === undefined) return text
190
- if (listy(held, 'seeds') !== undefined) return text
191
-
192
- const to = held.getEnd() - 1
193
- const line = text.lastIndexOf('\n', held.getStart())
194
- const pad = /^[ \t]*/.exec(text.slice(line + 1))?.[0] ?? ' '
195
- const before = text.slice(0, to).trimEnd()
196
- const comma = before.endsWith(',') ? '' : ','
197
- return `${before}${comma}\n${pad} seeds: [\n${seed}\n${pad} ],\n${pad}${text.slice(to)}`
198
- }
199
-
200
- export function withRequires(text: string, where: Bounds, id: string, requires: readonly string[]): string | undefined {
201
- const held = rowAt(text, where, id)
202
- if (held === undefined) return undefined
203
-
204
- const line = text.lastIndexOf('\n', held.getStart()) + 1
205
- const pad = `${/^[ \t]*/.exec(text.slice(line))?.[0] ?? ' '} `
206
- const written = requires.length === 0 ? '' : `${pad}requires: [${requires.map((one) => `'${one}'`).join(', ')}],\n`
207
-
208
- const propertyNamed = (name: string): ts.PropertyAssignment | undefined => {
209
- for (const one of held.properties) {
210
- if (ts.isPropertyAssignment(one) && keyed(one) === name) return one
211
- }
212
- return undefined
213
- }
214
-
215
- const already = propertyNamed('requires')
216
- if (already !== undefined) {
217
- const opens = text.lastIndexOf('\n', already.getStart()) + 1
218
- const shut = text.indexOf('\n', already.getEnd())
219
- return `${text.slice(0, opens)}${written}${text.slice(shut === -1 ? text.length : shut + 1)}`
220
- }
221
-
222
- const version = propertyNamed('version')
223
- if (version === undefined) return undefined
224
- const after = text.indexOf('\n', version.getEnd())
225
- const at = after === -1 ? text.length : after + 1
226
- return `${text.slice(0, at)}${written}${text.slice(at)}`
227
- }
228
-
229
- export function seedsIn(text: string, where: Bounds, id: string): Bounds | undefined {
230
- const held = rowAt(text, where, id)
231
- if (held === undefined) return undefined
232
- const list = listy(held, 'seeds')
233
- return list === undefined ? undefined : spanned(list)
234
- }
235
-
236
- export function afterRow(text: string, where: Bounds, follows: string, row: string): string | undefined {
237
- const held = rowAt(text, where, follows)
238
- if (held === undefined) return undefined
239
- let to = held.getEnd()
240
- if (text[to] === ',') to += 1
241
- return `${text.slice(0, to)}\n${row}${text.slice(to)}`
242
- }
243
-
244
- function headed(text: string): ts.ObjectLiteralExpression | undefined {
245
- let found: ts.ObjectLiteralExpression | undefined
246
- walk(tree(text), (node) => {
247
- if (found !== undefined || !ts.isVariableDeclaration(node) || node.initializer === undefined) return
248
- const one = ts.isAsExpression(node.initializer) ? node.initializer.expression : node.initializer
249
- if (ts.isObjectLiteralExpression(one)) found = one
250
- })
251
- return found
252
- }
253
-
254
- function stated(node: ts.ObjectLiteralExpression, field: string): Bounds | undefined {
255
- for (const one of node.properties) {
256
- if (!ts.isPropertyAssignment(one) || keyed(one) !== field) continue
257
- return { open: one.initializer.getStart(), close: one.initializer.getEnd() }
258
- }
259
- return undefined
260
- }
261
-
262
- export const quoted = (one: string): string => `'${one.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\n/g, '\\n')}'`
263
-
264
- const UNREAD = Symbol.for('thread.unread')
265
-
266
- function valued(node: ts.Expression): unknown {
267
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text
268
- if (ts.isNumericLiteral(node)) return Number(node.text)
269
- if (node.kind === ts.SyntaxKind.TrueKeyword) return true
270
- if (node.kind === ts.SyntaxKind.FalseKeyword) return false
271
- if (node.kind === ts.SyntaxKind.NullKeyword) return null
272
- if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isParenthesizedExpression(node)) return valued(node.expression)
273
- if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken) {
274
- const held = valued(node.operand)
275
- return typeof held === 'number' ? -held : UNREAD
276
- }
277
- if (ts.isArrayLiteralExpression(node)) {
278
- const held: unknown[] = []
279
- for (const one of node.elements) {
280
- const each = valued(one)
281
- if (each === UNREAD) return UNREAD
282
- held.push(each)
283
- }
284
- return held
285
- }
286
- if (ts.isObjectLiteralExpression(node)) {
287
- const held: Record<string, unknown> = {}
288
- for (const one of node.properties) {
289
- if (!ts.isPropertyAssignment(one)) return UNREAD
290
- const key = keyed(one)
291
- if (key === undefined) return UNREAD
292
- const each = valued(one.initializer)
293
- if (each === UNREAD) return UNREAD
294
- held[key] = each
295
- }
296
- return held
297
- }
298
- return UNREAD
299
- }
300
-
301
- function taken(text: string): readonly (readonly [string, unknown])[] {
302
- const found: (readonly [string, unknown])[] = []
303
- walk(tree(text), (node) => {
304
- if (!ts.isVariableDeclaration(node) || node.initializer === undefined || !ts.isIdentifier(node.name)) return
305
- found.push([node.name.text, valued(node.initializer)])
306
- })
307
- return found
308
- }
309
-
310
- export function valuesIn(text: string): Readonly<Record<string, unknown>> {
311
- const found: Record<string, unknown> = {}
312
- for (const [name, held] of taken(text)) {
313
- if (held !== UNREAD) found[name] = held
314
- }
315
- return found
316
- }
317
-
318
- export function unread(text: string): readonly string[] {
319
- return taken(text).filter(([, held]) => held === UNREAD).map(([name]) => name)
320
- }
321
-
322
- export const STATED = ['at', 'describes', 'version']
323
-
324
- export function reconciled(held: string, source: string, fields: readonly string[]): string {
325
- const ships = headed(source)
326
- if (ships === undefined) return held
327
- const named = stringy(ships, 'id')
328
-
329
- let next = held
330
- for (const field of fields) {
331
- const want = stated(ships, field)
332
- if (want === undefined) continue
333
-
334
- const mine = headed(next)
335
- if (mine === undefined || stringy(mine, 'id') !== named) return held
336
- const have = stated(mine, field)
337
- if (have === undefined) continue
338
- const said = source.slice(want.open, want.close)
339
- if (next.slice(have.open, have.close) === said) continue
340
- next = next.slice(0, have.open) + said + next.slice(have.close)
341
- }
342
- return next
343
- }
344
-
345
- export function fieldIn(text: string, where: Bounds, id: string, field: string): string | undefined {
346
- const held = rowAt(text, where, id)
347
- if (held === undefined) return undefined
348
- for (const one of held.properties) {
349
- if (!ts.isPropertyAssignment(one) || keyed(one) !== field) continue
350
- return text.slice(one.initializer.getStart(), one.initializer.getEnd())
351
- }
352
- return undefined
353
- }
354
-
355
- export function withField(
356
- text: string,
357
- where: Bounds,
358
- id: string,
359
- field: string,
360
- value: string,
361
- ): string | undefined {
362
- const held = rowAt(text, where, id)
363
- return held === undefined ? undefined : fieldOn(text, held, field, value)
364
- }
365
-
366
- export function withTopField(text: string, field: string, value: string): string | undefined {
367
- const held = headed(text)
368
- return held === undefined ? undefined : fieldOn(text, held, field, value)
369
- }
370
-
371
- export function withoutField(text: string, where: Bounds, id: string, field: string): string {
372
- const held = rowAt(text, where, id)
373
- const one = held?.properties.find((each) => ts.isPropertyAssignment(each) && keyed(each) === field)
374
- if (held === undefined || one === undefined) return text
375
- let ends = one.getEnd()
376
- if (text[ends] === ',') ends += 1
377
- const line = text.lastIndexOf('\n', one.getStart())
378
- if (line > held.getStart()) return text.slice(0, line) + text.slice(ends)
379
- return text.slice(0, one.getStart()) + text.slice(text[ends] === ' ' ? ends + 1 : ends)
380
- }
381
-
382
- function fieldOn(text: string, held: ts.ObjectLiteralExpression, field: string, value: string): string | undefined {
383
- for (const one of held.properties) {
384
- if (!ts.isPropertyAssignment(one) || keyed(one) !== field) continue
385
- return `${text.slice(0, one.initializer.getStart())}${value}${text.slice(one.initializer.getEnd())}`
386
- }
387
-
388
- const last = held.properties.at(-1)
389
- if (last === undefined) return undefined
390
-
391
- let ends = last.getEnd()
392
- if (text[ends] === ',') ends += 1
393
- const already = text[ends - 1] === ',' ? '' : ','
394
-
395
- if (!text.slice(held.getStart(), held.getEnd()).includes('\n')) {
396
- return `${text.slice(0, ends)}${already} ${field}: ${value}${text.slice(ends)}`
397
- }
398
-
399
- const line = text.lastIndexOf('\n', last.getStart()) + 1
400
- const pad = /^[ \t]*/.exec(text.slice(line))?.[0] ?? ' '
401
- return `${text.slice(0, ends)}${already}\n${pad}${field}: ${value},${text.slice(ends)}`
402
- }
403
-
404
- export function withoutRow(text: string, where: Bounds, id: string): string {
405
- const held = rowAt(text, where, id)
406
- if (held === undefined) return text
407
- let ends = held.getEnd()
408
- if (text[ends] === ',') ends += 1
409
- const pad = /[ \t]*$/.exec(text.slice(0, held.getStart()))?.[0] ?? ''
410
- const from = held.getStart() - pad.length
411
- if (text[ends] === '\n') ends += 1
412
- const left = text.slice(0, from)
413
- const right = text.slice(ends)
414
- return left.trimEnd().endsWith('[') && right.trimStart().startsWith(']')
415
- ? `${left.replace(/\s*$/, '')}${right.replace(/^\s*/, '')}`
416
- : left + right
417
- }
418
-
419
- const lines = (held: unknown, pad: string): readonly string[] => {
420
- if (held === null || held === undefined) return [String(held)]
421
- if (Array.isArray(held)) {
422
- if (held.length === 0) return ['[]']
423
- if (held.every((one) => typeof one !== 'object' || one === null)) return [held.map((one) => String(one)).join(', ')]
424
- return held.flatMap((one) => {
425
- const [first = '', ...rest] = lines(one, `${pad} `)
426
- return [`${pad}- ${first.trimStart()}`, ...rest]
427
- })
428
- }
429
- if (typeof held === 'object') {
430
- const parts = Object.entries(held as Record<string, unknown>)
431
- if (parts.length === 0) return ['{}']
432
- return parts.flatMap(([key, one]) => {
433
- const [first = '', ...rest] = lines(one, `${pad} `)
434
- return rest.length === 0 && !first.includes('\n') ? [`${pad}${key}: ${first}`] : [`${pad}${key}:`, first, ...rest]
435
- })
436
- }
437
- return [String(held)]
438
- }
439
-
440
- export function marked(parts: readonly string[]): string {
441
- return createHash('sha256').update(parts.join('\n')).digest('hex').slice(0, 6)
442
- }
443
-
444
- export function showing(row: object, only: readonly string[] = []): string {
445
- const held = row as Record<string, unknown>
446
- const keys = Object.keys(held)
447
-
448
- const wanted = only.filter((one) => one !== '')
449
- const stray = wanted.filter((one) => !keys.includes(one))
450
- if (stray.length > 0) {
451
- return `${stray.map((one) => `\`${one}\``).join(', ')} ${stray.length === 1 ? 'is not a field' : 'are not fields'} of this row. It states ${keys.join(', ')}\n`
452
- }
453
-
454
- const showing = wanted.length === 0 ? keys : wanted
455
- return `${showing.flatMap((key) => {
456
- const [first = '', ...rest] = lines(held[key], ' ')
457
- return rest.length === 0 ? [`${key}: ${first.trimStart()}`] : [`${key}:`, first, ...rest]
458
- }).join('\n')}\n`
459
- }
@@ -1,20 +0,0 @@
1
- export const ORGANISATION = '@prestack'
2
-
3
- export const THING = 'thread'
4
-
5
- export const NAMED = `${ORGANISATION}/${THING}`
6
-
7
- const CORE = 'core'
8
-
9
- const HEAD = `${NAMED}-`
10
-
11
- export const named = (id: string): string => (id === CORE ? NAMED : `${HEAD}${id}`)
12
-
13
- export const idOf = (name: string): string | undefined => {
14
- if (name === NAMED) return CORE
15
- return name.startsWith(HEAD) ? name.slice(HEAD.length) : undefined
16
- }
17
-
18
- export const ours = (name: string): boolean => idOf(name) !== undefined
19
-
20
- export const installed = (at: string): boolean => at.startsWith('node_modules/') && ours(at.split('/').slice(1, 3).join('/'))
@@ -1,29 +0,0 @@
1
- export interface Quote {
2
- readonly on: string
3
- readonly said: string
4
- }
5
-
6
- export interface Threaded {
7
- readonly id: string
8
- readonly at: string
9
- readonly describes: string
10
- readonly version?: number
11
- readonly cites?: readonly Quote[]
12
- readonly requires?: readonly string[]
13
- readonly takes?: readonly string[]
14
- readonly by?: string
15
- readonly runs?: string
16
- readonly declares?: readonly Threaded[]
17
- readonly derives?: readonly Threaded[]
18
- readonly seeds?: readonly Threaded[]
19
- }
20
-
21
- export interface Member extends Threaded {
22
- readonly version: number
23
- }
24
-
25
- export const PREFIXES = {
26
- workflow: 'wf_',
27
- view: 'vw_',
28
- agent: 'agt_',
29
- } as const satisfies Readonly<Record<string, string>>
package/dist/core/tree.ts DELETED
@@ -1,90 +0,0 @@
1
- import { FOLDER, attached, existsSync, readdirSync, statSync } from '../integrations/disk.ts'
2
- import { dirname, join, relative, resolve } from 'node:path'
3
- import { cwd, env } from 'node:process'
4
-
5
- export { FOLDER }
6
-
7
- const NAMES = ['_threads', 'threads'] as const
8
- const ROOT = 'thread.ts'
9
-
10
- export interface Tree {
11
- readonly at: string
12
- readonly dir: string
13
- readonly name: string
14
- readonly root: string
15
- }
16
-
17
- export class UnthreadedRepositoryError extends Error {
18
- constructor(from: string, floor?: string) {
19
- super(
20
- 'no tree above ' + from + ' — looked for a ' + NAMES.map((one) => one + '/').join(' or ') + ' directory in every directory up to ' + (floor === undefined ? 'the filesystem root' : floor + ', the folder this was pointed at') + '. ' +
21
- 'Run `thread init` to write one.',
22
- )
23
- this.name = 'UnthreadedRepositoryError'
24
- }
25
- }
26
-
27
- function given(): string {
28
- const named = env[FOLDER]
29
- return named === undefined ? '' : named
30
- }
31
-
32
- export function folder(): string {
33
- const named = given()
34
- if (named !== '') return resolve(named)
35
- if (attached())
36
- throw new Error(
37
- 'this is answering for a tree on another machine and nothing said which folder that is. ' +
38
- FOLDER +
39
- ' carries it and is not set here. Falling back to the folder this process was started in would read ' +
40
- 'the wrong tree and report it as yours, so it stopped instead.',
41
- )
42
- return cwd()
43
- }
44
-
45
- export function findTree(from: string = folder()): Tree {
46
- const named = given()
47
- const floor = attached() && named !== '' ? resolve(named) : undefined
48
- let at = resolve(from)
49
- for (;;) {
50
- for (const name of NAMES) {
51
- const dir = join(at, name)
52
- if (existsSync(dir) && statSync(dir).isDirectory()) return { at, dir, name, root: join(dir, ROOT) }
53
- }
54
- const up = dirname(at)
55
- if (up === at) throw new UnthreadedRepositoryError(from, floor)
56
- if (at === floor) throw new UnthreadedRepositoryError(from, floor)
57
- at = up
58
- }
59
- }
60
-
61
- export function strayFiles(root: string, prefix: string, ends: string): readonly string[] {
62
- const skip = new Set(['node_modules', '.git', '.next', 'dist', '_generated', 'coverage'])
63
- const found: string[] = []
64
- const walk = (dir: string): void => {
65
-
66
- let held
67
- try {
68
- held = readdirSync(dir, { withFileTypes: true })
69
- } catch {
70
- return
71
- }
72
- for (const one of held) {
73
- if (one.name.startsWith('.') || skip.has(one.name)) continue
74
- const path = join(dir, one.name)
75
- if (one.isDirectory()) {
76
- walk(path)
77
- continue
78
- }
79
- if (one.name.startsWith(prefix) && one.name.endsWith(ends)) {
80
- found.push(relative(root, path).split('\\').join('/'))
81
- }
82
- }
83
- }
84
- walk(root)
85
- return found.sort()
86
- }
87
-
88
- export function inTree(tree: Tree, file: string): string {
89
- return join(tree.dir, file)
90
- }