@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.
- package/CHANGELOG.md +227 -0
- package/dist/core/attach.js +21 -0
- package/dist/core/descend.js +6 -3
- package/dist/core/generators/commit.js +55 -3
- package/dist/core/generators/dev.d.ts +1 -0
- package/dist/core/generators/dev.js +69 -0
- package/dist/derivation/generators/build.d.ts +3 -1
- package/dist/derivation/generators/build.js +104 -22
- package/dist/derivation/generators/release.js +74 -25
- package/dist/derivation/release.js +3 -3
- package/dist/integrations/cli.d.ts +0 -1
- package/dist/integrations/cli.js +69 -11
- package/dist/integrations/declared.d.ts +2 -0
- package/dist/integrations/declared.js +6 -1
- package/dist/integrations/pglite.js +13 -3
- package/dist/integrations/target.d.ts +3 -0
- package/dist/integrity/attach.js +1 -5
- package/dist/integrity/slopnators/sl_stale_path.js +10 -0
- package/dist/operations/access.js +3 -2
- package/dist/operations/capabilities.d.ts +2 -0
- package/dist/operations/capabilities.js +2 -0
- package/dist/operations/generators/capability.js +237 -24
- package/dist/operations/generators/compile.js +150 -50
- package/dist/operations/generators/seed.d.ts +3 -0
- package/dist/operations/generators/seed.js +25 -3
- package/dist/operations/nodes.d.ts +2 -2
- package/package.json +1 -1
- package/dist/core/actor.ts +0 -21
- package/dist/core/attach.ts +0 -613
- package/dist/core/chain.ts +0 -145
- package/dist/core/condition.ts +0 -227
- package/dist/core/descend.ts +0 -1185
- package/dist/core/errors/catalogue.ts +0 -314
- package/dist/core/errors/classes.ts +0 -51
- package/dist/core/errors/error.ts +0 -152
- package/dist/core/errors/namespaces.ts +0 -19
- package/dist/core/finding.ts +0 -37
- package/dist/core/generators/commit.ts +0 -157
- package/dist/core/init.ts +0 -222
- package/dist/core/invoked.ts +0 -52
- package/dist/core/round.ts +0 -74
- package/dist/core/rows.ts +0 -506
- package/dist/core/scope.ts +0 -20
- package/dist/core/thread.ts +0 -29
- package/dist/core/tree.ts +0 -90
- package/dist/core/types.ts +0 -351
- package/dist/derivation/attach.ts +0 -57
- package/dist/derivation/generators/build.ts +0 -371
- package/dist/derivation/generators/check.ts +0 -118
- package/dist/derivation/generators/determinism.ts +0 -145
- package/dist/derivation/generators/release.ts +0 -236
- package/dist/derivation/release.ts +0 -43
- package/dist/integrations/attach.ts +0 -187
- package/dist/integrations/cli.ts +0 -606
- package/dist/integrations/declared.ts +0 -34
- package/dist/integrations/disk.ts +0 -466
- package/dist/integrations/generators/read.ts +0 -127
- package/dist/integrations/generators/vault.ts +0 -210
- package/dist/integrations/https.ts +0 -216
- package/dist/integrations/pglite.ts +0 -206
- package/dist/integrations/secret.ts +0 -54
- package/dist/integrations/target.ts +0 -672
- package/dist/integrations/vault.ts +0 -148
- package/dist/integrity/attach.ts +0 -150
- package/dist/integrity/check-threads.ts +0 -166
- package/dist/integrity/constraint.ts +0 -1246
- package/dist/integrity/generators/compiler.ts +0 -138
- package/dist/integrity/generators/gate.ts +0 -227
- package/dist/integrity/generators/issues.ts +0 -160
- package/dist/integrity/generators/publish.ts +0 -233
- package/dist/integrity/generators/trial.ts +0 -359
- package/dist/integrity/lint.ts +0 -214
- package/dist/integrity/lsp/bin.ts +0 -44
- package/dist/integrity/lsp/diagnostics.ts +0 -92
- package/dist/integrity/lsp/findings.ts +0 -63
- package/dist/integrity/lsp/lint.ts +0 -124
- package/dist/integrity/lsp/protocol.ts +0 -78
- package/dist/integrity/lsp/server.ts +0 -224
- package/dist/integrity/slopnator.ts +0 -324
- package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
- package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
- package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
- package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
- package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
- package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
- package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
- package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
- package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
- package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
- package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
- package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
- package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
- package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
- package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
- package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
- package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
- package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
- package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
- package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
- package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
- package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
- package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
- package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
- package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
- package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
- package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
- package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
- package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
- package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
- package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
- package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
- package/dist/integrity/sweep.ts +0 -395
- package/dist/knowledge/attach.ts +0 -327
- package/dist/knowledge/generators/docsgen.ts +0 -186
- package/dist/knowledge/generators/glossary.ts +0 -73
- package/dist/knowledge/glossary.ts +0 -6
- package/dist/operations/access.ts +0 -131
- package/dist/operations/attach.ts +0 -408
- package/dist/operations/capabilities.ts +0 -88
- package/dist/operations/dispatch.ts +0 -294
- package/dist/operations/error-results.ts +0 -31
- package/dist/operations/generators/capability.ts +0 -1054
- package/dist/operations/generators/compile.ts +0 -701
- package/dist/operations/generators/permits.ts +0 -229
- package/dist/operations/generators/seed.ts +0 -359
- package/dist/operations/generators/trial.ts +0 -666
- package/dist/operations/nodes.ts +0 -53
- package/dist/operations/operations.ts +0 -91
- package/dist/operations/result.ts +0 -28
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from '../../integrations/disk.ts'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import type { Sourced } from '../constraint.ts'
|
|
5
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
6
|
-
import { findTree } from '../../core/tree.ts'
|
|
7
|
-
|
|
8
|
-
const ROOT = findTree().at
|
|
9
|
-
|
|
10
|
-
type Node = {
|
|
11
|
-
type?: string
|
|
12
|
-
key?: { type?: string; name?: string; value?: unknown }
|
|
13
|
-
value?: { type?: string; value?: unknown }
|
|
14
|
-
computed?: boolean
|
|
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
|
-
function scripts(): ReadonlySet<string> {
|
|
26
|
-
try {
|
|
27
|
-
const held = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf8')) as { scripts?: Record<string, string> }
|
|
28
|
-
return new Set(Object.keys(held.scripts ?? {}))
|
|
29
|
-
} catch {
|
|
30
|
-
return new Set()
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const HAS: readonly Sourced[] = [
|
|
35
|
-
{ at: 'package.json', source: '{\n "scripts": {\n "typecheck": "tsc",\n "gate:generate": "node gate.mjs"\n }\n}\n' },
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
export const slopnator: Slopnator = {
|
|
39
|
-
on: ['Property'],
|
|
40
|
-
holds: (node) => {
|
|
41
|
-
const property = node as Node
|
|
42
|
-
const key = keyOf(property)
|
|
43
|
-
if (key !== 'runs' && key !== 'by') return false
|
|
44
|
-
|
|
45
|
-
const held = property.value
|
|
46
|
-
if (held?.type !== 'Literal' || typeof held.value !== 'string') return false
|
|
47
|
-
|
|
48
|
-
const spoken = held.value.trim()
|
|
49
|
-
if (!spoken.startsWith('pnpm ')) return false
|
|
50
|
-
|
|
51
|
-
const named = spoken.replace(/^pnpm (run )?/, '').split(/\s+/)[0] ?? ''
|
|
52
|
-
const known = scripts()
|
|
53
|
-
if (known.size === 0 || known.has(named)) return false
|
|
54
|
-
|
|
55
|
-
return `\`${key}: ${spoken}\` names the script \`${named}\`, and package.json has no such script`
|
|
56
|
-
},
|
|
57
|
-
proves: {
|
|
58
|
-
wrong: [
|
|
59
|
-
{
|
|
60
|
-
files: [...HAS, { at: 'threads/_probe_command.ts', source: "const M = {\n runs: 'pnpm nope:check',\n}\n" }],
|
|
61
|
-
at: 'threads/_probe_command.ts',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
files: [...HAS, { at: 'threads/_probe_command.ts', source: "const M = {\n by: 'pnpm also-not-a-script',\n}\n" }],
|
|
65
|
-
at: 'threads/_probe_command.ts',
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
right: [
|
|
69
|
-
{
|
|
70
|
-
files: [...HAS, { at: 'threads/_probe_command.ts', source: "const M = {\n runs: 'pnpm typecheck',\n}\n" }],
|
|
71
|
-
at: 'threads/_probe_command.ts',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
files: [...HAS, { at: 'threads/_probe_command.ts', source: "const M = {\n by: 'pnpm gate:generate',\n}\n" }],
|
|
75
|
-
at: 'threads/_probe_command.ts',
|
|
76
|
-
},
|
|
77
|
-
"const M = {\n runs: 'node scripts/_generated/gate.mjs',\n}",
|
|
78
|
-
"const M = {\n describes: 'A sentence mentioning pnpm nope:check without naming it as a command.',\n}",
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
|
|
3
|
-
interface Node {
|
|
4
|
-
readonly type?: string
|
|
5
|
-
readonly callee?: { readonly type?: string; readonly name?: string }
|
|
6
|
-
readonly arguments?: readonly { readonly type?: string; readonly elements?: readonly { readonly type?: string }[] }[]
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const slopnator: Slopnator = {
|
|
10
|
-
on: ['CallExpression'],
|
|
11
|
-
holds: (node) => {
|
|
12
|
-
const held = node as Node
|
|
13
|
-
if (held.callee?.type !== 'Identifier' || held.callee.name !== 'only') return false
|
|
14
|
-
if (held.arguments?.length !== 3) return false
|
|
15
|
-
const keys = held.arguments[1]
|
|
16
|
-
if (keys?.type !== 'ArrayExpression') return false
|
|
17
|
-
const typed = (keys.elements ?? []).filter((one) => one?.type !== 'SpreadElement')
|
|
18
|
-
if (typed.length === 0) return false
|
|
19
|
-
return `it hands \`only\` ${String(typed.length)} key(s) written here, and the receipt prints its questions from somewhere else`
|
|
20
|
-
},
|
|
21
|
-
proves: {
|
|
22
|
-
wrong: [
|
|
23
|
-
{
|
|
24
|
-
files: [
|
|
25
|
-
{
|
|
26
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
27
|
-
source: "only(piped, ['name', 'describes'], 'a thing')\n",
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
files: [
|
|
34
|
-
{
|
|
35
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
36
|
-
source: "only(one, ['stop', 'sets'], 'a stop')\n",
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
right: [
|
|
43
|
-
{
|
|
44
|
-
files: [
|
|
45
|
-
{
|
|
46
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
47
|
-
source: "const TAKES = ASKS.map((one) => one.key)\nonly(piped, TAKES, 'a thing')\n",
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
files: [
|
|
54
|
-
{
|
|
55
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
56
|
-
source: "only(all, [...allowed, ...worded], 'a thing')\n",
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
at: 'thread/integrations/generators/probe.ts',
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
|
|
3
|
-
import { HANDED_TO, judging } from './sl_undeclared_crossing.ts'
|
|
4
|
-
|
|
5
|
-
const SAYS =
|
|
6
|
-
'Each of these uses what this app hands an operation, and an operation is the only thing handed one.'
|
|
7
|
-
|
|
8
|
-
export const slopnator: Slopnator = {
|
|
9
|
-
holds: (_node, at) => judging(at, HANDED_TO, SAYS),
|
|
10
|
-
proves: {
|
|
11
|
-
wrong: [
|
|
12
|
-
{
|
|
13
|
-
files: [
|
|
14
|
-
{ at: 'thread/operations/operations.ts', source: 'export interface Store {\n insert(row: unknown): Promise<void>\n}\n\nexport type Opened<R extends string = never> = { readonly [K in R]: Store }\n' },
|
|
15
|
-
{ at: 'threads/_probe_reach.ts', source: "import type { Store } from '../thread/operations/operations.ts'\n\nexport const seeded = async (kept: Store): Promise<void> => {\n await kept['insert']({})\n}\n" },
|
|
16
|
-
],
|
|
17
|
-
at: 'threads/_probe_reach.ts',
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
right: [
|
|
21
|
-
'export const began = Date.now()',
|
|
22
|
-
"import { join } from 'node:path'\n\nexport const at = join('a', 'b')",
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
|
|
3
|
-
import { descend, read, reached } from '../../core/descend.ts'
|
|
4
|
-
import { rowsIn } from './sl_unthreaded.ts'
|
|
5
|
-
|
|
6
|
-
const WRAPS = 'screen'
|
|
7
|
-
|
|
8
|
-
const HANDS = 'dispatch'
|
|
9
|
-
|
|
10
|
-
const ELEMENT = 'element'
|
|
11
|
-
|
|
12
|
-
const COMPOSITION = 'composition'
|
|
13
|
-
|
|
14
|
-
const nameOf = (id: string): string =>
|
|
15
|
-
id.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')
|
|
16
|
-
|
|
17
|
-
function declared(): ReadonlySet<string> {
|
|
18
|
-
const found = new Set<string>()
|
|
19
|
-
|
|
20
|
-
descend()
|
|
21
|
-
|
|
22
|
-
for (const at of reached()) {
|
|
23
|
-
const text = read(at)
|
|
24
|
-
if (text === undefined) continue
|
|
25
|
-
|
|
26
|
-
let waiting: string[] = []
|
|
27
|
-
for (const one of rowsIn(text)) {
|
|
28
|
-
if (one.id === undefined) continue
|
|
29
|
-
if (one.list === 'declares') {
|
|
30
|
-
waiting.push(one.id)
|
|
31
|
-
continue
|
|
32
|
-
}
|
|
33
|
-
if (one.list !== undefined) continue
|
|
34
|
-
if (one.id === ELEMENT || one.id === COMPOSITION) for (const id of waiting) found.add(nameOf(id))
|
|
35
|
-
waiting = []
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return found
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const slopnator: Slopnator = {
|
|
43
|
-
on: ['CallExpression'],
|
|
44
|
-
holds: (node) => {
|
|
45
|
-
const held = node as { readonly callee?: { readonly type?: string; readonly name?: string } }
|
|
46
|
-
const called = held.callee?.type === 'Identifier' ? held.callee.name : undefined
|
|
47
|
-
if (called === undefined) return false
|
|
48
|
-
if (called === WRAPS || called === HANDS) return false
|
|
49
|
-
if (declared().has(called)) return false
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
called + ' is called here, and a screen is made of declared elements and compositions and may hand an operation to ' +
|
|
53
|
-
HANDS + '. Nothing else has a place in one, so this is work that belongs in an operation'
|
|
54
|
-
)
|
|
55
|
-
},
|
|
56
|
-
proves: {
|
|
57
|
-
wrong: ["export const Orders = screen('orders', {}, () => loadOrders())"],
|
|
58
|
-
right: [
|
|
59
|
-
{
|
|
60
|
-
files: [
|
|
61
|
-
{ 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" },
|
|
62
|
-
{ 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_operations.ts',\n },\n ],\n}\n" },
|
|
63
|
-
{ at: 'threads/_probe_operations.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const OPERATIONS: Threaded = {\n id: 'operations',\n declares: [\n {\n id: 'wf_list_orders',\n describes: 'lists the orders',\n derives: [\n {\n id: 'wf_list_orders_body',\n at: 'operations/wf_list_orders.ts',\n by: 'thread compile',\n },\n ],\n },\n ],\n}\n" },
|
|
64
|
-
{ at: 'screens/probe.tsx', source: "import { dispatch } from '../operations/_dispatch.ts'\n\nimport { operation } from '../operations/wf_list_orders.ts'\n\nexport const Orders = screen('orders', {}, () => dispatch(operation, input, actor, opened))\n" },
|
|
65
|
-
],
|
|
66
|
-
at: 'screens/probe.tsx',
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
|
|
3
|
-
const ANNOUNCED: readonly { readonly what: string; readonly pattern: RegExp }[] = [
|
|
4
|
-
{ what: 'a Stripe secret key', pattern: /\bsk_(?:live|test)_[A-Za-z0-9]{16,}/ },
|
|
5
|
-
{ what: 'a Stripe restricted key', pattern: /\brk_(?:live|test)_[A-Za-z0-9]{16,}/ },
|
|
6
|
-
{ what: 'a GitHub token', pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{30,}/ },
|
|
7
|
-
{ what: 'a GitHub personal access token', pattern: /\bgithub_pat_[A-Za-z0-9_]{30,}/ },
|
|
8
|
-
{ what: 'an AWS access key id', pattern: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/ },
|
|
9
|
-
{ what: 'a Slack token', pattern: /\bxox[abposr]-[A-Za-z0-9-]{10,}/ },
|
|
10
|
-
{ what: 'an OpenAI key', pattern: /\bsk-[A-Za-z0-9_-]{32,}/ },
|
|
11
|
-
{ what: 'an Anthropic key', pattern: /\bsk-ant-[A-Za-z0-9_-]{20,}/ },
|
|
12
|
-
{ what: 'a Google API key', pattern: /\bAIza[A-Za-z0-9_-]{35}\b/ },
|
|
13
|
-
{ what: 'a JSON web token', pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/ },
|
|
14
|
-
{ what: 'a private key', pattern: /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/ },
|
|
15
|
-
{ what: 'a password inside a connection string', pattern: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:[^\s:/@]{6,}@/ },
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
const NAMED = /\b(?:secret|password|passwd|api_?key|apikey|access_?token|auth_?token|private_?key|client_?secret|credential)s?\b\s*[:=]\s*(['"`])([^'"`\n]{16,})\1/gi
|
|
19
|
-
|
|
20
|
-
const MIXED = /^(?=.*[a-z])(?=.*[A-Z0-9])[A-Za-z0-9_+/=.-]{16,}$/
|
|
21
|
-
|
|
22
|
-
const NOT = [
|
|
23
|
-
/^(?:sec|pub)_[a-z0-9_]+$/,
|
|
24
|
-
/^\$\{/,
|
|
25
|
-
/^(?:x{3,}|X{3,}|\.{3,}|<[^>]+>|change[-_]?me|your[-_]|example|placeholder|redacted|todo|test|dummy|sample|fake|dGhpcyBpcyBub3QgYSBzZWNyZXQ)/i,
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
const CODE = /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs|json|env|ya?ml|toml|sql|md|sh)$/
|
|
29
|
-
|
|
30
|
-
export const slopnator: Slopnator = {
|
|
31
|
-
holds: (_node, at) => {
|
|
32
|
-
if (!CODE.test(at.filename)) return false
|
|
33
|
-
|
|
34
|
-
if (/(?:^|\/)\.thread\/vault\.sealed\.json$/.test(at.filename)) return false
|
|
35
|
-
|
|
36
|
-
const text = String(at.text)
|
|
37
|
-
|
|
38
|
-
for (const one of ANNOUNCED) {
|
|
39
|
-
if (!one.pattern.test(text)) continue
|
|
40
|
-
return (
|
|
41
|
-
`this holds ${one.what}, written into the file. It is in every copy of this repository, in its history for ` +
|
|
42
|
-
'ever, and in whatever bundle reaches it'
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
for (const found of text.matchAll(NAMED)) {
|
|
47
|
-
const value = found[2] ?? ''
|
|
48
|
-
if (NOT.some((each) => each.test(value))) continue
|
|
49
|
-
if (!MIXED.test(value)) continue
|
|
50
|
-
return (
|
|
51
|
-
`this writes a ${(found[0].split(/[:=]/)[0] ?? '').trim()} down as a literal ${String(value.length)} characters ` +
|
|
52
|
-
'long. A credential in a file is in every copy of this repository and in its history for ever'
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return false
|
|
57
|
-
},
|
|
58
|
-
proves: {
|
|
59
|
-
wrong: [
|
|
60
|
-
"const config = { password: 'Hunter2Hunter2Hunter2' }\n",
|
|
61
|
-
"export const db = 'postgres://app:s3cr3tpassword@db.example.com:5432/main'\n",
|
|
62
|
-
],
|
|
63
|
-
right: [
|
|
64
|
-
"export const stripe = { apiKey: 'sec_stripe_key' }\n",
|
|
65
|
-
"export const node = nd_action(async (opened) => await opened.ht_stripe.charge({ json: { amount: 100 } }))\n",
|
|
66
|
-
],
|
|
67
|
-
},
|
|
68
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from '../../integrations/disk.ts'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
5
|
-
import { descend } from '../../core/descend.ts'
|
|
6
|
-
import { findTree } from '../../core/tree.ts'
|
|
7
|
-
|
|
8
|
-
const ROOT = findTree().at
|
|
9
|
-
const TREE = findTree().name
|
|
10
|
-
const canonical = (at: string): string => (at.startsWith('threads/') ? `${TREE}/${at.slice('threads/'.length)}` : at)
|
|
11
|
-
const NAMES_A_FILE = /\.[a-z]{1,5}$/
|
|
12
|
-
|
|
13
|
-
const known = new WeakMap<object, ReadonlySet<string>>()
|
|
14
|
-
|
|
15
|
-
const derived = (): ReadonlySet<string> => {
|
|
16
|
-
const found = new Set<string>()
|
|
17
|
-
try {
|
|
18
|
-
const pass = descend()
|
|
19
|
-
const cached = known.get(pass)
|
|
20
|
-
if (cached !== undefined) return cached
|
|
21
|
-
for (const [at, held] of pass.threaded) {
|
|
22
|
-
if (held.some((one) => one.row.by !== undefined)) found.add(at)
|
|
23
|
-
}
|
|
24
|
-
for (const one of pass.derived.values()) if (one.at !== undefined) found.add(one.at)
|
|
25
|
-
known.set(pass, found)
|
|
26
|
-
} catch {
|
|
27
|
-
}
|
|
28
|
-
return found
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const ours = (): ReadonlySet<string> => {
|
|
32
|
-
try {
|
|
33
|
-
return new Set(
|
|
34
|
-
readdirSync(ROOT).filter(
|
|
35
|
-
(one) => one !== 'node_modules' && statSync(resolve(ROOT, one), { throwIfNoEntry: false })?.isDirectory() === true,
|
|
36
|
-
),
|
|
37
|
-
)
|
|
38
|
-
} catch {
|
|
39
|
-
return new Set()
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
interface Keyed {
|
|
44
|
-
readonly type?: string
|
|
45
|
-
readonly key?: { readonly name?: string; readonly value?: unknown }
|
|
46
|
-
readonly value?: { readonly type?: string }
|
|
47
|
-
readonly properties?: readonly Keyed[]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const named = (one: Keyed): string | undefined => one.key?.name ?? (typeof one.key?.value === 'string' ? one.key.value : undefined)
|
|
51
|
-
|
|
52
|
-
const sourced = (properties: readonly Keyed[]): boolean => properties.some((one) => named(one) === 'source')
|
|
53
|
-
|
|
54
|
-
function proving(ancestors: readonly unknown[]): boolean {
|
|
55
|
-
for (let at = ancestors.length - 1; at >= 0; at -= 1) {
|
|
56
|
-
const held = ancestors[at] as Keyed
|
|
57
|
-
if (held.type !== 'ObjectExpression') continue
|
|
58
|
-
const properties = held.properties ?? []
|
|
59
|
-
const files = properties.some((one) => named(one) === 'files' && one.value?.type === 'ArrayExpression')
|
|
60
|
-
const where = properties.some((one) => named(one) === 'at' && one.value?.type === 'Literal')
|
|
61
|
-
if (where && (files || sourced(properties))) return true
|
|
62
|
-
}
|
|
63
|
-
return false
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const slopnator: Slopnator = {
|
|
67
|
-
on: ['Literal'],
|
|
68
|
-
holds: (node, held) => {
|
|
69
|
-
if (proving(held.ancestors())) return false
|
|
70
|
-
const value = (node as { value?: unknown }).value
|
|
71
|
-
if (typeof value !== 'string' || !value.includes('/')) return false
|
|
72
|
-
|
|
73
|
-
const path = canonical(value)
|
|
74
|
-
const tops = ours()
|
|
75
|
-
if (tops.size === 0 || !tops.has(path.split('/')[0] ?? '')) return false
|
|
76
|
-
|
|
77
|
-
const varies = path.search(/[{*]/)
|
|
78
|
-
if (varies !== -1) {
|
|
79
|
-
const cut = path.lastIndexOf('/', varies)
|
|
80
|
-
const dir = cut === -1 ? '.' : path.slice(0, cut)
|
|
81
|
-
if (statSync(resolve(ROOT, dir), { throwIfNoEntry: false })?.isDirectory() === true) return false
|
|
82
|
-
return `\`${value}\` ${path[varies] === '*' ? 'names what is in' : 'writes into'} \`${dir}\`, which is not a directory on disk`
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!NAMES_A_FILE.test(path)) return false
|
|
86
|
-
if (existsSync(resolve(ROOT, path))) return false
|
|
87
|
-
if (derived().has(path)) return false
|
|
88
|
-
return `\`${value}\` is not on disk`
|
|
89
|
-
},
|
|
90
|
-
proves: {
|
|
91
|
-
wrong: [
|
|
92
|
-
{
|
|
93
|
-
files: [
|
|
94
|
-
{ at: 'threads/_probe_there.ts', source: 'export const THERE = 1\n' },
|
|
95
|
-
{ at: 'probe.tsx', source: "const at = 'threads/nope.ts'\n" },
|
|
96
|
-
],
|
|
97
|
-
at: 'probe.tsx',
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
files: [
|
|
101
|
-
{ at: 'scripts/_probe_there.ts', source: 'export const THERE = 1\n' },
|
|
102
|
-
{ at: 'probe.tsx', source: "const at = 'scripts/gone.ts'\n" },
|
|
103
|
-
],
|
|
104
|
-
at: 'probe.tsx',
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
files: [
|
|
108
|
-
{ at: 'docs/_probe_there.md', source: 'there\n' },
|
|
109
|
-
{ at: 'probe.tsx', source: "const at = 'docs/nowhere/{page}.md'\n" },
|
|
110
|
-
],
|
|
111
|
-
at: 'probe.tsx',
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
files: [
|
|
115
|
-
{ at: 'docs/_probe_there.md', source: 'there\n' },
|
|
116
|
-
{ at: 'probe.tsx', source: "const at = 'docs/nowhere/*.md'\n" },
|
|
117
|
-
],
|
|
118
|
-
at: 'probe.tsx',
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
files: [
|
|
122
|
-
{ at: 'migrations/_probe_there.sql', source: 'select 1;\n' },
|
|
123
|
-
{ at: 'probe.tsx', source: "const at = 'migrations/gone.sql'\n" },
|
|
124
|
-
],
|
|
125
|
-
at: 'probe.tsx',
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
files: [
|
|
129
|
-
{ at: 'plans/_probe_there.md', source: 'there\n' },
|
|
130
|
-
{ at: 'probe.tsx', source: "const at = 'plans/gone.md'\n" },
|
|
131
|
-
],
|
|
132
|
-
at: 'probe.tsx',
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
right: [
|
|
136
|
-
{
|
|
137
|
-
files: [
|
|
138
|
-
{ at: 'packages/core/integrity/src/constraint.ts', source: 'export const CONSTRAINTS = []\n' },
|
|
139
|
-
{ at: 'probe.tsx', source: "const at = 'packages/core/integrity/src/constraint.ts'\n" },
|
|
140
|
-
],
|
|
141
|
-
at: 'probe.tsx',
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
files: [
|
|
145
|
-
{ at: 'packages/core/integrity/src/lint.ts', source: 'export const plugin = {}\n' },
|
|
146
|
-
{ at: 'probe.tsx', source: "const at = 'packages/core/integrity/src/lint.ts'\n" },
|
|
147
|
-
],
|
|
148
|
-
at: 'probe.tsx',
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
files: [
|
|
152
|
-
{ at: 'docs/reference/_probe_there.md', source: 'there\n' },
|
|
153
|
-
{ at: 'probe.tsx', source: "const at = 'docs/reference/{page}.md'\n" },
|
|
154
|
-
],
|
|
155
|
-
at: 'probe.tsx',
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
files: [
|
|
159
|
-
{ at: 'docs/reference/_probe_there.md', source: 'there\n' },
|
|
160
|
-
{ at: 'probe.tsx', source: "const at = 'docs/reference/*.md'\n" },
|
|
161
|
-
],
|
|
162
|
-
at: 'probe.tsx',
|
|
163
|
-
},
|
|
164
|
-
"const at = 'threads/'",
|
|
165
|
-
"const said = 'a sentence about packages/core/integrity/src/constraint.ts and nothing else'",
|
|
166
|
-
{
|
|
167
|
-
files: [
|
|
168
|
-
{ at: 'thread/core/thread.ts', source: 'export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly by?: string\n readonly runs?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n' },
|
|
169
|
-
{ at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n derives: [\n {\n id: 'layout',\n at: 'app/layout.tsx',\n by: 'thread routes',\n runs: 'thread routes --check',\n },\n ],\n}\n" },
|
|
170
|
-
{ at: 'app/_probe_there.tsx', source: 'export const THERE = 1\n' },
|
|
171
|
-
{ at: 'probe.tsx', source: "const at = 'app/layout.tsx'\n" },
|
|
172
|
-
],
|
|
173
|
-
at: 'probe.tsx',
|
|
174
|
-
},
|
|
175
|
-
"const at = 'node_modules/thread/package.json'",
|
|
176
|
-
],
|
|
177
|
-
},
|
|
178
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
import { here, index, meaningsIn, parses, unreadable } from './sl_unthreaded.ts'
|
|
3
|
-
|
|
4
|
-
export const slopnator: Slopnator = {
|
|
5
|
-
holds: (_node, at) => {
|
|
6
|
-
const path = here(at.filename)
|
|
7
|
-
if (unreadable(path, at.text) !== undefined) return false
|
|
8
|
-
const mine = parses(path) ? meaningsIn(at.text) : []
|
|
9
|
-
if (mine.length === 0) return false
|
|
10
|
-
|
|
11
|
-
const meanings = index().meanings
|
|
12
|
-
|
|
13
|
-
for (const one of mine) {
|
|
14
|
-
const held = meanings.get(one.id)
|
|
15
|
-
if (held === undefined || held.size < 2) continue
|
|
16
|
-
return `\`${one.id}\` is coined with ${String(held.size)} different \`describes\`, and the glossary holds one meaning per word`
|
|
17
|
-
}
|
|
18
|
-
return false
|
|
19
|
-
},
|
|
20
|
-
proves: {
|
|
21
|
-
wrong: [
|
|
22
|
-
{
|
|
23
|
-
files: [
|
|
24
|
-
{
|
|
25
|
-
at: 'thread/core/thread.ts',
|
|
26
|
-
source:
|
|
27
|
-
"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",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
at: 'threads/thread.ts',
|
|
31
|
-
source:
|
|
32
|
-
"import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_probe_meant.ts',\n },\n ],\n}\n",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
at: 'threads/_probe_meant.ts',
|
|
36
|
-
source:
|
|
37
|
-
"import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n {\n id: 'one',\n describes: 'The first thing.',\n },\n {\n id: 'one',\n describes: 'A different thing entirely.',\n },\n ],\n}\n",
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
at: 'threads/_probe_meant.ts',
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
files: [
|
|
44
|
-
{ 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" },
|
|
45
|
-
{ 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_meant_two.ts',\n },\n ],\n}\n" },
|
|
46
|
-
{ at: 'threads/_probe_meant_two.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n {\n id: 'two',\n describes: 'The stated meaning.',\n },\n {\n id: 'two',\n },\n ],\n}\n" },
|
|
47
|
-
],
|
|
48
|
-
at: 'threads/_probe_meant_two.ts',
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
right: [
|
|
52
|
-
"const M: Threaded = {\n declares: [\n {\n id: 'one',\n describes: 'The first thing.',\n },\n {\n id: 'one',\n describes: 'The first thing.',\n },\n ],\n}",
|
|
53
|
-
"const M: Threaded = {\n declares: [\n {\n id: 'one',\n describes: 'The first thing.',\n },\n {\n id: 'two',\n describes: 'A different thing entirely.',\n },\n ],\n}",
|
|
54
|
-
'const M = { declares: [] }',
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { Slopnator } from '../slopnator.ts'
|
|
2
|
-
import { atsIn, canonical, here, index, parses, unreadable } from './sl_unthreaded.ts'
|
|
3
|
-
|
|
4
|
-
const ONLY_DECLARES = new Set(['declares'])
|
|
5
|
-
|
|
6
|
-
const declaredIn = (text: string): readonly string[] => atsIn(text, ONLY_DECLARES).map(canonical)
|
|
7
|
-
|
|
8
|
-
export const slopnator: Slopnator = {
|
|
9
|
-
holds: (_node, at) => {
|
|
10
|
-
const path = here(at.filename)
|
|
11
|
-
if (unreadable(path, at.text) !== undefined) return false
|
|
12
|
-
const mine = parses(path) ? declaredIn(at.text) : []
|
|
13
|
-
if (mine.length === 0) return false
|
|
14
|
-
|
|
15
|
-
const threaded = index().declared
|
|
16
|
-
|
|
17
|
-
for (const claimed of mine) {
|
|
18
|
-
const times = threaded.get(claimed) ?? 0
|
|
19
|
-
if (times > 1) return `${claimed} is declared ${String(times)} times, and \`declares\` is exactly one parent ever`
|
|
20
|
-
}
|
|
21
|
-
return false
|
|
22
|
-
},
|
|
23
|
-
proves: {
|
|
24
|
-
wrong: [
|
|
25
|
-
{
|
|
26
|
-
files: [
|
|
27
|
-
{ 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" },
|
|
28
|
-
{ 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_parented.ts',\n },\n ],\n}\n" },
|
|
29
|
-
{ at: 'threads/_probe_parented.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n {\n at: 'threads/one.ts',\n },\n {\n at: 'threads/one.ts',\n },\n ],\n}\n" },
|
|
30
|
-
],
|
|
31
|
-
at: 'threads/_probe_parented.ts',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
files: [
|
|
35
|
-
{ 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" },
|
|
36
|
-
{ 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_parented_2.ts',\n },\n ],\n}\n" },
|
|
37
|
-
{ at: 'threads/_probe_parented_2.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n {\n at: 'threads/two.ts',\n },\n {\n at: 'threads/three.ts',\n },\n {\n at: 'threads/two.ts',\n },\n ],\n}\n" },
|
|
38
|
-
],
|
|
39
|
-
at: 'threads/_probe_parented_2.ts',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
files: [
|
|
43
|
-
{ 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" },
|
|
44
|
-
{ 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_parented_hoisted.ts',\n },\n ],\n}\n" },
|
|
45
|
-
{ at: 'threads/_probe_parented_hoisted.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nconst ROW = {\n at: 'threads/one.ts',\n}\nconst M: Threaded = {\n declares: [ROW, ROW],\n}\n" },
|
|
46
|
-
],
|
|
47
|
-
at: 'threads/_probe_parented_hoisted.ts',
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
right: [
|
|
51
|
-
{
|
|
52
|
-
files: [
|
|
53
|
-
{ at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly by?: string\n readonly runs?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
|
|
54
|
-
{ 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_derived.ts',\n },\n ],\n}\n" },
|
|
55
|
-
{ at: 'threads/_probe_derived.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n derives: [\n {\n at: 'threads/glossary.ts',\n by: 'thread glossary',\n runs: 'thread glossary --check',\n },\n {\n at: 'threads/glossary.ts',\n by: 'thread glossary',\n runs: 'thread glossary --check',\n },\n ],\n}\n" },
|
|
56
|
-
{ at: 'threads/glossary.ts', source: 'export const GLOSSARY = 1\n' },
|
|
57
|
-
],
|
|
58
|
-
at: 'threads/_probe_derived.ts',
|
|
59
|
-
},
|
|
60
|
-
'const M = { declares: [] }',
|
|
61
|
-
{
|
|
62
|
-
files: [
|
|
63
|
-
{ 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" },
|
|
64
|
-
{ 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_hoisted.ts',\n },\n ],\n}\n" },
|
|
65
|
-
{ at: 'threads/_probe_hoisted.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nconst ROW = {\n at: 'threads/core.ts',\n}\nexport const M: Threaded = {\n declares: [ROW],\n}\n" },
|
|
66
|
-
{ at: 'threads/core.ts', source: 'export const CORE = 1\n' },
|
|
67
|
-
],
|
|
68
|
-
at: 'threads/_probe_hoisted.ts',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
files: [
|
|
72
|
-
{ 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" },
|
|
73
|
-
{ 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_nested.ts',\n },\n ],\n}\n" },
|
|
74
|
-
{ at: 'threads/_probe_nested.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const M: Threaded = {\n declares: [\n {\n at: 'threads/core.ts',\n declares: [\n {\n at: 'threads/data.ts',\n },\n ],\n },\n ],\n}\n" },
|
|
75
|
-
{ at: 'threads/core.ts', source: 'export const CORE = 1\n' },
|
|
76
|
-
{ at: 'threads/data.ts', source: 'export const DATA = 1\n' },
|
|
77
|
-
],
|
|
78
|
-
at: 'threads/_probe_nested.ts',
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
}
|