@prestack/thread 0.1.3 → 0.1.5

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 (270) hide show
  1. package/CHANGELOG.md +563 -0
  2. package/dist/core/actor.d.ts +1 -1
  3. package/dist/core/actor.js +5 -4
  4. package/dist/core/actor.ts +5 -4
  5. package/dist/core/attach.d.ts +0 -7
  6. package/dist/core/attach.js +38 -67
  7. package/dist/core/attach.ts +34 -80
  8. package/dist/core/chain.js +13 -17
  9. package/dist/core/chain.ts +11 -15
  10. package/dist/core/condition.d.ts +4 -4
  11. package/dist/core/condition.js +2 -2
  12. package/dist/core/descend.d.ts +4 -2
  13. package/dist/core/descend.js +91 -23
  14. package/dist/core/descend.ts +90 -21
  15. package/dist/core/errors/catalogue.d.ts +52 -0
  16. package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
  17. package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
  18. package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
  19. package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
  20. package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
  21. package/dist/core/errors/namespaces.d.ts +3 -0
  22. package/dist/core/errors/namespaces.js +15 -0
  23. package/dist/core/errors/namespaces.ts +19 -0
  24. package/dist/core/finding.js +2 -2
  25. package/dist/core/finding.ts +1 -2
  26. package/dist/core/init.d.ts +1 -1
  27. package/dist/core/init.js +51 -5
  28. package/dist/core/init.ts +58 -5
  29. package/dist/core/invoked.d.ts +1 -1
  30. package/dist/core/invoked.js +3 -1
  31. package/dist/core/invoked.ts +5 -2
  32. package/dist/core/round.js +36 -22
  33. package/dist/core/round.ts +26 -9
  34. package/dist/core/rows.d.ts +4 -0
  35. package/dist/core/rows.js +31 -2
  36. package/dist/core/rows.ts +33 -1
  37. package/dist/core/scope.d.ts +1 -0
  38. package/dist/core/scope.js +1 -0
  39. package/dist/core/scope.ts +2 -0
  40. package/dist/core/thread.d.ts +3 -3
  41. package/dist/core/tree.d.ts +4 -1
  42. package/dist/core/tree.js +26 -6
  43. package/dist/core/tree.ts +29 -6
  44. package/dist/core/types.d.ts +3 -3
  45. package/dist/core/types.js +3 -1
  46. package/dist/core/types.ts +2 -1
  47. package/dist/derivation/attach.js +3 -2
  48. package/dist/derivation/attach.ts +2 -1
  49. package/dist/derivation/generators/build.js +6 -6
  50. package/dist/derivation/generators/build.ts +1 -1
  51. package/dist/derivation/generators/check.js +1 -1
  52. package/dist/derivation/generators/determinism.js +1 -1
  53. package/dist/derivation/generators/release.js +60 -47
  54. package/dist/derivation/generators/release.ts +66 -43
  55. package/dist/derivation/release.d.ts +7 -3
  56. package/dist/derivation/release.js +14 -1
  57. package/dist/derivation/release.ts +22 -2
  58. package/dist/integrations/attach.d.ts +4 -0
  59. package/dist/integrations/attach.js +37 -56
  60. package/dist/integrations/attach.ts +54 -60
  61. package/dist/integrations/cli.d.ts +37 -0
  62. package/dist/integrations/cli.js +440 -0
  63. package/dist/integrations/cli.ts +543 -0
  64. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -24
  65. package/dist/integrations/disk.js +435 -0
  66. package/dist/integrations/disk.ts +465 -0
  67. package/dist/integrations/generators/read.js +6 -6
  68. package/dist/integrations/generators/read.ts +4 -4
  69. package/dist/integrations/generators/vault.js +10 -11
  70. package/dist/integrations/generators/vault.ts +4 -5
  71. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  72. package/dist/integrations/https.js +170 -0
  73. package/dist/integrations/https.ts +216 -0
  74. package/dist/integrations/pglite.d.ts +26 -0
  75. package/dist/integrations/pglite.js +143 -0
  76. package/dist/integrations/pglite.ts +206 -0
  77. package/dist/integrations/secret.d.ts +8 -2
  78. package/dist/integrations/secret.js +3 -5
  79. package/dist/integrations/secret.ts +10 -6
  80. package/dist/integrations/target.d.ts +155 -14
  81. package/dist/integrations/target.js +171 -50
  82. package/dist/integrations/target.ts +377 -61
  83. package/dist/integrations/vault.d.ts +1 -0
  84. package/dist/integrations/vault.js +20 -5
  85. package/dist/integrations/vault.ts +17 -5
  86. package/dist/integrity/attach.js +8 -77
  87. package/dist/integrity/attach.ts +7 -76
  88. package/dist/integrity/check-threads.js +5 -5
  89. package/dist/integrity/check-threads.ts +2 -2
  90. package/dist/integrity/constraint.d.ts +0 -1
  91. package/dist/integrity/constraint.js +267 -366
  92. package/dist/integrity/constraint.ts +267 -375
  93. package/dist/integrity/generators/compiler.js +14 -17
  94. package/dist/integrity/generators/compiler.ts +10 -15
  95. package/dist/integrity/generators/gate.js +15 -15
  96. package/dist/integrity/generators/gate.ts +10 -10
  97. package/dist/integrity/generators/issues.js +7 -7
  98. package/dist/integrity/generators/publish.js +39 -57
  99. package/dist/integrity/generators/publish.ts +44 -55
  100. package/dist/integrity/generators/trial.d.ts +3 -3
  101. package/dist/integrity/generators/trial.js +133 -165
  102. package/dist/integrity/generators/trial.ts +145 -169
  103. package/dist/integrity/lint.js +9 -13
  104. package/dist/integrity/lint.ts +7 -10
  105. package/dist/integrity/lsp/bin.js +5 -4
  106. package/dist/integrity/lsp/bin.ts +3 -1
  107. package/dist/integrity/lsp/diagnostics.js +3 -3
  108. package/dist/integrity/lsp/diagnostics.ts +1 -1
  109. package/dist/integrity/lsp/lint.js +19 -30
  110. package/dist/integrity/lsp/lint.ts +16 -32
  111. package/dist/integrity/lsp/server.js +3 -3
  112. package/dist/integrity/slopnator.d.ts +3 -13
  113. package/dist/integrity/slopnator.js +59 -38
  114. package/dist/integrity/slopnator.ts +54 -38
  115. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  116. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  117. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  118. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  119. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  120. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  121. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  122. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  123. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  124. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  125. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  126. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  127. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  128. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  129. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  130. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  131. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  132. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  133. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  134. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  135. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  136. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  137. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  138. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  139. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  140. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  141. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  142. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  143. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  144. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  145. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  146. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  147. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  148. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  149. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  150. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  151. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  152. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  153. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  154. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  155. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  156. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  157. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  158. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  159. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  160. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  161. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  162. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  163. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  164. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  165. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  166. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  167. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  168. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  169. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  170. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  171. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  172. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  173. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  174. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  175. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  176. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  177. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  178. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  179. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  180. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  181. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  182. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  183. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  184. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  185. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  186. package/dist/integrity/sweep.d.ts +1 -0
  187. package/dist/integrity/sweep.js +105 -42
  188. package/dist/integrity/sweep.ts +115 -42
  189. package/dist/knowledge/attach.js +4 -3
  190. package/dist/knowledge/attach.ts +3 -2
  191. package/dist/knowledge/generators/docsgen.js +8 -6
  192. package/dist/knowledge/generators/docsgen.ts +4 -2
  193. package/dist/knowledge/generators/glossary.js +4 -4
  194. package/dist/knowledge/generators/glossary.ts +1 -1
  195. package/dist/operations/access.d.ts +23 -0
  196. package/dist/operations/access.js +28 -1
  197. package/dist/operations/access.ts +43 -0
  198. package/dist/operations/attach.js +33 -113
  199. package/dist/operations/attach.ts +51 -117
  200. package/dist/operations/capabilities.d.ts +14 -5
  201. package/dist/operations/capabilities.js +13 -4
  202. package/dist/operations/capabilities.ts +27 -8
  203. package/dist/operations/dispatch.d.ts +8 -2
  204. package/dist/operations/dispatch.js +128 -185
  205. package/dist/operations/dispatch.ts +138 -191
  206. package/dist/operations/error-results.d.ts +1 -1
  207. package/dist/operations/error-results.js +2 -2
  208. package/dist/operations/error-results.ts +2 -2
  209. package/dist/operations/generators/capability.d.ts +11 -1
  210. package/dist/operations/generators/capability.js +481 -224
  211. package/dist/operations/generators/capability.ts +562 -233
  212. package/dist/operations/generators/compile.js +66 -39
  213. package/dist/operations/generators/compile.ts +78 -39
  214. package/dist/operations/generators/permits.js +11 -12
  215. package/dist/operations/generators/permits.ts +3 -4
  216. package/dist/operations/generators/seed.d.ts +1 -0
  217. package/dist/operations/generators/seed.js +19 -17
  218. package/dist/operations/generators/seed.ts +22 -14
  219. package/dist/operations/generators/trial.d.ts +6 -8
  220. package/dist/operations/generators/trial.js +200 -70
  221. package/dist/operations/generators/trial.ts +230 -93
  222. package/dist/operations/nodes.d.ts +15 -16
  223. package/dist/operations/nodes.ts +16 -17
  224. package/dist/operations/operations.d.ts +40 -4
  225. package/dist/operations/operations.js +1 -0
  226. package/dist/operations/operations.ts +61 -4
  227. package/dist/operations/result.d.ts +2 -2
  228. package/dist/operations/result.ts +2 -2
  229. package/package.json +1 -4
  230. package/dist/core/answers.d.ts +0 -171
  231. package/dist/core/answers.js +0 -789
  232. package/dist/core/answers.ts +0 -999
  233. package/dist/core/client.d.ts +0 -63
  234. package/dist/core/client.js +0 -249
  235. package/dist/core/client.ts +0 -289
  236. package/dist/core/files.js +0 -171
  237. package/dist/core/files.ts +0 -222
  238. package/dist/integrations/module.d.ts +0 -6
  239. package/dist/integrations/module.js +0 -153
  240. package/dist/integrations/module.ts +0 -191
  241. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  242. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  243. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  244. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  245. package/dist/operations/cost.d.ts +0 -14
  246. package/dist/operations/cost.js +0 -37
  247. package/dist/operations/cost.ts +0 -58
  248. package/dist/operations/errors/errors.d.ts +0 -52
  249. package/dist/operations/http.js +0 -124
  250. package/dist/operations/http.ts +0 -169
  251. package/dist/operations/memory.d.ts +0 -104
  252. package/dist/operations/memory.js +0 -365
  253. package/dist/operations/memory.ts +0 -470
  254. package/dist/operations/metering.d.ts +0 -55
  255. package/dist/operations/metering.js +0 -247
  256. package/dist/operations/metering.ts +0 -328
  257. package/dist/operations/queue-policy.d.ts +0 -3
  258. package/dist/operations/queue-policy.js +0 -8
  259. package/dist/operations/queue-policy.ts +0 -10
  260. package/dist/operations/seams.d.ts +0 -239
  261. package/dist/operations/seams.js +0 -45
  262. package/dist/operations/seams.ts +0 -364
  263. package/dist/operations/store.d.ts +0 -14
  264. package/dist/operations/store.js +0 -1
  265. package/dist/operations/store.ts +0 -29
  266. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  267. /package/dist/{operations → core}/errors/classes.js +0 -0
  268. /package/dist/{operations → core}/errors/classes.ts +0 -0
  269. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  270. /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
@@ -3,18 +3,6 @@ export declare const NOT_WRITTEN: unique symbol;
3
3
  export declare const SHIPPED: string;
4
4
  export declare const SEEDED: string;
5
5
  export declare const ROOT: string;
6
- export declare const DEPTH = "THREAD_DEPTH";
7
- export declare const CEILING = 1;
8
- export declare const SPAWN_TIMEOUT = 120000;
9
- export declare const SPAWN_BUFFER: number;
10
- export declare function nested(): boolean;
11
- export declare function ran(command: string, options: {
12
- readonly cwd: string;
13
- readonly args?: readonly string[];
14
- }): {
15
- readonly status: number | null;
16
- readonly said: string;
17
- } | undefined;
18
6
  export interface SlopnatorContext {
19
7
  readonly filename: string;
20
8
  readonly text: string;
@@ -53,7 +41,9 @@ export interface Byproduct {
53
41
  readonly content: string;
54
42
  }
55
43
  export declare function slopnatorName(rule: string): string;
56
- export declare function names(fragment: string, path: readonly string[]): boolean;
44
+ export declare function region(fragment: string, path: readonly string[]): boolean;
45
+ export declare function derivedHere(): ReadonlySet<string> | undefined;
46
+ export declare function subject(rule: Constraint): boolean;
57
47
  export declare function governs(rule: Constraint, filename: string): boolean;
58
48
  export declare class UnloadableSlopnatorError extends Error {
59
49
  constructor(rule: string, at: string, because: string);
@@ -6,14 +6,15 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- import { spawnSync } from 'node:child_process';
10
- import { existsSync, readFileSync, readdirSync, writeFileSync } from "../core/files.js";
9
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from '../integrations/disk.js';
11
10
  import { dirname, join } from 'node:path';
12
11
  import { fileURLToPath, pathToFileURL } from 'node:url';
13
- import { invoked } from "../core/invoked.js";
14
- import { listBounds, quoted, withSeed } from "../core/rows.js";
15
- import { CONSTRAINTS } from "./constraint.js";
16
- import { findTree, inTree } from "../core/tree.js";
12
+ import { descend } from '../core/descend.js';
13
+ import { governs as reaches, islandsDeclared } from './slopnators/sl_unthreaded.js';
14
+ import { invoked } from '../core/invoked.js';
15
+ import { listBounds, quoted, withSeed } from '../core/rows.js';
16
+ import { CONSTRAINTS } from './constraint.js';
17
+ import { findTree, inTree } from '../core/tree.js';
17
18
  export const NOT_WRITTEN = Symbol.for('thread.slopnator.not_written');
18
19
  const HOME = dirname(fileURLToPath(import.meta.url));
19
20
  export const SHIPPED = `${HOME}/slopnators`;
@@ -22,29 +23,6 @@ function homes(root) {
22
23
  return [SHIPPED, join(root, SEEDED)];
23
24
  }
24
25
  export const ROOT = `${findTree().at}/`;
25
- export const DEPTH = 'THREAD_DEPTH';
26
- export const CEILING = 1;
27
- export const SPAWN_TIMEOUT = 120_000;
28
- export const SPAWN_BUFFER = 8 * 1024 * 1024;
29
- export function nested() {
30
- return Number(process.env[DEPTH] ?? '0') >= CEILING;
31
- }
32
- export function ran(command, options) {
33
- if (nested())
34
- return undefined;
35
- const depth = Number(process.env[DEPTH] ?? '0');
36
- const out = spawnSync(command, [...(options.args ?? [])], {
37
- shell: options.args === undefined,
38
- cwd: options.cwd,
39
- encoding: 'utf8',
40
- stdio: ['ignore', 'pipe', 'pipe'],
41
- timeout: SPAWN_TIMEOUT,
42
- killSignal: 'SIGKILL',
43
- maxBuffer: SPAWN_BUFFER,
44
- env: { ...process.env, [DEPTH]: String(depth + 1) },
45
- });
46
- return { status: out.status, said: `${String(out.stdout ?? '')}${String(out.stderr ?? '')}` };
47
- }
48
26
  export const reads = (one) => 'holds' in one;
49
27
  export const visits = (one) => 'holds' in one && one.on !== undefined;
50
28
  export const sweeps = (one) => 'holds' in one && one.on === undefined;
@@ -63,7 +41,10 @@ function wanted(fragment) {
63
41
  const all = parts(fragment);
64
42
  return all[0] === CANONICAL_TREE ? [TREE, ...all.slice(1)] : all;
65
43
  }
66
- export function names(fragment, path) {
44
+ function holding(want, path, from) {
45
+ return want.every((part, step) => part === path[from + step]);
46
+ }
47
+ export function region(fragment, path) {
67
48
  if (fragment === '.')
68
49
  return true;
69
50
  const want = wanted(fragment);
@@ -71,17 +52,57 @@ export function names(fragment, path) {
71
52
  return false;
72
53
  if (!fragment.endsWith('/'))
73
54
  return want.join('/') === path.join('/');
74
- for (let at = 0; at + want.length < path.length; at += 1) {
75
- if (want.every((part, step) => part === path[at + step]))
76
- return true;
55
+ return want.length < path.length && holding(want, path, 0);
56
+ }
57
+ let written;
58
+ export function derivedHere() {
59
+ if (written !== undefined)
60
+ return written;
61
+ try {
62
+ const found = new Set();
63
+ for (const [at, threadings] of descend().threaded) {
64
+ if (threadings.some((one) => one.list === 'derives' && (one.row.by ?? one.row.runs) !== undefined))
65
+ found.add(at);
66
+ }
67
+ written = found;
68
+ return written;
69
+ }
70
+ catch {
71
+ return undefined;
77
72
  }
78
- return false;
73
+ }
74
+ const islands = new WeakMap();
75
+ function islandsHere() {
76
+ try {
77
+ const pass = descend();
78
+ const known = islands.get(pass);
79
+ if (known !== undefined)
80
+ return known;
81
+ const named = new Map(islandsDeclared().map((one) => [one.id, one.governs]));
82
+ islands.set(pass, named);
83
+ return named;
84
+ }
85
+ catch {
86
+ return undefined;
87
+ }
88
+ }
89
+ export function subject(rule) {
90
+ if (rule.governs === undefined)
91
+ return true;
92
+ const named = islandsHere();
93
+ return named === undefined || named.has(rule.governs);
79
94
  }
80
95
  export function governs(rule, filename) {
81
- const path = parts(filename.startsWith(ROOT) ? filename.slice(ROOT.length) : filename);
82
- if ((rule.where.except ?? []).some((fragment) => names(fragment, path)))
96
+ const under = filename.startsWith(ROOT) ? filename.slice(ROOT.length) : filename;
97
+ const path = parts(under);
98
+ if (rule.governs !== undefined) {
99
+ const body = islandsHere()?.get(rule.governs);
100
+ if (body !== undefined && reaches(body, under))
101
+ return false;
102
+ }
103
+ if (!rule.where.paths.some((fragment) => region(fragment, path)))
83
104
  return false;
84
- return rule.where.paths.some((fragment) => names(fragment, path));
105
+ return derivedHere()?.has(under) !== true;
85
106
  }
86
107
  export class UnloadableSlopnatorError extends Error {
87
108
  constructor(rule, at, because) {
@@ -105,7 +126,7 @@ export async function load(root, all) {
105
126
  for (const rule of all) {
106
127
  const name = slopnatorName(rule.id);
107
128
  const at = homes(root)
108
- .flatMap((dir) => [join(dir, `${name}.ts`), join(dir, `${name}.js`)])
129
+ .flatMap((dir) => [join(dir, `${name}.js`), join(dir, `${name}.ts`)])
109
130
  .find((one) => existsSync(one));
110
131
  if (at === undefined)
111
132
  continue;
@@ -1,8 +1,9 @@
1
- import { spawnSync } from 'node:child_process'
2
- import { existsSync, readFileSync, readdirSync, writeFileSync } from '../core/files.ts'
1
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from '../integrations/disk.ts'
3
2
  import { dirname, join } from 'node:path'
4
3
  import { fileURLToPath, pathToFileURL } from 'node:url'
5
4
 
5
+ import { descend } from '../core/descend.ts'
6
+ import { governs as reaches, islandsDeclared } from './slopnators/sl_unthreaded.ts'
6
7
  import { invoked } from '../core/invoked.ts'
7
8
 
8
9
  import { listBounds, quoted, withSeed } from '../core/rows.ts'
@@ -24,34 +25,6 @@ function homes(root: string): readonly string[] {
24
25
 
25
26
  export const ROOT = `${findTree().at}/`
26
27
 
27
- export const DEPTH = 'THREAD_DEPTH'
28
-
29
- export const CEILING = 1
30
-
31
- export const SPAWN_TIMEOUT = 120_000
32
-
33
- export const SPAWN_BUFFER = 8 * 1024 * 1024
34
-
35
- export function nested(): boolean {
36
- return Number(process.env[DEPTH] ?? '0') >= CEILING
37
- }
38
-
39
- export function ran(command: string, options: { readonly cwd: string; readonly args?: readonly string[] }): { readonly status: number | null; readonly said: string } | undefined {
40
- if (nested()) return undefined
41
- const depth = Number(process.env[DEPTH] ?? '0')
42
- const out = spawnSync(command, [...(options.args ?? [])], {
43
- shell: options.args === undefined,
44
- cwd: options.cwd,
45
- encoding: 'utf8',
46
- stdio: ['ignore', 'pipe', 'pipe'],
47
- timeout: SPAWN_TIMEOUT,
48
- killSignal: 'SIGKILL',
49
- maxBuffer: SPAWN_BUFFER,
50
- env: { ...process.env, [DEPTH]: String(depth + 1) },
51
- })
52
- return { status: out.status, said: `${String(out.stdout ?? '')}${String(out.stderr ?? '')}` }
53
- }
54
-
55
28
  export interface SlopnatorContext {
56
29
  readonly filename: string
57
30
  readonly text: string
@@ -119,21 +92,64 @@ function wanted(fragment: string): readonly string[] {
119
92
  return all[0] === CANONICAL_TREE ? [TREE, ...all.slice(1)] : all
120
93
  }
121
94
 
122
- export function names(fragment: string, path: readonly string[]): boolean {
95
+ function holding(want: readonly string[], path: readonly string[], from: number): boolean {
96
+ return want.every((part, step) => part === path[from + step])
97
+ }
98
+
99
+ export function region(fragment: string, path: readonly string[]): boolean {
123
100
  if (fragment === '.') return true
124
101
  const want = wanted(fragment)
125
102
  if (want.length === 0) return false
126
103
  if (!fragment.endsWith('/')) return want.join('/') === path.join('/')
127
- for (let at = 0; at + want.length < path.length; at += 1) {
128
- if (want.every((part, step) => part === path[at + step])) return true
104
+ return want.length < path.length && holding(want, path, 0)
105
+ }
106
+
107
+ let written: ReadonlySet<string> | undefined
108
+
109
+ export function derivedHere(): ReadonlySet<string> | undefined {
110
+ if (written !== undefined) return written
111
+ try {
112
+ const found = new Set<string>()
113
+ for (const [at, threadings] of descend().threaded) {
114
+ if (threadings.some((one) => one.list === 'derives' && (one.row.by ?? one.row.runs) !== undefined)) found.add(at)
115
+ }
116
+ written = found
117
+ return written
118
+ } catch {
119
+ return undefined
120
+ }
121
+ }
122
+
123
+ const islands = new WeakMap<object, ReadonlyMap<string, readonly string[]>>()
124
+
125
+ function islandsHere(): ReadonlyMap<string, readonly string[]> | undefined {
126
+ try {
127
+ const pass = descend()
128
+ const known = islands.get(pass)
129
+ if (known !== undefined) return known
130
+ const named = new Map(islandsDeclared().map((one) => [one.id, one.governs]))
131
+ islands.set(pass, named)
132
+ return named
133
+ } catch {
134
+ return undefined
129
135
  }
130
- return false
136
+ }
137
+
138
+ export function subject(rule: Constraint): boolean {
139
+ if (rule.governs === undefined) return true
140
+ const named = islandsHere()
141
+ return named === undefined || named.has(rule.governs)
131
142
  }
132
143
 
133
144
  export function governs(rule: Constraint, filename: string): boolean {
134
- const path = parts(filename.startsWith(ROOT) ? filename.slice(ROOT.length) : filename)
135
- if ((rule.where.except ?? []).some((fragment) => names(fragment, path))) return false
136
- return rule.where.paths.some((fragment) => names(fragment, path))
145
+ const under = filename.startsWith(ROOT) ? filename.slice(ROOT.length) : filename
146
+ const path = parts(under)
147
+ if (rule.governs !== undefined) {
148
+ const body = islandsHere()?.get(rule.governs)
149
+ if (body !== undefined && reaches(body, under)) return false
150
+ }
151
+ if (!rule.where.paths.some((fragment) => region(fragment, path))) return false
152
+ return derivedHere()?.has(under) !== true
137
153
  }
138
154
 
139
155
  export class UnloadableSlopnatorError extends Error {
@@ -164,7 +180,7 @@ export async function load(root: string, all: readonly Constraint[]): Promise<Re
164
180
  for (const rule of all) {
165
181
  const name = slopnatorName(rule.id)
166
182
  const at = homes(root)
167
- .flatMap((dir) => [join(dir, `${name}.ts`), join(dir, `${name}.js`)])
183
+ .flatMap((dir) => [join(dir, `${name}.js`), join(dir, `${name}.ts`)])
168
184
  .find((one) => existsSync(one))
169
185
  if (at === undefined) continue
170
186
 
@@ -1,5 +1,5 @@
1
- import { here, names, threaded, unreadable } from "./sl_unthreaded.js";
2
- import { findTree } from "../../core/tree.js";
1
+ import { here, names, threaded, unreadable } from './sl_unthreaded.js';
2
+ import { findTree } from '../../core/tree.js';
3
3
  const THREAD_AT = `${findTree().name}/thread.ts`;
4
4
  export const slopnator = {
5
5
  holds: (_node, at) => {
@@ -1,4 +1,4 @@
1
- import { filesGoverned, here, islandsDeclared } from "./sl_unthreaded.js";
1
+ import { filesGoverned, here, islandsDeclared } from './sl_unthreaded.js';
2
2
  const sentence = (describes) => `${describes.split(/ — |\. /)[0] ?? describes}.`;
3
3
  export const slopnator = {
4
4
  holds: (_node, at) => {
@@ -1,8 +1,8 @@
1
- import { readFileSync } from "../../core/files.js";
1
+ import { readFileSync } from '../../integrations/disk.js';
2
2
  import { resolve } from 'node:path';
3
- import { atsIn } from "./sl_unthreaded.js";
4
- import { reached } from "../../core/descend.js";
5
- import { findTree } from "../../core/tree.js";
3
+ import { atsIn } from './sl_unthreaded.js';
4
+ import { reached } from '../../core/descend.js';
5
+ import { findTree } from '../../core/tree.js';
6
6
  const ROOT = `${findTree().at}/`;
7
7
  export function derivations(root) {
8
8
  const found = [];
@@ -1,4 +1,4 @@
1
- import { readFileSync } from '../../core/files.ts'
1
+ import { readFileSync } from '../../integrations/disk.ts'
2
2
  import { resolve } from 'node:path'
3
3
 
4
4
  import type { Slopnator } from '../slopnator.ts'
@@ -0,0 +1,220 @@
1
+ import { resolve } from 'node:path';
2
+ import ts from 'typescript';
3
+ import { ROOT, configured, hosting } from '../../core/descend.js';
4
+ import { kind, readFileSync } from '../../integrations/disk.js';
5
+ import { OPENS } from '../../integrations/target.js';
6
+ import { here } from './sl_unthreaded.js';
7
+ const IMPORTED = 'import ';
8
+ const MADE = 'new ';
9
+ const RUNTIME = 'node:';
10
+ const ANYWHERE = 'globalThis';
11
+ const REQUIRED = 'require';
12
+ const DECLARED = /\.d\.([cm]?)ts$/;
13
+ const READABLE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
14
+ const plain = (specifier) => (specifier.startsWith(RUNTIME) ? specifier.slice(RUNTIME.length) : specifier);
15
+ function doors() {
16
+ const modules = new Map();
17
+ const globals = new Map();
18
+ const properties = new Map();
19
+ for (const [reach, spellings] of Object.entries(OPENS)) {
20
+ for (const spelling of spellings) {
21
+ const door = { reach, spelling };
22
+ if (spelling.startsWith(IMPORTED)) {
23
+ const rest = spelling.slice(IMPORTED.length);
24
+ const dot = rest.lastIndexOf('.');
25
+ modules.set(plain(dot === -1 || rest.slice(dot).includes('/') ? rest : rest.slice(0, dot)), door);
26
+ continue;
27
+ }
28
+ if (spelling.startsWith(MADE)) {
29
+ globals.set(spelling.slice(MADE.length), door);
30
+ continue;
31
+ }
32
+ if (spelling.includes('.'))
33
+ properties.set(spelling, door);
34
+ else
35
+ globals.set(spelling, door);
36
+ }
37
+ }
38
+ return { modules, globals, properties };
39
+ }
40
+ const DOORS = doors();
41
+ const files = new Map();
42
+ function parsed(at, text) {
43
+ const held = files.get(text);
44
+ if (held !== undefined)
45
+ return held;
46
+ const file = ts.createSourceFile(at, text, ts.ScriptTarget.Latest, true, at.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
47
+ files.set(text, file);
48
+ return file;
49
+ }
50
+ function brought(file) {
51
+ const found = [];
52
+ const line = (node) => file.getLineAndCharacterOfPosition(node.getStart(file)).line + 1;
53
+ const visit = (node) => {
54
+ if (ts.isImportDeclaration(node) && node.importClause?.isTypeOnly !== true && ts.isStringLiteral(node.moduleSpecifier)) {
55
+ found.push({ specifier: node.moduleSpecifier.text, line: line(node) });
56
+ }
57
+ if (ts.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && ts.isStringLiteral(node.moduleSpecifier)) {
58
+ found.push({ specifier: node.moduleSpecifier.text, line: line(node) });
59
+ }
60
+ if (ts.isCallExpression(node)) {
61
+ const first = node.arguments[0];
62
+ const loads = node.expression.kind === ts.SyntaxKind.ImportKeyword || (ts.isIdentifier(node.expression) && node.expression.text === REQUIRED);
63
+ if (loads && first !== undefined && ts.isStringLiteral(first))
64
+ found.push({ specifier: first.text, line: line(node) });
65
+ }
66
+ ts.forEachChild(node, visit);
67
+ };
68
+ visit(file);
69
+ return found;
70
+ }
71
+ const binds = (node) => {
72
+ const parent = node.parent;
73
+ return ((ts.isVariableDeclaration(parent) ||
74
+ ts.isParameter(parent) ||
75
+ ts.isBindingElement(parent) ||
76
+ ts.isFunctionDeclaration(parent) ||
77
+ ts.isClassDeclaration(parent) ||
78
+ ts.isImportSpecifier(parent) ||
79
+ ts.isImportClause(parent) ||
80
+ ts.isNamespaceImport(parent)) &&
81
+ parent.name === node);
82
+ };
83
+ const named = (node) => node.parent?.name === node;
84
+ const opened = new Map();
85
+ function opening(at, text) {
86
+ if (opened.has(text))
87
+ return opened.get(text);
88
+ const file = parsed(at, text);
89
+ let found;
90
+ for (const one of brought(file))
91
+ found ??= DOORS.modules.get(plain(one.specifier));
92
+ const bound = new Set();
93
+ const collect = (node) => {
94
+ if (ts.isIdentifier(node) && binds(node))
95
+ bound.add(node.text);
96
+ ts.forEachChild(node, collect);
97
+ };
98
+ collect(file);
99
+ const visit = (node) => {
100
+ if (found !== undefined)
101
+ return;
102
+ if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && !ts.isPartOfTypeNode(node)) {
103
+ const object = node.expression.text;
104
+ found = DOORS.properties.get(object + '.' + node.name.text) ?? (object === ANYWHERE ? DOORS.globals.get(node.name.text) : undefined);
105
+ }
106
+ if (found === undefined && ts.isIdentifier(node) && !named(node) && !ts.isPartOfTypeNode(node) && !bound.has(node.text)) {
107
+ found = DOORS.globals.get(node.text);
108
+ }
109
+ ts.forEachChild(node, visit);
110
+ };
111
+ visit(file);
112
+ opened.set(text, found);
113
+ return found;
114
+ }
115
+ let options;
116
+ let host;
117
+ function resolvedOf(specifier, from) {
118
+ options ??= configured().options;
119
+ host ??= hosting(options);
120
+ const found = ts.resolveModuleName(specifier, from, options, host).resolvedModule;
121
+ if (found === undefined)
122
+ return undefined;
123
+ const at = found.resolvedFileName;
124
+ if (!DECLARED.test(at))
125
+ return at;
126
+ const emitted = at.replace(DECLARED, '.$1js');
127
+ return kind(emitted) === 'file' ? emitted : undefined;
128
+ }
129
+ const readable = (at) => (READABLE.test(at) && kind(at) === 'file' ? readFileSync(at, 'utf8') : undefined);
130
+ const shown = (chain, door) => chain.map((one) => '`' + one + '`').join(', which imports ') +
131
+ (door.spelling.startsWith(IMPORTED) ? ', which imports ' + door.spelling.slice(IMPORTED.length) : ', which reaches ' + door.spelling) +
132
+ ' — the ' +
133
+ door.reach +
134
+ ' reach, and no target declares it. Nothing prices that reach, replays it in a trial or refuses it. Declare the place with `thread create target`, require it on the operation, and call what the node is handed instead';
135
+ function through(at, chain, seen) {
136
+ const text = readable(at);
137
+ if (text === undefined)
138
+ return undefined;
139
+ const door = opening(at, text);
140
+ if (door !== undefined)
141
+ return shown(chain, door);
142
+ for (const one of brought(parsed(at, text))) {
143
+ const next = resolvedOf(one.specifier, at);
144
+ if (next === undefined || seen.has(next))
145
+ continue;
146
+ seen.add(next);
147
+ const found = through(next, [...chain, one.specifier], seen);
148
+ if (found !== undefined)
149
+ return found;
150
+ }
151
+ return undefined;
152
+ }
153
+ export const slopnator = {
154
+ holds: (_node, at) => {
155
+ const path = here(at.filename);
156
+ if (!READABLE.test(path))
157
+ return false;
158
+ const from = resolve(ROOT, path);
159
+ const seen = new Set([from]);
160
+ for (const one of brought(parsed(from, at.text))) {
161
+ const next = resolvedOf(one.specifier, from);
162
+ if (next === undefined || seen.has(next))
163
+ continue;
164
+ seen.add(next);
165
+ const found = through(next, [one.specifier], seen);
166
+ if (found !== undefined)
167
+ return 'line ' + String(one.line) + ': imports ' + found;
168
+ }
169
+ return false;
170
+ },
171
+ proves: {
172
+ wrong: [
173
+ {
174
+ files: [
175
+ { at: 'thread/integrations/cli.ts', source: "import { spawn } from 'node:child_process'\n\nexport const starts = (program: string): void => {\n spawn(program)\n}\n" },
176
+ { at: 'operations/_probe_node.ts', source: "export { starts } from '../thread/integrations/cli.ts'\n" },
177
+ ],
178
+ at: 'operations/_probe_node.ts',
179
+ },
180
+ {
181
+ files: [
182
+ { at: 'thread/integrations/https.ts', source: "export const sendingHttp = async (address: string): Promise<number> => (await fetch(address)).status\n" },
183
+ { at: 'src/_probe_helper.ts', source: "import { sendingHttp } from '../thread/integrations/https.ts'\n\nexport const status = (address: string): Promise<number> => sendingHttp(address)\n" },
184
+ { at: 'operations/_probe_node.ts', source: "import { status } from '../src/_probe_helper.ts'\n\nexport const node = (address: string): Promise<number> => status(address)\n" },
185
+ ],
186
+ at: 'operations/_probe_node.ts',
187
+ },
188
+ {
189
+ files: [
190
+ { at: 'thread/integrations/disk.ts', source: "import * as disk from 'node:fs'\n\nexport const read = (at: string): string => disk.readFileSync(at, 'utf8')\n" },
191
+ { at: 'operations/_probe_node.ts', source: "export const node = async (at: string): Promise<string> => (await import('../thread/integrations/disk.ts')).read(at)\n" },
192
+ ],
193
+ at: 'operations/_probe_node.ts',
194
+ },
195
+ ],
196
+ right: [
197
+ {
198
+ files: [
199
+ { at: 'thread/operations/nodes.ts', source: "export const nd_action = <T>(run: T): T => run\n" },
200
+ { at: 'operations/_probe_node.ts', source: "import { nd_action } from '../thread/operations/nodes.ts'\n\nexport const node = nd_action(async () => 1)\n" },
201
+ ],
202
+ at: 'operations/_probe_node.ts',
203
+ },
204
+ {
205
+ files: [
206
+ { at: 'thread/integrations/cli.ts', source: "import { spawn } from 'node:child_process'\n\nexport interface Ran {\n readonly out: string\n}\n\nexport const starts = (program: string): void => {\n spawn(program)\n}\n" },
207
+ { at: 'operations/_probe_node.ts', source: "import type { Ran } from '../thread/integrations/cli.ts'\n\nexport const node = (ran: Ran): string => ran.out\n" },
208
+ ],
209
+ at: 'operations/_probe_node.ts',
210
+ },
211
+ {
212
+ files: [
213
+ { at: 'src/_probe_helper.ts', source: "const fetch = (said: string): string => said\n\nexport const shout = (said: string): string => fetch(said).toUpperCase()\n" },
214
+ { at: 'operations/_probe_node.ts', source: "import { shout } from '../src/_probe_helper.ts'\n\nexport const node = (): string => shout('a')\n" },
215
+ ],
216
+ at: 'operations/_probe_node.ts',
217
+ },
218
+ ],
219
+ },
220
+ };