@prestack/thread 0.1.2 → 0.1.4
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 +193 -0
- package/dist/core/actor.d.ts +1 -1
- package/dist/core/actor.js +5 -4
- package/dist/core/actor.ts +5 -4
- package/dist/core/attach.d.ts +0 -7
- package/dist/core/attach.js +67 -58
- package/dist/core/attach.ts +61 -68
- package/dist/core/chain.js +13 -17
- package/dist/core/chain.ts +11 -15
- package/dist/core/condition.d.ts +4 -4
- package/dist/core/condition.js +2 -2
- package/dist/core/descend.d.ts +4 -2
- package/dist/core/descend.js +89 -21
- package/dist/core/descend.ts +86 -17
- package/dist/core/errors/catalogue.d.ts +52 -0
- package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
- package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
- package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
- package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
- package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
- package/dist/core/errors/namespaces.d.ts +3 -0
- package/dist/core/errors/namespaces.js +15 -0
- package/dist/core/errors/namespaces.ts +19 -0
- package/dist/core/finding.js +2 -2
- package/dist/core/finding.ts +1 -2
- package/dist/core/init.d.ts +0 -2
- package/dist/core/init.js +51 -15
- package/dist/core/init.ts +58 -15
- package/dist/core/invoked.d.ts +1 -1
- package/dist/core/invoked.js +3 -1
- package/dist/core/invoked.ts +5 -2
- package/dist/core/round.js +36 -22
- package/dist/core/round.ts +26 -9
- package/dist/core/rows.d.ts +4 -0
- package/dist/core/rows.js +31 -2
- package/dist/core/rows.ts +33 -1
- package/dist/core/thread.d.ts +3 -3
- package/dist/core/tree.d.ts +4 -1
- package/dist/core/tree.js +26 -6
- package/dist/core/tree.ts +29 -6
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +3 -1
- package/dist/core/types.ts +2 -1
- package/dist/derivation/attach.js +1 -1
- package/dist/derivation/generators/build.js +6 -6
- package/dist/derivation/generators/build.ts +1 -1
- package/dist/derivation/generators/check.js +1 -1
- package/dist/derivation/generators/determinism.js +1 -1
- package/dist/derivation/generators/release.js +60 -47
- package/dist/derivation/generators/release.ts +66 -43
- package/dist/derivation/release.d.ts +7 -3
- package/dist/derivation/release.js +14 -1
- package/dist/derivation/release.ts +22 -2
- package/dist/integrations/attach.d.ts +4 -0
- package/dist/integrations/attach.js +33 -54
- package/dist/integrations/attach.ts +50 -57
- package/dist/integrations/cli.d.ts +37 -0
- package/dist/integrations/cli.js +440 -0
- package/dist/integrations/cli.ts +543 -0
- package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -20
- package/dist/integrations/disk.js +435 -0
- package/dist/integrations/disk.ts +465 -0
- package/dist/integrations/generators/read.js +6 -6
- package/dist/integrations/generators/read.ts +4 -4
- package/dist/integrations/generators/vault.js +10 -11
- package/dist/integrations/generators/vault.ts +4 -5
- package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
- package/dist/integrations/https.js +170 -0
- package/dist/integrations/https.ts +216 -0
- package/dist/integrations/pglite.d.ts +26 -0
- package/dist/integrations/pglite.js +143 -0
- package/dist/integrations/pglite.ts +206 -0
- package/dist/integrations/secret.d.ts +8 -2
- package/dist/integrations/secret.js +3 -5
- package/dist/integrations/secret.ts +10 -6
- package/dist/integrations/target.d.ts +155 -14
- package/dist/integrations/target.js +171 -50
- package/dist/integrations/target.ts +377 -61
- package/dist/integrations/vault.d.ts +1 -0
- package/dist/integrations/vault.js +20 -5
- package/dist/integrations/vault.ts +17 -5
- package/dist/integrity/attach.js +3 -73
- package/dist/integrity/attach.ts +1 -71
- package/dist/integrity/check-threads.js +5 -5
- package/dist/integrity/check-threads.ts +2 -2
- package/dist/integrity/constraint.d.ts +0 -1
- package/dist/integrity/constraint.js +267 -366
- package/dist/integrity/constraint.ts +267 -375
- package/dist/integrity/generators/compiler.js +14 -17
- package/dist/integrity/generators/compiler.ts +10 -15
- package/dist/integrity/generators/gate.js +15 -15
- package/dist/integrity/generators/gate.ts +10 -10
- package/dist/integrity/generators/issues.js +7 -7
- package/dist/integrity/generators/publish.js +39 -57
- package/dist/integrity/generators/publish.ts +44 -55
- package/dist/integrity/generators/trial.d.ts +3 -3
- package/dist/integrity/generators/trial.js +133 -161
- package/dist/integrity/generators/trial.ts +145 -165
- package/dist/integrity/lint.js +9 -13
- package/dist/integrity/lint.ts +7 -10
- package/dist/integrity/lsp/bin.js +5 -4
- package/dist/integrity/lsp/bin.ts +3 -1
- package/dist/integrity/lsp/diagnostics.js +3 -3
- package/dist/integrity/lsp/diagnostics.ts +1 -1
- package/dist/integrity/lsp/lint.js +19 -30
- package/dist/integrity/lsp/lint.ts +16 -32
- package/dist/integrity/lsp/server.js +3 -3
- package/dist/integrity/slopnator.d.ts +3 -13
- package/dist/integrity/slopnator.js +58 -37
- package/dist/integrity/slopnator.ts +53 -37
- package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
- package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
- package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
- package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
- package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
- package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
- package/dist/integrity/slopnators/sl_inert_island.js +10 -8
- package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
- package/dist/integrity/slopnators/sl_missing_row.js +6 -51
- package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
- package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
- package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
- package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
- package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
- package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
- package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
- package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
- package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
- package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
- package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
- package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
- package/dist/integrity/slopnators/sl_stale_path.js +5 -22
- package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
- package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
- package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
- package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
- package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
- package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
- package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
- package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
- package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
- package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
- package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
- package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
- package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
- package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
- package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
- package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
- package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
- package/dist/integrity/slopnators/sl_underived_route.js +61 -0
- package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
- package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
- package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
- package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
- package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
- package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
- package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
- package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
- package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
- package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
- package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
- package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
- package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
- package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
- package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
- package/dist/integrity/slopnators/sl_unversioned.js +6 -4
- package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
- package/dist/integrity/sweep.d.ts +1 -0
- package/dist/integrity/sweep.js +105 -42
- package/dist/integrity/sweep.ts +115 -42
- package/dist/knowledge/attach.js +1 -1
- package/dist/knowledge/generators/docsgen.js +8 -6
- package/dist/knowledge/generators/docsgen.ts +4 -2
- package/dist/knowledge/generators/glossary.js +4 -4
- package/dist/knowledge/generators/glossary.ts +1 -1
- package/dist/operations/access.d.ts +23 -0
- package/dist/operations/access.js +28 -1
- package/dist/operations/access.ts +43 -0
- package/dist/operations/attach.js +28 -109
- package/dist/operations/attach.ts +46 -113
- package/dist/operations/capabilities.d.ts +14 -5
- package/dist/operations/capabilities.js +13 -4
- package/dist/operations/capabilities.ts +27 -8
- package/dist/operations/dispatch.d.ts +8 -2
- package/dist/operations/dispatch.js +128 -185
- package/dist/operations/dispatch.ts +138 -191
- package/dist/operations/error-results.d.ts +1 -1
- package/dist/operations/error-results.js +2 -2
- package/dist/operations/error-results.ts +2 -2
- package/dist/operations/generators/capability.d.ts +11 -1
- package/dist/operations/generators/capability.js +481 -224
- package/dist/operations/generators/capability.ts +562 -233
- package/dist/operations/generators/compile.js +66 -39
- package/dist/operations/generators/compile.ts +78 -39
- package/dist/operations/generators/permits.js +11 -12
- package/dist/operations/generators/permits.ts +3 -4
- package/dist/operations/generators/seed.d.ts +1 -0
- package/dist/operations/generators/seed.js +19 -17
- package/dist/operations/generators/seed.ts +22 -14
- package/dist/operations/generators/trial.d.ts +6 -8
- package/dist/operations/generators/trial.js +200 -70
- package/dist/operations/generators/trial.ts +230 -93
- package/dist/operations/nodes.d.ts +15 -16
- package/dist/operations/nodes.ts +16 -17
- package/dist/operations/operations.d.ts +40 -4
- package/dist/operations/operations.js +1 -0
- package/dist/operations/operations.ts +61 -4
- package/dist/operations/result.d.ts +2 -2
- package/dist/operations/result.ts +2 -2
- package/package.json +1 -4
- package/dist/core/answers.d.ts +0 -171
- package/dist/core/answers.js +0 -789
- package/dist/core/answers.ts +0 -999
- package/dist/core/client.d.ts +0 -57
- package/dist/core/client.js +0 -247
- package/dist/core/client.ts +0 -286
- package/dist/core/files.js +0 -145
- package/dist/core/files.ts +0 -193
- package/dist/integrations/module.d.ts +0 -6
- package/dist/integrations/module.js +0 -153
- package/dist/integrations/module.ts +0 -191
- package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
- package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
- package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
- package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
- package/dist/operations/cost.d.ts +0 -14
- package/dist/operations/cost.js +0 -37
- package/dist/operations/cost.ts +0 -58
- package/dist/operations/errors/errors.d.ts +0 -52
- package/dist/operations/http.js +0 -124
- package/dist/operations/http.ts +0 -169
- package/dist/operations/memory.d.ts +0 -104
- package/dist/operations/memory.js +0 -365
- package/dist/operations/memory.ts +0 -470
- package/dist/operations/metering.d.ts +0 -55
- package/dist/operations/metering.js +0 -247
- package/dist/operations/metering.ts +0 -328
- package/dist/operations/queue-policy.d.ts +0 -3
- package/dist/operations/queue-policy.js +0 -8
- package/dist/operations/queue-policy.ts +0 -10
- package/dist/operations/seams.d.ts +0 -239
- package/dist/operations/seams.js +0 -45
- package/dist/operations/seams.ts +0 -364
- package/dist/operations/store.d.ts +0 -14
- package/dist/operations/store.js +0 -1
- package/dist/operations/store.ts +0 -29
- /package/dist/{operations → core}/errors/classes.d.ts +0 -0
- /package/dist/{operations → core}/errors/classes.js +0 -0
- /package/dist/{operations → core}/errors/classes.ts +0 -0
- /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
- /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
package/dist/core/attach.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { installing, needing } from '../integrations/cli.ts'
|
|
2
|
+
import { attached, existsSync, readFileSync, rmSync, writeFileSync } from '../integrations/disk.ts'
|
|
2
3
|
import { createRequire } from 'node:module'
|
|
3
4
|
import { join, relative, resolve } from 'node:path'
|
|
4
5
|
import { stdout } from 'node:process'
|
|
5
6
|
|
|
6
7
|
import { LISTS } from './descend.ts'
|
|
7
8
|
import { ROOT, TREE, root as rooted } from './init.ts'
|
|
9
|
+
import { BESIDE } from './invoked.ts'
|
|
8
10
|
import { STATED, holdsRow, listBounds, quoted, reconciled, rowsIn, withRow, withoutRow } from './rows.ts'
|
|
9
|
-
import { ours as isOurs } from './scope.ts'
|
|
11
|
+
import { idOf, ours as isOurs } from './scope.ts'
|
|
10
12
|
|
|
11
13
|
const SHAPE = /export interface [A-Za-z0-9_]+ extends Threaded \{[\s\S]*?\n\}\n/
|
|
12
14
|
|
|
@@ -35,16 +37,6 @@ export interface Attaching {
|
|
|
35
37
|
readonly declares: string
|
|
36
38
|
readonly rows?: readonly Appending[]
|
|
37
39
|
|
|
38
|
-
readonly retires?: readonly {
|
|
39
|
-
readonly into: string
|
|
40
|
-
readonly list: string
|
|
41
|
-
readonly id: string
|
|
42
|
-
|
|
43
|
-
readonly made?: string
|
|
44
|
-
|
|
45
|
-
readonly why: string
|
|
46
|
-
}[]
|
|
47
|
-
|
|
48
40
|
readonly attaches?: readonly string[]
|
|
49
41
|
|
|
50
42
|
readonly scripts?: Readonly<Record<string, string>>
|
|
@@ -108,18 +100,27 @@ export async function attaches(into: string, name: string): Promise<boolean> {
|
|
|
108
100
|
}
|
|
109
101
|
}
|
|
110
102
|
|
|
103
|
+
function shipped(spec: string, owner: string): string {
|
|
104
|
+
const rest = spec.slice(owner.length + 1)
|
|
105
|
+
const named = idOf(owner) ?? owner
|
|
106
|
+
const part = rest === DOOR.slice(1) ? named : String(rest.split('/')[0])
|
|
107
|
+
return new URL('../' + part + '/' + BESIDE('attach'), import.meta.url).href
|
|
108
|
+
}
|
|
109
|
+
|
|
111
110
|
async function attaching(into: string, name: string): Promise<Attaching> {
|
|
112
111
|
const spec = name.endsWith(DOOR) ? name : `${name}${DOOR}`
|
|
113
112
|
const owner = packageOf(name)
|
|
114
113
|
let held: { ATTACH?: Attaching }
|
|
115
114
|
try {
|
|
115
|
+
if (attached() && isOurs(owner)) held = (await import(shipped(spec, owner))) as { ATTACH?: Attaching }
|
|
116
|
+
else
|
|
116
117
|
held = (await import(createRequire(join(into, 'package.json')).resolve(spec))) as { ATTACH?: Attaching }
|
|
117
118
|
} catch {
|
|
118
119
|
if (!existsSync(join(into, 'node_modules', owner, 'package.json'))) {
|
|
119
120
|
throw new UnattachableError(
|
|
120
121
|
owner,
|
|
121
|
-
|
|
122
|
-
'package
|
|
122
|
+
'is not installed here, and fetching it did not put it on disk either. Check the name — `thread attach` ' +
|
|
123
|
+
'takes the package as the registry spells it. Nothing here was changed',
|
|
123
124
|
)
|
|
124
125
|
}
|
|
125
126
|
throw new UnattachableError(
|
|
@@ -163,6 +164,28 @@ function edit(at: string, change: (text: string) => string, touched: Set<string>
|
|
|
163
164
|
touched.add(relative(into, at))
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
function acquire(into: string, owner: string): void {
|
|
168
|
+
const manifest = join(into, 'package.json')
|
|
169
|
+
const was = readFileSync(manifest, 'utf8')
|
|
170
|
+
const parsed = JSON.parse(was) as Record<string, unknown> & { dependencies?: Record<string, string> }
|
|
171
|
+
stdout.write(`thread: ${owner} is not here yet, so this is fetching it. Nothing has to be typed for that.\n`)
|
|
172
|
+
writeFileSync(manifest, `${JSON.stringify({ ...parsed, dependencies: { ...parsed.dependencies, [owner]: 'latest' } }, null, 2)}\n`, 'utf8')
|
|
173
|
+
try {
|
|
174
|
+
installing(into)
|
|
175
|
+
} catch (thrown) {
|
|
176
|
+
writeFileSync(manifest, was, 'utf8')
|
|
177
|
+
throw new Error(
|
|
178
|
+
`${owner} could not be fetched — ${thrown instanceof Error ? thrown.message : String(thrown)} package.json is as it was, so nothing here names a package that is not on disk.`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
const at = join(into, 'node_modules', owner, 'package.json')
|
|
182
|
+
if (!existsSync(at)) return
|
|
183
|
+
const got = (JSON.parse(readFileSync(at, 'utf8')) as { version?: string }).version
|
|
184
|
+
if (got === undefined) return
|
|
185
|
+
const now = JSON.parse(readFileSync(manifest, 'utf8')) as Record<string, unknown> & { dependencies?: Record<string, string> }
|
|
186
|
+
writeFileSync(manifest, `${JSON.stringify({ ...now, dependencies: { ...now.dependencies, [owner]: '^' + got } }, null, 2)}\n`, 'utf8')
|
|
187
|
+
}
|
|
188
|
+
|
|
166
189
|
export async function attach(
|
|
167
190
|
into: string,
|
|
168
191
|
name: string,
|
|
@@ -174,13 +197,17 @@ export async function attach(
|
|
|
174
197
|
const root = join(dir, ROOT)
|
|
175
198
|
if (!existsSync(root)) throw new UnthreadedError()
|
|
176
199
|
|
|
200
|
+
const owned = packageOf(name)
|
|
201
|
+
if (!existsSync(join(into, 'node_modules', owned, 'package.json'))) acquire(into, owned)
|
|
202
|
+
|
|
177
203
|
const one = await attaching(into, name)
|
|
178
204
|
|
|
179
205
|
for (const on of one.attaches ?? []) {
|
|
206
|
+
if (!(await attaches(into, on))) acquire(into, packageOf(on))
|
|
180
207
|
if (!(await attaches(into, on))) {
|
|
181
208
|
throw new UnattachableError(
|
|
182
209
|
name,
|
|
183
|
-
`must have ${on} attached before it, and ${on}
|
|
210
|
+
`must have ${on} attached before it, and fetching ${packageOf(on)} did not put it on disk. ` +
|
|
184
211
|
`${on} is named in \`attaches\` and not in dependencies, because a package that only appends a row to a file ` +
|
|
185
212
|
'another package owns would otherwise carry an npm edge it never imports',
|
|
186
213
|
)
|
|
@@ -190,7 +217,6 @@ export async function attach(
|
|
|
190
217
|
|
|
191
218
|
const plan = new Map<string, string>()
|
|
192
219
|
|
|
193
|
-
const retired: string[] = []
|
|
194
220
|
|
|
195
221
|
const reshaped: string[] = []
|
|
196
222
|
|
|
@@ -336,13 +362,6 @@ export async function attach(
|
|
|
336
362
|
if (where === undefined) return false
|
|
337
363
|
return !text.slice(where.open, where.close).includes(each.source.trim().replace(/,$/, ''))
|
|
338
364
|
}).length
|
|
339
|
-
const withdrawing = (one.retires ?? []).filter((gone) => {
|
|
340
|
-
const at = join(dir, gone.into)
|
|
341
|
-
if (!existsSync(at)) return false
|
|
342
|
-
const text = plan.get(at) ?? readFileSync(at, 'utf8')
|
|
343
|
-
const where = listBounds(text, gone.list)
|
|
344
|
-
return where !== undefined && holdsRow(text, where, gone.id)
|
|
345
|
-
}).length
|
|
346
365
|
|
|
347
366
|
throw new Error(
|
|
348
367
|
`${name} brings a noun called \`${coined}\`, and this tree already declares something by that name. One ` +
|
|
@@ -354,11 +373,10 @@ export async function attach(
|
|
|
354
373
|
|
|
355
374
|
`A refusal here names a command you can actually run. If the one above does not fit what you are trying ` +
|
|
356
375
|
`to do, that is a gap in this framework rather than something to work around — say so.` +
|
|
357
|
-
(waiting
|
|
376
|
+
(waiting === 0
|
|
358
377
|
? ''
|
|
359
378
|
: `\n\nAn attach is all or nothing, so this is also holding back everything else ${name} would have ` +
|
|
360
|
-
`delivered: ${String(waiting)} row(s) this tree does not hold at the version installed` +
|
|
361
|
-
`${withdrawing === 0 ? '' : ` and ${String(withdrawing)} it has withdrawn`}. None of that arrives until the ` +
|
|
379
|
+
`delivered: ${String(waiting)} row(s) this tree does not hold at the version installed. None of that arrives until the ` +
|
|
362
380
|
`collision above is cleared, and nothing else will tell you — \`npm install\` will go on reporting this ` +
|
|
363
381
|
`tree current.`),
|
|
364
382
|
)
|
|
@@ -383,34 +401,6 @@ export async function attach(
|
|
|
383
401
|
plan.set(target, withRow(held, bounds, row.source))
|
|
384
402
|
}
|
|
385
403
|
|
|
386
|
-
for (const gone of one.retires ?? []) {
|
|
387
|
-
const shipped = (one.rows ?? []).find(
|
|
388
|
-
(row) => row.into === gone.into && row.list === gone.list && row.id === gone.id,
|
|
389
|
-
)
|
|
390
|
-
if (shipped !== undefined) {
|
|
391
|
-
throw new UnattachableError(
|
|
392
|
-
name,
|
|
393
|
-
`both ships and retires \`${gone.id}\` in ${gone.into}, so attaching it would add and remove one row`,
|
|
394
|
-
)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
if (gone.made !== undefined) {
|
|
398
|
-
const byproduct = join(into, gone.made)
|
|
399
|
-
if (existsSync(byproduct)) {
|
|
400
|
-
rmSync(byproduct)
|
|
401
|
-
retired.push(`${gone.made} — the file \`${gone.id}\` derived, which nothing writes now`)
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const target = join(dir, gone.into)
|
|
406
|
-
if (!existsSync(target) && !plan.has(target)) continue
|
|
407
|
-
const text = plan.get(target) ?? readFileSync(target, 'utf8')
|
|
408
|
-
const where = listBounds(text, gone.list)
|
|
409
|
-
if (where === undefined || !holdsRow(text, where, gone.id)) continue
|
|
410
|
-
plan.set(target, withoutRow(text, where, gone.id))
|
|
411
|
-
retired.push(`${gone.into}: ${gone.id} — ${gone.why}`)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
404
|
if (one.scripts !== undefined) {
|
|
415
405
|
const manifest = join(into, 'package.json')
|
|
416
406
|
const held = readFileSync(manifest, 'utf8')
|
|
@@ -427,19 +417,23 @@ export async function attach(
|
|
|
427
417
|
|
|
428
418
|
if (one.needs !== undefined) {
|
|
429
419
|
const manifest = join(into, 'package.json')
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
420
|
+
const was = readFileSync(manifest, 'utf8')
|
|
421
|
+
const scripted = plan.get(manifest)
|
|
422
|
+
if (scripted !== undefined) {
|
|
423
|
+
writeFileSync(manifest, scripted, 'utf8')
|
|
424
|
+
plan.delete(manifest)
|
|
425
|
+
touched.add(relative(into, manifest))
|
|
426
|
+
}
|
|
427
|
+
let added: readonly string[]
|
|
428
|
+
try {
|
|
429
|
+
added = needing(into, one.needs)
|
|
430
|
+
} catch (thrown) {
|
|
431
|
+
writeFileSync(manifest, was, 'utf8')
|
|
432
|
+
throw new Error(`${thrown instanceof Error ? thrown.message : String(thrown)} Nothing was attached.`)
|
|
439
433
|
}
|
|
440
434
|
if (added.length > 0) {
|
|
441
|
-
|
|
442
|
-
stdout.write(`thread:
|
|
435
|
+
touched.add(relative(into, manifest))
|
|
436
|
+
stdout.write(`thread: ${name} needs ${added.join(', ')}, so ${added.length === 1 ? 'it is' : 'they are'} in package.json now and fetched. Nothing has to be typed for that.\n`)
|
|
443
437
|
}
|
|
444
438
|
}
|
|
445
439
|
|
|
@@ -459,7 +453,6 @@ export async function attach(
|
|
|
459
453
|
touched.add(relative(into, path))
|
|
460
454
|
}
|
|
461
455
|
|
|
462
|
-
for (const line of retired) stdout.write(`thread: retired ${line}\n`)
|
|
463
456
|
for (const file of reshaped) stdout.write(`thread: reshaped ${file} — what a row may state has changed\n`)
|
|
464
457
|
for (const id of noticed) stdout.write(`thread: declared ${id} — a file this app grew after \`thread init\` ran\n`)
|
|
465
458
|
|
|
@@ -545,7 +538,7 @@ export async function detach(into: string, name: string): Promise<readonly strin
|
|
|
545
538
|
}
|
|
546
539
|
|
|
547
540
|
const DESCRIBES =
|
|
548
|
-
'The package every tree installs first: the descent, the
|
|
541
|
+
'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.'
|
|
549
542
|
|
|
550
543
|
const CORE_SOURCE = `import type { Threaded } from '../core/thread.ts'
|
|
551
544
|
|
|
@@ -567,7 +560,7 @@ const SEEDED = {
|
|
|
567
560
|
' {',
|
|
568
561
|
' id: \'core\',',
|
|
569
562
|
' at: \'_threads/core.ts\',',
|
|
570
|
-
' describes: \'The package every tree installs first: the descent, the
|
|
563
|
+
' describes: \'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.\',',
|
|
571
564
|
' version: 1,',
|
|
572
565
|
' },',
|
|
573
566
|
].join('\n'),
|
package/dist/core/chain.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { starts } from '../integrations/cli.js';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { execPath } from 'node:process';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { existsSync, readFileSync, readdirSync } from
|
|
6
|
-
import { valuesIn } from
|
|
7
|
-
import { findTree } from
|
|
5
|
+
import { existsSync, readFileSync, readdirSync } from '../integrations/disk.js';
|
|
6
|
+
import { valuesIn } from './rows.js';
|
|
7
|
+
import { findTree } from './tree.js';
|
|
8
8
|
const STATING = 'derivation.ts';
|
|
9
9
|
export async function generators(tree = findTree()) {
|
|
10
10
|
if (!existsSync(tree.dir))
|
|
@@ -39,12 +39,8 @@ export const REFUSED_BY = 'round: refused';
|
|
|
39
39
|
export function batched(at, commands, within) {
|
|
40
40
|
if (commands.length === 0)
|
|
41
41
|
return [];
|
|
42
|
-
const out =
|
|
43
|
-
|
|
44
|
-
encoding: 'utf8',
|
|
45
|
-
...(within === undefined ? {} : { timeout: within, killSignal: 'SIGKILL' }),
|
|
46
|
-
});
|
|
47
|
-
const lines = `${out.stdout ?? ''}${out.stderr ?? ''}`.split('\n');
|
|
42
|
+
const out = starts(execPath, [...LOADER, RUNNER, ...new Set(commands)], { at, shows: 'errors', within });
|
|
43
|
+
const lines = out.out.split('\n');
|
|
48
44
|
const found = new Map();
|
|
49
45
|
let held = [];
|
|
50
46
|
for (const line of lines) {
|
|
@@ -58,12 +54,12 @@ export function batched(at, commands, within) {
|
|
|
58
54
|
held = [];
|
|
59
55
|
}
|
|
60
56
|
const orphaned = held.join('\n').trim();
|
|
61
|
-
const died = out.
|
|
62
|
-
? ` The runner itself failed to start or was stopped: ${out.
|
|
63
|
-
: out.
|
|
64
|
-
? ` The runner was killed by ${out.
|
|
65
|
-
: found.size === 0 && out.
|
|
66
|
-
? ` The runner exited ${String(out.
|
|
57
|
+
const died = out.why !== ''
|
|
58
|
+
? ` The runner itself failed to start or was stopped: ${out.why}.`
|
|
59
|
+
: out.killed !== null
|
|
60
|
+
? ` The runner was killed by ${out.killed} after ${String(within ?? 0)} ms. The last "settle: running" line above names the command it was inside, and everything after that one is unreported rather than refused.`
|
|
61
|
+
: found.size === 0 && !out.ok
|
|
62
|
+
? ` The runner exited ${String(out.code)} having reported nothing, so it died before the first command finished.`
|
|
67
63
|
: '';
|
|
68
64
|
let firstUnreached = true;
|
|
69
65
|
return commands.map((one) => {
|
|
@@ -93,7 +89,7 @@ export function settling(at, all, skip = []) {
|
|
|
93
89
|
let before;
|
|
94
90
|
while (round < ROUNDS) {
|
|
95
91
|
round += 1;
|
|
96
|
-
const asking =
|
|
92
|
+
const asking = batch(at, mine.map((one) => word(one.runs))).refused;
|
|
97
93
|
const unhappy = mine.filter((one) => asking.includes(word(one.runs)));
|
|
98
94
|
if (unhappy.length === 0)
|
|
99
95
|
return { ran, unsettled: [], rounds: round };
|
package/dist/core/chain.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { starts } from '../integrations/cli.ts'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
import { execPath } from 'node:process'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
|
|
6
6
|
import type { Row } from './descend.ts'
|
|
7
|
-
import { existsSync, readFileSync, readdirSync } from '
|
|
7
|
+
import { existsSync, readFileSync, readdirSync } from '../integrations/disk.ts'
|
|
8
8
|
import { valuesIn } from './rows.ts'
|
|
9
9
|
import { findTree, type Tree } from './tree.ts'
|
|
10
10
|
|
|
@@ -58,12 +58,8 @@ export function batched(
|
|
|
58
58
|
): readonly { readonly command: string; readonly ok: boolean; readonly said: string }[] {
|
|
59
59
|
if (commands.length === 0) return []
|
|
60
60
|
|
|
61
|
-
const out =
|
|
62
|
-
|
|
63
|
-
encoding: 'utf8',
|
|
64
|
-
...(within === undefined ? {} : { timeout: within, killSignal: 'SIGKILL' as const }),
|
|
65
|
-
})
|
|
66
|
-
const lines = `${out.stdout ?? ''}${out.stderr ?? ''}`.split('\n')
|
|
61
|
+
const out = starts(execPath, [...LOADER, RUNNER, ...new Set(commands)], { at, shows: 'errors', within })
|
|
62
|
+
const lines = out.out.split('\n')
|
|
67
63
|
|
|
68
64
|
const found = new Map<string, { readonly command: string; readonly ok: boolean; readonly said: string }>()
|
|
69
65
|
let held: string[] = []
|
|
@@ -80,12 +76,12 @@ export function batched(
|
|
|
80
76
|
|
|
81
77
|
const orphaned = held.join('\n').trim()
|
|
82
78
|
const died =
|
|
83
|
-
out.
|
|
84
|
-
? ` The runner itself failed to start or was stopped: ${out.
|
|
85
|
-
: out.
|
|
86
|
-
? ` The runner was killed by ${out.
|
|
87
|
-
: found.size === 0 && out.
|
|
88
|
-
? ` The runner exited ${String(out.
|
|
79
|
+
out.why !== ''
|
|
80
|
+
? ` The runner itself failed to start or was stopped: ${out.why}.`
|
|
81
|
+
: out.killed !== null
|
|
82
|
+
? ` The runner was killed by ${out.killed} after ${String(within ?? 0)} ms. The last "settle: running" line above names the command it was inside, and everything after that one is unreported rather than refused.`
|
|
83
|
+
: found.size === 0 && !out.ok
|
|
84
|
+
? ` The runner exited ${String(out.code)} having reported nothing, so it died before the first command finished.`
|
|
89
85
|
: ''
|
|
90
86
|
let firstUnreached = true
|
|
91
87
|
return commands.map((one) => {
|
|
@@ -127,7 +123,7 @@ export function settling(
|
|
|
127
123
|
while (round < ROUNDS) {
|
|
128
124
|
round += 1
|
|
129
125
|
|
|
130
|
-
const asking =
|
|
126
|
+
const asking = batch(at, mine.map((one) => word(one.runs))).refused
|
|
131
127
|
const unhappy = mine.filter((one) => asking.includes(word(one.runs)))
|
|
132
128
|
if (unhappy.length === 0) return { ran, unsettled: [], rounds: round }
|
|
133
129
|
|
package/dist/core/condition.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Actor } from './actor.ts';
|
|
2
|
-
export declare const COMPARE_OPS: readonly [
|
|
2
|
+
export declare const COMPARE_OPS: readonly ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in', 'has'];
|
|
3
3
|
export type CompareOp = (typeof COMPARE_OPS)[number];
|
|
4
|
-
export declare const AGGREGATIONS: readonly [
|
|
5
|
-
export declare const ACTOR_FACTS: readonly ["id", "roles", "entitlements", ...("
|
|
4
|
+
export declare const AGGREGATIONS: readonly ['count', 'sum', 'min', 'max', 'avg'];
|
|
5
|
+
export declare const ACTOR_FACTS: readonly ["id", "roles", "entitlements", ...("address" | "device" | "moment" | "replay" | "run")[]];
|
|
6
6
|
export declare const AGO: RegExp;
|
|
7
7
|
export type Operand = {
|
|
8
8
|
readonly value: string | number | boolean | null;
|
|
@@ -41,7 +41,7 @@ export declare function walkOperands(condition: Condition, take: (one: Operand)
|
|
|
41
41
|
export declare function mentionsActor(condition: Condition): boolean;
|
|
42
42
|
export declare function agoSeconds(ago: string): number | undefined;
|
|
43
43
|
export declare function satisfies(condition: Condition, actor: Actor): boolean;
|
|
44
|
-
export declare const CONDITION_ANSWERS: readonly [
|
|
44
|
+
export declare const CONDITION_ANSWERS: readonly ['is', 'than', 'field', 'value', 'actor', 'ago', 'of', 'how', 'over', 'op', 'when', 'joins'];
|
|
45
45
|
export declare function conditioned(ask: (key: string, question: string) => Promise<string>, say: (line: string) => void, subject: {
|
|
46
46
|
readonly id: string;
|
|
47
47
|
readonly fields: readonly string[];
|
package/dist/core/condition.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ENVIRONMENT } from
|
|
1
|
+
import { ENVIRONMENT } from './actor.js';
|
|
2
2
|
export const COMPARE_OPS = ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in', 'has'];
|
|
3
3
|
export const AGGREGATIONS = ['count', 'sum', 'min', 'max', 'avg'];
|
|
4
4
|
export const ACTOR_FACTS = ['id', 'roles', 'entitlements', ...ENVIRONMENT.map(([fact]) => fact)];
|
|
@@ -182,7 +182,7 @@ export async function conditioned(ask, say, subject, all) {
|
|
|
182
182
|
const first = held[0];
|
|
183
183
|
return held.length === 1 ? first : joiner === 'all' ? { all: held } : { any: held };
|
|
184
184
|
}
|
|
185
|
-
import { quoted } from
|
|
185
|
+
import { quoted } from './rows.js';
|
|
186
186
|
export function said(one) {
|
|
187
187
|
if (typeof one === 'string')
|
|
188
188
|
return quoted(one);
|
package/dist/core/descend.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const ROOT: string;
|
|
|
4
4
|
export declare const TREE: string;
|
|
5
5
|
export declare const THREAD_AT: string;
|
|
6
6
|
export declare function unkept(at: string): boolean;
|
|
7
|
-
export declare const LISTS: readonly [
|
|
7
|
+
export declare const LISTS: readonly ['declares', 'derives', 'seeds'];
|
|
8
8
|
export declare const ROW_LISTS: readonly ["declares", "derives", "seeds", "holds"];
|
|
9
9
|
export interface Row {
|
|
10
10
|
readonly at?: string;
|
|
@@ -59,6 +59,7 @@ export declare function shapeFields(named: string, inside?: string): readonly {
|
|
|
59
59
|
readonly map: boolean;
|
|
60
60
|
readonly worded: boolean;
|
|
61
61
|
readonly guide: string;
|
|
62
|
+
readonly record: readonly string[];
|
|
62
63
|
}[];
|
|
63
64
|
export interface Field {
|
|
64
65
|
readonly name: string;
|
|
@@ -68,9 +69,10 @@ export interface Field {
|
|
|
68
69
|
readonly boolean: boolean;
|
|
69
70
|
readonly worded: boolean;
|
|
70
71
|
readonly guide: string;
|
|
72
|
+
readonly record: readonly string[];
|
|
71
73
|
}
|
|
72
74
|
export declare function listShape(at: string, list: string): string | undefined;
|
|
73
|
-
export declare function listFields(at: string, list: string): readonly Field[];
|
|
75
|
+
export declare function listFields(at: string, list: string, within?: number): readonly Field[];
|
|
74
76
|
export declare function rowShape(at: string, list: string): string | undefined;
|
|
75
77
|
interface Held {
|
|
76
78
|
readonly name: string;
|
package/dist/core/descend.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { attached, existsSync, kind, readdirSync, readFileSync, realpathSync, statSync, writeFileSync } from
|
|
1
|
+
import { starts } from '../integrations/cli.js';
|
|
2
|
+
import { attached, beyond, existsSync, here as answering, kind, readdirSync, readFileSync, realpathSync, statSync, writeFileSync } from '../integrations/disk.js';
|
|
3
3
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
4
4
|
import ts from 'typescript';
|
|
5
|
-
import { ignored } from
|
|
6
|
-
import { NAMED, ORGANISATION } from
|
|
7
|
-
import { findTree } from
|
|
5
|
+
import { ignored } from './init.js';
|
|
6
|
+
import { NAMED, ORGANISATION } from './scope.js';
|
|
7
|
+
import { findTree } from './tree.js';
|
|
8
8
|
const BUILT = new Set(ignored()
|
|
9
9
|
.split('\n')
|
|
10
10
|
.map((one) => one.trim())
|
|
@@ -32,7 +32,7 @@ function ownIgnores() {
|
|
|
32
32
|
if (readIgnores)
|
|
33
33
|
return ignores;
|
|
34
34
|
readIgnores = true;
|
|
35
|
-
if (!attached() &&
|
|
35
|
+
if (!attached() && starts('git', ['rev-parse', '--is-inside-work-tree'], { at: ROOT }).ok) {
|
|
36
36
|
return ignores;
|
|
37
37
|
}
|
|
38
38
|
try {
|
|
@@ -55,7 +55,7 @@ export function unkept(at) {
|
|
|
55
55
|
return held;
|
|
56
56
|
const own = ownIgnores();
|
|
57
57
|
const found = own === undefined
|
|
58
|
-
?
|
|
58
|
+
? starts('git', ['check-ignore', '-q', '--', at], { at: ROOT }).ok
|
|
59
59
|
: own.some((one) => at === one || at.startsWith(`${one}/`) || at.split('/').includes(one));
|
|
60
60
|
asked.set(at, found);
|
|
61
61
|
return found;
|
|
@@ -198,7 +198,7 @@ function listing(at, take, skip, only, deep) {
|
|
|
198
198
|
function parsing(from) {
|
|
199
199
|
return {
|
|
200
200
|
useCaseSensitiveFileNames: true,
|
|
201
|
-
fileExists: (at) => existsSync(at),
|
|
201
|
+
fileExists: (at) => !beyond(at) && existsSync(at),
|
|
202
202
|
readFile: (at) => {
|
|
203
203
|
try {
|
|
204
204
|
return readFileSync(at);
|
|
@@ -237,23 +237,34 @@ export function configured() {
|
|
|
237
237
|
}
|
|
238
238
|
return { options: { ...FALLBACK, ...INVARIANT }, from: '' };
|
|
239
239
|
}
|
|
240
|
+
const libraries = new Map();
|
|
241
|
+
const DEPENDENCIES = '/node_' + 'modules/';
|
|
240
242
|
export function hosting(options) {
|
|
241
243
|
const host = ts.createCompilerHost(options, true);
|
|
242
244
|
const lib = host.getDefaultLibLocation?.();
|
|
245
|
+
const settings = JSON.stringify(options);
|
|
243
246
|
const toolchain = (at) => lib !== undefined && (at === lib || at.startsWith(`${lib}/`));
|
|
247
|
+
const seen = (at) => (beyond(at) ? 'none' : kind(at));
|
|
244
248
|
return {
|
|
245
249
|
...host,
|
|
246
|
-
fileExists: (at) => (toolchain(at) ? host.fileExists(at) :
|
|
247
|
-
directoryExists: (at) => (toolchain(at) ? (host.directoryExists?.(at) ?? false) :
|
|
248
|
-
readFile: (at) => (toolchain(at) ? host.readFile(at) :
|
|
250
|
+
fileExists: (at) => (toolchain(at) ? host.fileExists(at) : seen(at) === 'file'),
|
|
251
|
+
directoryExists: (at) => (toolchain(at) ? (host.directoryExists?.(at) ?? false) : seen(at) === 'folder'),
|
|
252
|
+
readFile: (at) => (toolchain(at) ? host.readFile(at) : seen(at) === 'file' ? readFileSync(at) : undefined),
|
|
249
253
|
getSourceFile: (at, version) => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
return
|
|
254
|
-
|
|
254
|
+
const lasting = toolchain(at) ? true : at.includes(DEPENDENCIES);
|
|
255
|
+
const key = settings + at + JSON.stringify(version);
|
|
256
|
+
if (lasting && libraries.has(key))
|
|
257
|
+
return libraries.get(key);
|
|
258
|
+
const made = toolchain(at)
|
|
259
|
+
? host.getSourceFile(at, version)
|
|
260
|
+
: seen(at) === 'file'
|
|
261
|
+
? ts.createSourceFile(at, readFileSync(at), version, true)
|
|
262
|
+
: undefined;
|
|
263
|
+
if (lasting)
|
|
264
|
+
libraries.set(key, made);
|
|
265
|
+
return made;
|
|
255
266
|
},
|
|
256
|
-
getDirectories: (at) =>
|
|
267
|
+
getDirectories: (at) => seen(at) === 'folder' ? readdirSync(at, { withFileTypes: true }).filter((one) => one.isDirectory()).map((one) => one.name) : [],
|
|
257
268
|
realpath: (at) => (toolchain(at) ? (host.realpath?.(at) ?? at) : realpathSync(at)),
|
|
258
269
|
writeFile: (at, said) => {
|
|
259
270
|
writeFileSync(at, said);
|
|
@@ -328,8 +339,13 @@ export function read(at) {
|
|
|
328
339
|
source.set(at, text);
|
|
329
340
|
return text;
|
|
330
341
|
}
|
|
342
|
+
const shapes = new WeakMap();
|
|
331
343
|
export function shapesNamed() {
|
|
332
|
-
const
|
|
344
|
+
const held = compiled();
|
|
345
|
+
const known = shapes.get(held);
|
|
346
|
+
if (known !== undefined)
|
|
347
|
+
return known;
|
|
348
|
+
const { program, checker } = held;
|
|
333
349
|
const shape = threadedType(checker, program);
|
|
334
350
|
const found = new Map();
|
|
335
351
|
if (shape === undefined)
|
|
@@ -368,6 +384,7 @@ export function shapesNamed() {
|
|
|
368
384
|
found.set(named, [...where, at]);
|
|
369
385
|
}
|
|
370
386
|
}
|
|
387
|
+
shapes.set(held, found);
|
|
371
388
|
return found;
|
|
372
389
|
}
|
|
373
390
|
export function threading() {
|
|
@@ -408,13 +425,14 @@ export function shapeFields(named, inside) {
|
|
|
408
425
|
map: mapped(kind),
|
|
409
426
|
worded: (kind.isUnion() ? kind.types : [kind]).some((each) => (each.flags & ts.TypeFlags.StringLike) !== 0),
|
|
410
427
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
428
|
+
record: recordOf(checker, kind),
|
|
411
429
|
};
|
|
412
430
|
});
|
|
413
431
|
}
|
|
414
432
|
}
|
|
415
433
|
return [];
|
|
416
434
|
}
|
|
417
|
-
function elementAt(at, list) {
|
|
435
|
+
function elementAt(at, list, within) {
|
|
418
436
|
const { program, checker } = compiled();
|
|
419
437
|
const file = program.getSourceFile(resolve(ROOT, at));
|
|
420
438
|
if (file === undefined)
|
|
@@ -424,6 +442,8 @@ function elementAt(at, list) {
|
|
|
424
442
|
const consider = (node) => {
|
|
425
443
|
if (held !== undefined)
|
|
426
444
|
return;
|
|
445
|
+
if (within !== undefined && node.getStart() !== within)
|
|
446
|
+
return;
|
|
427
447
|
const wanted = checker.getContextualType(node) ?? checker.getTypeAtLocation(node);
|
|
428
448
|
const kinds = (wanted.isUnionOrIntersection() ? wanted.types : [wanted])
|
|
429
449
|
.filter((one) => checker.getIndexTypeOfType(one, ts.IndexKind.Number) !== undefined)
|
|
@@ -455,8 +475,8 @@ export function listShape(at, list) {
|
|
|
455
475
|
const held = elementAt(at, list);
|
|
456
476
|
return held === undefined ? undefined : compiled().checker.typeToString(held.type);
|
|
457
477
|
}
|
|
458
|
-
export function listFields(at, list) {
|
|
459
|
-
const held = elementAt(at, list);
|
|
478
|
+
export function listFields(at, list, within) {
|
|
479
|
+
const held = elementAt(at, list, within);
|
|
460
480
|
if (held === undefined)
|
|
461
481
|
return [];
|
|
462
482
|
const { checker } = compiled();
|
|
@@ -480,12 +500,29 @@ export function listFields(at, list) {
|
|
|
480
500
|
boolean: flagged(kind),
|
|
481
501
|
worded: worded(kind),
|
|
482
502
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
503
|
+
record: recordOf(checker, kind),
|
|
483
504
|
};
|
|
484
505
|
});
|
|
485
506
|
}
|
|
486
507
|
function elementOf(checker, type) {
|
|
487
508
|
return checker.getIndexTypeOfType(type, ts.IndexKind.Number) ?? type;
|
|
488
509
|
}
|
|
510
|
+
function recordOf(checker, type) {
|
|
511
|
+
for (const each of type.isUnion() ? type.types : [type]) {
|
|
512
|
+
if ((each.flags & ts.TypeFlags.StringLike) !== 0 || checker.getIndexTypeOfType(each, ts.IndexKind.Number) === undefined)
|
|
513
|
+
continue;
|
|
514
|
+
const element = elementOf(checker, each);
|
|
515
|
+
if ((element.flags & ts.TypeFlags.Object) === 0)
|
|
516
|
+
return [];
|
|
517
|
+
const fields = checker.getPropertiesOfType(element);
|
|
518
|
+
const worded = fields.every((one) => {
|
|
519
|
+
const kind = checker.getNonNullableType(checker.getTypeOfSymbol(one));
|
|
520
|
+
return (kind.isUnion() ? kind.types : [kind]).every((part) => (part.flags & ts.TypeFlags.StringLike) !== 0);
|
|
521
|
+
});
|
|
522
|
+
return worded ? fields.map((one) => one.getName()) : [];
|
|
523
|
+
}
|
|
524
|
+
return [];
|
|
525
|
+
}
|
|
489
526
|
export function rowShape(at, list) {
|
|
490
527
|
const { program, checker } = compiled();
|
|
491
528
|
const file = program.getSourceFile(resolve(ROOT, at));
|
|
@@ -666,7 +703,38 @@ let passed;
|
|
|
666
703
|
export function reached() {
|
|
667
704
|
return [THREAD_AT, ...descend().threaded.keys()];
|
|
668
705
|
}
|
|
706
|
+
let world = answering();
|
|
707
|
+
const worlds = new WeakMap();
|
|
708
|
+
function kept() {
|
|
709
|
+
const was = { passed, built, scanned, commands, ignores, readIgnores, source: new Map(source), asked: new Map(asked) };
|
|
710
|
+
return () => {
|
|
711
|
+
passed = was.passed;
|
|
712
|
+
built = was.built;
|
|
713
|
+
scanned = was.scanned;
|
|
714
|
+
commands = was.commands;
|
|
715
|
+
ignores = was.ignores;
|
|
716
|
+
readIgnores = was.readIgnores;
|
|
717
|
+
source.clear();
|
|
718
|
+
for (const [at, text] of was.source)
|
|
719
|
+
source.set(at, text);
|
|
720
|
+
asked.clear();
|
|
721
|
+
for (const [at, ignore] of was.asked)
|
|
722
|
+
asked.set(at, ignore);
|
|
723
|
+
};
|
|
724
|
+
}
|
|
669
725
|
export function forget() {
|
|
726
|
+
const now = answering();
|
|
727
|
+
if (now === world)
|
|
728
|
+
libraries.clear();
|
|
729
|
+
else {
|
|
730
|
+
worlds.set(world, kept());
|
|
731
|
+
world = now;
|
|
732
|
+
const back = worlds.get(now);
|
|
733
|
+
if (back !== undefined) {
|
|
734
|
+
back();
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
670
738
|
passed = undefined;
|
|
671
739
|
built = undefined;
|
|
672
740
|
scanned = undefined;
|