@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.
Files changed (265) hide show
  1. package/CHANGELOG.md +193 -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 +67 -58
  7. package/dist/core/attach.ts +61 -68
  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 +89 -21
  14. package/dist/core/descend.ts +86 -17
  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 +0 -2
  27. package/dist/core/init.js +51 -15
  28. package/dist/core/init.ts +58 -15
  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/thread.d.ts +3 -3
  38. package/dist/core/tree.d.ts +4 -1
  39. package/dist/core/tree.js +26 -6
  40. package/dist/core/tree.ts +29 -6
  41. package/dist/core/types.d.ts +3 -3
  42. package/dist/core/types.js +3 -1
  43. package/dist/core/types.ts +2 -1
  44. package/dist/derivation/attach.js +1 -1
  45. package/dist/derivation/generators/build.js +6 -6
  46. package/dist/derivation/generators/build.ts +1 -1
  47. package/dist/derivation/generators/check.js +1 -1
  48. package/dist/derivation/generators/determinism.js +1 -1
  49. package/dist/derivation/generators/release.js +60 -47
  50. package/dist/derivation/generators/release.ts +66 -43
  51. package/dist/derivation/release.d.ts +7 -3
  52. package/dist/derivation/release.js +14 -1
  53. package/dist/derivation/release.ts +22 -2
  54. package/dist/integrations/attach.d.ts +4 -0
  55. package/dist/integrations/attach.js +33 -54
  56. package/dist/integrations/attach.ts +50 -57
  57. package/dist/integrations/cli.d.ts +37 -0
  58. package/dist/integrations/cli.js +440 -0
  59. package/dist/integrations/cli.ts +543 -0
  60. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -20
  61. package/dist/integrations/disk.js +435 -0
  62. package/dist/integrations/disk.ts +465 -0
  63. package/dist/integrations/generators/read.js +6 -6
  64. package/dist/integrations/generators/read.ts +4 -4
  65. package/dist/integrations/generators/vault.js +10 -11
  66. package/dist/integrations/generators/vault.ts +4 -5
  67. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  68. package/dist/integrations/https.js +170 -0
  69. package/dist/integrations/https.ts +216 -0
  70. package/dist/integrations/pglite.d.ts +26 -0
  71. package/dist/integrations/pglite.js +143 -0
  72. package/dist/integrations/pglite.ts +206 -0
  73. package/dist/integrations/secret.d.ts +8 -2
  74. package/dist/integrations/secret.js +3 -5
  75. package/dist/integrations/secret.ts +10 -6
  76. package/dist/integrations/target.d.ts +155 -14
  77. package/dist/integrations/target.js +171 -50
  78. package/dist/integrations/target.ts +377 -61
  79. package/dist/integrations/vault.d.ts +1 -0
  80. package/dist/integrations/vault.js +20 -5
  81. package/dist/integrations/vault.ts +17 -5
  82. package/dist/integrity/attach.js +3 -73
  83. package/dist/integrity/attach.ts +1 -71
  84. package/dist/integrity/check-threads.js +5 -5
  85. package/dist/integrity/check-threads.ts +2 -2
  86. package/dist/integrity/constraint.d.ts +0 -1
  87. package/dist/integrity/constraint.js +267 -366
  88. package/dist/integrity/constraint.ts +267 -375
  89. package/dist/integrity/generators/compiler.js +14 -17
  90. package/dist/integrity/generators/compiler.ts +10 -15
  91. package/dist/integrity/generators/gate.js +15 -15
  92. package/dist/integrity/generators/gate.ts +10 -10
  93. package/dist/integrity/generators/issues.js +7 -7
  94. package/dist/integrity/generators/publish.js +39 -57
  95. package/dist/integrity/generators/publish.ts +44 -55
  96. package/dist/integrity/generators/trial.d.ts +3 -3
  97. package/dist/integrity/generators/trial.js +133 -161
  98. package/dist/integrity/generators/trial.ts +145 -165
  99. package/dist/integrity/lint.js +9 -13
  100. package/dist/integrity/lint.ts +7 -10
  101. package/dist/integrity/lsp/bin.js +5 -4
  102. package/dist/integrity/lsp/bin.ts +3 -1
  103. package/dist/integrity/lsp/diagnostics.js +3 -3
  104. package/dist/integrity/lsp/diagnostics.ts +1 -1
  105. package/dist/integrity/lsp/lint.js +19 -30
  106. package/dist/integrity/lsp/lint.ts +16 -32
  107. package/dist/integrity/lsp/server.js +3 -3
  108. package/dist/integrity/slopnator.d.ts +3 -13
  109. package/dist/integrity/slopnator.js +58 -37
  110. package/dist/integrity/slopnator.ts +53 -37
  111. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  112. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  113. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  114. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  115. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  116. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  117. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  118. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  119. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  120. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  121. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  122. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  123. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  124. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  125. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  126. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  127. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  128. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  129. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  130. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  131. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  132. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  133. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  134. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  135. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  136. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  137. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  138. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  139. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  140. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  141. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  142. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  143. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  144. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  145. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  146. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  147. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  148. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  149. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  150. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  151. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  152. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  153. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  154. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  155. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  156. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  157. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  158. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  159. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  160. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  161. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  162. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  163. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  164. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  165. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  166. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  167. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  168. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  169. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  170. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  171. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  172. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  173. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  174. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  175. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  176. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  177. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  178. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  179. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  180. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  181. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  182. package/dist/integrity/sweep.d.ts +1 -0
  183. package/dist/integrity/sweep.js +105 -42
  184. package/dist/integrity/sweep.ts +115 -42
  185. package/dist/knowledge/attach.js +1 -1
  186. package/dist/knowledge/generators/docsgen.js +8 -6
  187. package/dist/knowledge/generators/docsgen.ts +4 -2
  188. package/dist/knowledge/generators/glossary.js +4 -4
  189. package/dist/knowledge/generators/glossary.ts +1 -1
  190. package/dist/operations/access.d.ts +23 -0
  191. package/dist/operations/access.js +28 -1
  192. package/dist/operations/access.ts +43 -0
  193. package/dist/operations/attach.js +28 -109
  194. package/dist/operations/attach.ts +46 -113
  195. package/dist/operations/capabilities.d.ts +14 -5
  196. package/dist/operations/capabilities.js +13 -4
  197. package/dist/operations/capabilities.ts +27 -8
  198. package/dist/operations/dispatch.d.ts +8 -2
  199. package/dist/operations/dispatch.js +128 -185
  200. package/dist/operations/dispatch.ts +138 -191
  201. package/dist/operations/error-results.d.ts +1 -1
  202. package/dist/operations/error-results.js +2 -2
  203. package/dist/operations/error-results.ts +2 -2
  204. package/dist/operations/generators/capability.d.ts +11 -1
  205. package/dist/operations/generators/capability.js +481 -224
  206. package/dist/operations/generators/capability.ts +562 -233
  207. package/dist/operations/generators/compile.js +66 -39
  208. package/dist/operations/generators/compile.ts +78 -39
  209. package/dist/operations/generators/permits.js +11 -12
  210. package/dist/operations/generators/permits.ts +3 -4
  211. package/dist/operations/generators/seed.d.ts +1 -0
  212. package/dist/operations/generators/seed.js +19 -17
  213. package/dist/operations/generators/seed.ts +22 -14
  214. package/dist/operations/generators/trial.d.ts +6 -8
  215. package/dist/operations/generators/trial.js +200 -70
  216. package/dist/operations/generators/trial.ts +230 -93
  217. package/dist/operations/nodes.d.ts +15 -16
  218. package/dist/operations/nodes.ts +16 -17
  219. package/dist/operations/operations.d.ts +40 -4
  220. package/dist/operations/operations.js +1 -0
  221. package/dist/operations/operations.ts +61 -4
  222. package/dist/operations/result.d.ts +2 -2
  223. package/dist/operations/result.ts +2 -2
  224. package/package.json +1 -4
  225. package/dist/core/answers.d.ts +0 -171
  226. package/dist/core/answers.js +0 -789
  227. package/dist/core/answers.ts +0 -999
  228. package/dist/core/client.d.ts +0 -57
  229. package/dist/core/client.js +0 -247
  230. package/dist/core/client.ts +0 -286
  231. package/dist/core/files.js +0 -145
  232. package/dist/core/files.ts +0 -193
  233. package/dist/integrations/module.d.ts +0 -6
  234. package/dist/integrations/module.js +0 -153
  235. package/dist/integrations/module.ts +0 -191
  236. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  237. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  238. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  239. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  240. package/dist/operations/cost.d.ts +0 -14
  241. package/dist/operations/cost.js +0 -37
  242. package/dist/operations/cost.ts +0 -58
  243. package/dist/operations/errors/errors.d.ts +0 -52
  244. package/dist/operations/http.js +0 -124
  245. package/dist/operations/http.ts +0 -169
  246. package/dist/operations/memory.d.ts +0 -104
  247. package/dist/operations/memory.js +0 -365
  248. package/dist/operations/memory.ts +0 -470
  249. package/dist/operations/metering.d.ts +0 -55
  250. package/dist/operations/metering.js +0 -247
  251. package/dist/operations/metering.ts +0 -328
  252. package/dist/operations/queue-policy.d.ts +0 -3
  253. package/dist/operations/queue-policy.js +0 -8
  254. package/dist/operations/queue-policy.ts +0 -10
  255. package/dist/operations/seams.d.ts +0 -239
  256. package/dist/operations/seams.js +0 -45
  257. package/dist/operations/seams.ts +0 -364
  258. package/dist/operations/store.d.ts +0 -14
  259. package/dist/operations/store.js +0 -1
  260. package/dist/operations/store.ts +0 -29
  261. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  262. /package/dist/{operations → core}/errors/classes.js +0 -0
  263. /package/dist/{operations → core}/errors/classes.ts +0 -0
  264. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  265. /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) {
@@ -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 {
@@ -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
+ };