@prestack/thread 0.1.4 → 0.1.6

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.
@@ -1,5 +1,6 @@
1
1
  import type { Attaching } from '../core/attach.ts'
2
- import { named } from '../core/scope.ts'
2
+ import { SHAPED } from '../core/init.ts'
3
+ import { NAMED } from '../core/scope.ts'
3
4
 
4
5
  import { quoted } from '../core/rows.ts'
5
6
 
@@ -12,7 +13,7 @@ const CONSTRAINT =
12
13
  const RULES =
13
14
  'What this app refuses on top of what the framework already does. `thread create rule` asks what to ban, where it applies and what to do instead, then writes the row and the check beside it.'
14
15
 
15
- const HOME = `node_modules/${named('integrity')}/dist`
16
+ const HOME = `node_modules/${NAMED}/dist/integrity`
16
17
 
17
18
  const GATE =
18
19
  'Every surface that can refuse, each naming where it lives and the command that runs it, so the gate is derived from what this system declares rather than kept as a string beside it.'
@@ -20,7 +21,7 @@ const GATE =
20
21
  const COMPILER =
21
22
  'The compiler run over the files this app declares and no others. A type error is the plainest kind of broken build, so it is refused here rather than found by whoever runs the app next.'
22
23
 
23
- const INTEGRITY_SOURCE = `import type { Threaded } from '../core/thread.ts'
24
+ const INTEGRITY_SOURCE = `import type { Threaded } from '${SHAPED}'
24
25
 
25
26
  export const INTEGRITY: Threaded = {
26
27
  id: 'integrity',
@@ -57,12 +58,12 @@ export const INTEGRITY: Threaded = {
57
58
  }
58
59
  `
59
60
 
60
- const RULES_SOURCE = `import type { Constraint } from './constraint.ts'
61
+ const RULES_SOURCE = `import type { Constraint } from '${NAMED}/integrity/constraint'
61
62
 
62
63
  export const RULES: readonly Constraint[] = []
63
64
  `
64
65
 
65
- const GATE_SOURCE = `import type { Threaded } from '../core/thread.ts'
66
+ const GATE_SOURCE = `import type { Threaded } from '${SHAPED}'
66
67
 
67
68
  export const GATE: Threaded = {
68
69
  id: 'gate',
@@ -1,11 +1,8 @@
1
- import { starts } from '../../integrations/cli.js';
2
- import { attached, readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.js';
3
- import { createRequire } from 'node:module';
4
- import { dirname, join, resolve } from 'node:path';
5
- import { argv, execPath, stderr, stdout } from 'node:process';
1
+ import { readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.js';
2
+ import { join, resolve } from 'node:path';
3
+ import { argv, stderr, stdout } from 'node:process';
6
4
  import { exit } from '../../core/invoked.js';
7
- import { ROOT, THREAD_AT, descend } from '../../core/descend.js';
8
- import { MANIFEST } from '../../core/init.js';
5
+ import { ROOT, THREAD_AT, descend, uncompiled } from '../../core/descend.js';
9
6
  import { forbids, runChecker } from '../../core/finding.js';
10
7
  function refuse(why) {
11
8
  stderr.write(`compiler: ${why}\n`);
@@ -97,32 +94,9 @@ if (argv.includes('--check')) {
97
94
  instead: 'run `thread compiler`. What the compiler reads is derived from what the tree declares — an edit here is a declaration somebody skipped, and a path put here by hand is taken back out on the next settle',
98
95
  });
99
96
  }
97
+ findings.push(...uncompiled());
100
98
  runChecker('compiler', findings, `${String(leave.length)} path(s) left out, over ${String(pass.declarations)} declaration(s)`);
101
- if (findings.length > 0)
102
- exit(1);
103
- const asks = createRequire(join(ROOT, MANIFEST));
104
- let cli;
105
- try {
106
- const manifest = asks.resolve(`typescript/${MANIFEST}`);
107
- const bin = JSON.parse(readFileSync(manifest, 'utf8')).bin;
108
- const named = typeof bin === 'string' ? bin : (bin?.tsc ?? Object.values(bin ?? {})[0]);
109
- if (named === undefined)
110
- refuse(`the installed \`typescript\` states no executable in its ${MANIFEST}, so there is nothing here to run.`);
111
- cli = resolve(dirname(manifest), named);
112
- }
113
- catch (cause) {
114
- refuse(`the compiler is not installed — ${String(cause)}. \`typescript\` is a dependency this app declares, so \`npm install\` is what puts it there.`);
115
- }
116
- if (attached()) {
117
- stderr.write('compiler: NOT RUN. The typecheck is a separate compiler process, so it reads the disk of the machine this is\n' +
118
- 'running on rather than the tree being answered for. It would report on the wrong files, and a check that\n' +
119
- 'passed against the wrong machine says nothing about this one.\n');
120
- exit(1);
121
- }
122
- const built = starts(execPath, [cli, '--noEmit'], { at: ROOT, shows: true });
123
- if (!built.there)
124
- refuse(`the compiler could not be started — ${built.why}.`);
125
- exit(built.code);
99
+ exit(findings.length > 0 ? 1 : 0);
126
100
  }
127
101
  if (has) {
128
102
  stdout.write(`compiler: ${AT} already leaves out exactly what this tree declares nothing under.\n`);
@@ -1,12 +1,11 @@
1
- import { starts } from '../../integrations/cli.ts'
2
- import { attached, readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.ts'
3
- import { createRequire } from 'node:module'
4
- import { dirname, join, resolve } from 'node:path'
5
- import { argv, execPath, stderr, stdout } from 'node:process'
1
+
2
+ import { readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.ts'
3
+ import { join, resolve } from 'node:path'
4
+ import { argv, stderr, stdout } from 'node:process'
6
5
 
7
6
  import { exit } from '../../core/invoked.ts'
8
- import { ROOT, THREAD_AT, descend } from '../../core/descend.ts'
9
- import { MANIFEST } from '../../core/init.ts'
7
+ import { ROOT, THREAD_AT, descend, uncompiled } from '../../core/descend.ts'
8
+
10
9
  import { forbids, runChecker, type Finding } from '../../core/finding.ts'
11
10
 
12
11
  function refuse(why: string): never {
@@ -123,36 +122,10 @@ if (argv.includes('--check')) {
123
122
  'run `thread compiler`. What the compiler reads is derived from what the tree declares — an edit here is a declaration somebody skipped, and a path put here by hand is taken back out on the next settle',
124
123
  })
125
124
  }
126
-
125
+ findings.push(...uncompiled())
127
126
  runChecker('compiler', findings, `${String(leave.length)} path(s) left out, over ${String(pass.declarations)} declaration(s)`)
128
- if (findings.length > 0) exit(1)
129
-
130
- const asks = createRequire(join(ROOT, MANIFEST))
131
- let cli: string
132
- try {
133
- const manifest = asks.resolve(`typescript/${MANIFEST}`)
134
- const bin = (JSON.parse(readFileSync(manifest, 'utf8')) as { bin?: string | Record<string, string> }).bin
135
- const named = typeof bin === 'string' ? bin : (bin?.tsc ?? Object.values(bin ?? {})[0])
136
- if (named === undefined) refuse(`the installed \`typescript\` states no executable in its ${MANIFEST}, so there is nothing here to run.`)
137
- cli = resolve(dirname(manifest), named)
138
- } catch (cause) {
139
- refuse(
140
- `the compiler is not installed — ${String(cause)}. \`typescript\` is a dependency this app declares, so \`npm install\` is what puts it there.`,
141
- )
142
- }
143
-
144
- if (attached()) {
145
- stderr.write(
146
- 'compiler: NOT RUN. The typecheck is a separate compiler process, so it reads the disk of the machine this is\n' +
147
- 'running on rather than the tree being answered for. It would report on the wrong files, and a check that\n' +
148
- 'passed against the wrong machine says nothing about this one.\n',
149
- )
150
- exit(1)
151
- }
127
+ exit(findings.length > 0 ? 1 : 0)
152
128
 
153
- const built = starts(execPath, [cli, '--noEmit'], { at: ROOT, shows: true })
154
- if (!built.there) refuse(`the compiler could not be started — ${built.why}.`)
155
- exit(built.code)
156
129
  }
157
130
 
158
131
  if (has) {
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  import { join } from 'node:path';
4
4
  import { argv, execPath, stderr, stdout } from 'node:process';
5
5
  import { descend } from '../../core/descend.js';
6
- import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.js';
6
+ import { attached, existsSync, here, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.js';
7
7
  import { LOADER, exit } from '../../core/invoked.js';
8
8
  import { valuesIn } from '../../core/rows.js';
9
9
  import { ORGANISATION, ours } from '../../core/scope.js';
@@ -66,6 +66,12 @@ function ran(runs) {
66
66
  stderr.write(`gate: nothing in this tree is written by \`${of}\`, so this step names a command that does not exist here\n`);
67
67
  return 1;
68
68
  }
69
+ if (attached()) {
70
+ const ordered = here().run(join(ROOT, at), said.slice(2));
71
+ stdout.write(ordered.out);
72
+ stderr.write(ordered.err);
73
+ return ordered.there ? ordered.code : 1;
74
+ }
69
75
  const spun = starts(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent);
70
76
  return spun.there ? spun.code : 1;
71
77
  }
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path'
4
4
  import { argv, execPath, stderr, stdout } from 'node:process'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { descend } from '../../core/descend.ts'
7
- import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.ts'
7
+ import { attached, existsSync, here, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.ts'
8
8
  import { LOADER, exit } from '../../core/invoked.ts'
9
9
  import { valuesIn } from '../../core/rows.ts'
10
10
  import { ORGANISATION, ours } from '../../core/scope.ts'
@@ -95,6 +95,13 @@ function ran(runs: string): number {
95
95
  return 1
96
96
  }
97
97
 
98
+ if (attached()) {
99
+ const ordered = here().run(join(ROOT, at), said.slice(2))
100
+ stdout.write(ordered.out)
101
+ stderr.write(ordered.err)
102
+ return ordered.there ? ordered.code : 1
103
+ }
104
+
98
105
  const spun = starts(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent)
99
106
  return spun.there ? spun.code : 1
100
107
  }
@@ -126,7 +126,7 @@ export async function load(root, all) {
126
126
  for (const rule of all) {
127
127
  const name = slopnatorName(rule.id);
128
128
  const at = homes(root)
129
- .flatMap((dir) => [join(dir, `${name}.ts`), join(dir, `${name}.js`)])
129
+ .flatMap((dir) => [join(dir, `${name}.js`), join(dir, `${name}.ts`)])
130
130
  .find((one) => existsSync(one));
131
131
  if (at === undefined)
132
132
  continue;
@@ -180,7 +180,7 @@ export async function load(root: string, all: readonly Constraint[]): Promise<Re
180
180
  for (const rule of all) {
181
181
  const name = slopnatorName(rule.id)
182
182
  const at = homes(root)
183
- .flatMap((dir) => [join(dir, `${name}.ts`), join(dir, `${name}.js`)])
183
+ .flatMap((dir) => [join(dir, `${name}.js`), join(dir, `${name}.ts`)])
184
184
  .find((one) => existsSync(one))
185
185
  if (at === undefined) continue
186
186
 
@@ -1,7 +1,8 @@
1
+ import { SHAPED } from '../core/init.js';
1
2
  import { quoted } from '../core/rows.js';
2
3
  const DESCRIBES = 'The system that compiles what this repository holds into forms a reader can understand — the glossary first, and every later view of the tree computed rather than written.';
3
4
  const CONCEPTS = 'Every word this framework means something specific by that no declaration coins — its own verbs and the fields they sit in, written by a person because nothing in the tree can state them, and read into the glossary with everything else.';
4
- const CONCEPTS_SOURCE = `import type { Member } from '../core/thread.ts'
5
+ const CONCEPTS_SOURCE = `import type { Member } from '${SHAPED}'
5
6
 
6
7
  export interface Concept extends Member {
7
8
  readonly avoid?: readonly string[]
@@ -288,7 +289,7 @@ export const ATTACH = {
288
289
  {
289
290
  file: 'knowledge.ts',
290
291
  source: [
291
- "import type { Threaded } from '../core/thread.ts'",
292
+ `import type { Threaded } from '${SHAPED}'`,
292
293
  '',
293
294
  'export const KNOWLEDGE: Threaded = {',
294
295
  " id: 'knowledge',",
@@ -1,5 +1,6 @@
1
1
  import type { Attaching } from '../core/attach.ts'
2
2
 
3
+ import { SHAPED } from '../core/init.ts'
3
4
  import { quoted } from '../core/rows.ts'
4
5
 
5
6
  const DESCRIBES =
@@ -8,7 +9,7 @@ const DESCRIBES =
8
9
  const CONCEPTS =
9
10
  'Every word this framework means something specific by that no declaration coins — its own verbs and the fields they sit in, written by a person because nothing in the tree can state them, and read into the glossary with everything else.'
10
11
 
11
- const CONCEPTS_SOURCE = `import type { Member } from '../core/thread.ts'
12
+ const CONCEPTS_SOURCE = `import type { Member } from '${SHAPED}'
12
13
 
13
14
  export interface Concept extends Member {
14
15
  readonly avoid?: readonly string[]
@@ -298,7 +299,7 @@ export const ATTACH: Attaching = {
298
299
  {
299
300
  file: 'knowledge.ts',
300
301
  source: [
301
- "import type { Threaded } from '../core/thread.ts'",
302
+ `import type { Threaded } from '${SHAPED}'`,
302
303
  '',
303
304
  'export const KNOWLEDGE: Threaded = {',
304
305
  " id: 'knowledge',",
@@ -1,4 +1,5 @@
1
- import { named } from '../core/scope.js';
1
+ import { SHAPED } from '../core/init.js';
2
+ import { NAMED, named } from '../core/scope.js';
2
3
  import { LISTS } from '../core/descend.js';
3
4
  import { quoted } from '../core/rows.js';
4
5
  import { PERMITS_AT } from './access.js';
@@ -50,12 +51,12 @@ export const said = (one, pad) => {
50
51
  };
51
52
  const ACCESS = 'Who may ask this app to do what. A row says which operations it permits, on what, to whom, and under what condition. Nothing is permitted by default: an operation no row grants here cannot be run at all.';
52
53
  const PERMITS = 'The check compiled from the grants in _threads/access.ts: one branch per grant, so who may ask for what comes from one statement. Nobody edits it, because an edit here widens or narrows access nobody granted. An app that grants nothing permits nothing.';
53
- const ACCESS_SOURCE = `import type { Grant } from './access.ts'
54
+ const ACCESS_SOURCE = `import type { Grant } from '${NAMED}/operations/access'
54
55
 
55
56
  export const GRANTS: readonly Grant[] = []
56
57
  `;
57
58
  const DEFAULTS = 'Which surfaces every operation in this app answers on, stated once for all of them. An operation turns one off with `off` on its own row and can never turn on one this row leaves off. With no `live` stated, every operation answers on cli alone, so nothing is reachable from outside the machine until this row says so. `thread create capability edit defaults` changes it.';
58
- const DEFAULTS_SOURCE = `import type { Defaults } from './capabilities.ts'
59
+ const DEFAULTS_SOURCE = `import type { Defaults } from '${NAMED}/operations/capabilities'
59
60
 
60
61
  export const DEFAULTS: Defaults = {
61
62
  id: 'defaults',
@@ -218,8 +219,8 @@ const WHERE = {
218
219
  reaching: { into: OPERATIONS_FILE, list: 'declares' },
219
220
  };
220
221
  const placed = (id) => WHERE[id] ?? { into: NODES_FILE, list: MEMBERS_LIST };
221
- const NODES_SOURCE = `import type { Threaded } from '../core/thread.ts'
222
- import type { Node } from './nodes.ts'
222
+ const NODES_SOURCE = `import type { Threaded } from '${SHAPED}'
223
+ import type { Node } from '${NAMED}/operations/nodes'
223
224
 
224
225
  export const NODES: Threaded = {
225
226
  id: 'nodes',
@@ -231,7 +232,7 @@ export const NODES: Threaded = {
231
232
 
232
233
  export const ${MEMBERS_LIST}: readonly Node[] = []
233
234
  `;
234
- const OPERATIONS_SOURCE = `import type { Member, Threaded } from '../core/thread.ts'
235
+ const OPERATIONS_SOURCE = `import type { Member, Threaded } from '${SHAPED}'
235
236
 
236
237
  export const OPERATIONS: Threaded = {
237
238
  id: 'operations',
@@ -1,5 +1,6 @@
1
1
  import type { Attaching } from '../core/attach.ts'
2
- import { named } from '../core/scope.ts'
2
+ import { SHAPED } from '../core/init.ts'
3
+ import { NAMED, named } from '../core/scope.ts'
3
4
 
4
5
  import { LISTS } from '../core/descend.ts'
5
6
  import { quoted } from '../core/rows.ts'
@@ -106,7 +107,7 @@ const ACCESS =
106
107
  const PERMITS =
107
108
  'The check compiled from the grants in _threads/access.ts: one branch per grant, so who may ask for what comes from one statement. Nobody edits it, because an edit here widens or narrows access nobody granted. An app that grants nothing permits nothing.'
108
109
 
109
- const ACCESS_SOURCE = `import type { Grant } from './access.ts'
110
+ const ACCESS_SOURCE = `import type { Grant } from '${NAMED}/operations/access'
110
111
 
111
112
  export const GRANTS: readonly Grant[] = []
112
113
  `
@@ -114,7 +115,7 @@ export const GRANTS: readonly Grant[] = []
114
115
  const DEFAULTS =
115
116
  'Which surfaces every operation in this app answers on, stated once for all of them. An operation turns one off with `off` on its own row and can never turn on one this row leaves off. With no `live` stated, every operation answers on cli alone, so nothing is reachable from outside the machine until this row says so. `thread create capability edit defaults` changes it.'
116
117
 
117
- const DEFAULTS_SOURCE = `import type { Defaults } from './capabilities.ts'
118
+ const DEFAULTS_SOURCE = `import type { Defaults } from '${NAMED}/operations/capabilities'
118
119
 
119
120
  export const DEFAULTS: Defaults = {
120
121
  id: 'defaults',
@@ -287,8 +288,8 @@ const WHERE: Readonly<Record<string, { readonly into: string; readonly list: str
287
288
  const placed = (id: string): { readonly into: string; readonly list: string } =>
288
289
  WHERE[id] ?? { into: NODES_FILE, list: MEMBERS_LIST }
289
290
 
290
- const NODES_SOURCE = `import type { Threaded } from '../core/thread.ts'
291
- import type { Node } from './nodes.ts'
291
+ const NODES_SOURCE = `import type { Threaded } from '${SHAPED}'
292
+ import type { Node } from '${NAMED}/operations/nodes'
292
293
 
293
294
  export const NODES: Threaded = {
294
295
  id: 'nodes',
@@ -301,7 +302,7 @@ export const NODES: Threaded = {
301
302
  export const ${MEMBERS_LIST}: readonly Node[] = []
302
303
  `
303
304
 
304
- const OPERATIONS_SOURCE = `import type { Member, Threaded } from '../core/thread.ts'
305
+ const OPERATIONS_SOURCE = `import type { Member, Threaded } from '${SHAPED}'
305
306
 
306
307
  export const OPERATIONS: Threaded = {
307
308
  id: 'operations',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prestack/thread",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",