@ontrails/trails 1.0.0-beta.13 → 1.0.0-beta.14

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 (140) hide show
  1. package/.turbo/turbo-lint.log +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/__tests__/examples.test.ts +14 -0
  4. package/dist/src/app.d.ts.map +1 -1
  5. package/dist/src/app.js +13 -2
  6. package/dist/src/app.js.map +1 -1
  7. package/dist/src/clack.d.ts +1 -1
  8. package/dist/src/clack.js +1 -1
  9. package/dist/src/cli.js +2 -2
  10. package/dist/src/cli.js.map +1 -1
  11. package/dist/src/trails/add-trail.js +13 -13
  12. package/dist/src/trails/add-trail.js.map +1 -1
  13. package/dist/src/trails/add-trailhead.d.ts +13 -0
  14. package/dist/src/trails/add-trailhead.d.ts.map +1 -0
  15. package/dist/src/trails/add-trailhead.js +88 -0
  16. package/dist/src/trails/add-trailhead.js.map +1 -0
  17. package/dist/src/trails/add-verify.js +10 -10
  18. package/dist/src/trails/add-verify.js.map +1 -1
  19. package/dist/src/trails/create-scaffold.js +26 -26
  20. package/dist/src/trails/create-scaffold.js.map +1 -1
  21. package/dist/src/trails/create.d.ts +6 -6
  22. package/dist/src/trails/create.d.ts.map +1 -1
  23. package/dist/src/trails/create.js +29 -29
  24. package/dist/src/trails/create.js.map +1 -1
  25. package/dist/src/trails/dev-clean.d.ts +9 -0
  26. package/dist/src/trails/dev-clean.d.ts.map +1 -0
  27. package/dist/src/trails/dev-clean.js +65 -0
  28. package/dist/src/trails/dev-clean.js.map +1 -0
  29. package/dist/src/trails/dev-reset.d.ts +6 -0
  30. package/dist/src/trails/dev-reset.d.ts.map +1 -0
  31. package/dist/src/trails/dev-reset.js +38 -0
  32. package/dist/src/trails/dev-reset.js.map +1 -0
  33. package/dist/src/trails/dev-stats.d.ts +7 -0
  34. package/dist/src/trails/dev-stats.d.ts.map +1 -0
  35. package/dist/src/trails/dev-stats.js +61 -0
  36. package/dist/src/trails/dev-stats.js.map +1 -0
  37. package/dist/src/trails/dev-support.d.ts +64 -0
  38. package/dist/src/trails/dev-support.d.ts.map +1 -0
  39. package/dist/src/trails/dev-support.js +178 -0
  40. package/dist/src/trails/dev-support.js.map +1 -0
  41. package/dist/src/trails/draft-promote.d.ts +18 -0
  42. package/dist/src/trails/draft-promote.d.ts.map +1 -0
  43. package/dist/src/trails/draft-promote.js +386 -0
  44. package/dist/src/trails/draft-promote.js.map +1 -0
  45. package/dist/src/trails/guide.d.ts +13 -3
  46. package/dist/src/trails/guide.d.ts.map +1 -1
  47. package/dist/src/trails/guide.js +21 -37
  48. package/dist/src/trails/guide.js.map +1 -1
  49. package/dist/src/trails/load-app.d.ts +3 -1
  50. package/dist/src/trails/load-app.d.ts.map +1 -1
  51. package/dist/src/trails/load-app.js +53 -10
  52. package/dist/src/trails/load-app.js.map +1 -1
  53. package/dist/src/trails/project.d.ts.map +1 -1
  54. package/dist/src/trails/project.js +14 -3
  55. package/dist/src/trails/project.js.map +1 -1
  56. package/dist/src/trails/survey.d.ts +4 -58
  57. package/dist/src/trails/survey.d.ts.map +1 -1
  58. package/dist/src/trails/survey.js +52 -173
  59. package/dist/src/trails/survey.js.map +1 -1
  60. package/dist/src/trails/topo-constants.d.ts +3 -0
  61. package/dist/src/trails/topo-constants.d.ts.map +1 -0
  62. package/dist/src/trails/topo-constants.js +3 -0
  63. package/dist/src/trails/topo-constants.js.map +1 -0
  64. package/dist/src/trails/topo-export.d.ts +18 -0
  65. package/dist/src/trails/topo-export.d.ts.map +1 -0
  66. package/dist/src/trails/topo-export.js +34 -0
  67. package/dist/src/trails/topo-export.js.map +1 -0
  68. package/dist/src/trails/topo-history.d.ts +24 -0
  69. package/dist/src/trails/topo-history.d.ts.map +1 -0
  70. package/dist/src/trails/topo-history.js +33 -0
  71. package/dist/src/trails/topo-history.js.map +1 -0
  72. package/dist/src/trails/topo-pin.d.ts +21 -0
  73. package/dist/src/trails/topo-pin.d.ts.map +1 -0
  74. package/dist/src/trails/topo-pin.js +35 -0
  75. package/dist/src/trails/topo-pin.js.map +1 -0
  76. package/dist/src/trails/topo-read-support.d.ts +54 -0
  77. package/dist/src/trails/topo-read-support.d.ts.map +1 -0
  78. package/dist/src/trails/topo-read-support.js +178 -0
  79. package/dist/src/trails/topo-read-support.js.map +1 -0
  80. package/dist/src/trails/topo-reports.d.ts +50 -0
  81. package/dist/src/trails/topo-reports.d.ts.map +1 -0
  82. package/dist/src/trails/topo-reports.js +122 -0
  83. package/dist/src/trails/topo-reports.js.map +1 -0
  84. package/dist/src/trails/topo-show.d.ts +23 -0
  85. package/dist/src/trails/topo-show.d.ts.map +1 -0
  86. package/dist/src/trails/topo-show.js +53 -0
  87. package/dist/src/trails/topo-show.js.map +1 -0
  88. package/dist/src/trails/topo-store-support.d.ts +13 -0
  89. package/dist/src/trails/topo-store-support.d.ts.map +1 -0
  90. package/dist/src/trails/topo-store-support.js +55 -0
  91. package/dist/src/trails/topo-store-support.js.map +1 -0
  92. package/dist/src/trails/topo-support.d.ts +87 -0
  93. package/dist/src/trails/topo-support.d.ts.map +1 -0
  94. package/dist/src/trails/topo-support.js +165 -0
  95. package/dist/src/trails/topo-support.js.map +1 -0
  96. package/dist/src/trails/topo-unpin.d.ts +15 -0
  97. package/dist/src/trails/topo-unpin.d.ts.map +1 -0
  98. package/dist/src/trails/topo-unpin.js +39 -0
  99. package/dist/src/trails/topo-unpin.js.map +1 -0
  100. package/dist/src/trails/topo-verify.d.ts +5 -0
  101. package/dist/src/trails/topo-verify.d.ts.map +1 -0
  102. package/dist/src/trails/topo-verify.js +28 -0
  103. package/dist/src/trails/topo-verify.js.map +1 -0
  104. package/dist/src/trails/topo.d.ts +5 -0
  105. package/dist/src/trails/topo.d.ts.map +1 -0
  106. package/dist/src/trails/topo.js +67 -0
  107. package/dist/src/trails/topo.js.map +1 -0
  108. package/dist/src/trails/warden.d.ts +1 -1
  109. package/dist/src/trails/warden.d.ts.map +1 -1
  110. package/dist/src/trails/warden.js +28 -27
  111. package/dist/src/trails/warden.js.map +1 -1
  112. package/dist/tsconfig.tsbuildinfo +1 -1
  113. package/package.json +8 -7
  114. package/src/__tests__/draft-promote.test.ts +144 -0
  115. package/src/__tests__/load-app.test.ts +43 -0
  116. package/src/__tests__/survey.test.ts +85 -0
  117. package/src/__tests__/topo-dev.test.ts +424 -0
  118. package/src/app.ts +22 -0
  119. package/src/trails/dev-clean.ts +73 -0
  120. package/src/trails/dev-reset.ts +44 -0
  121. package/src/trails/dev-stats.ts +64 -0
  122. package/src/trails/dev-support.ts +326 -0
  123. package/src/trails/draft-promote.ts +704 -0
  124. package/src/trails/guide.ts +22 -37
  125. package/src/trails/load-app.ts +76 -13
  126. package/src/trails/project.ts +17 -3
  127. package/src/trails/survey.ts +56 -256
  128. package/src/trails/topo-constants.ts +2 -0
  129. package/src/trails/topo-export.ts +39 -0
  130. package/src/trails/topo-history.ts +40 -0
  131. package/src/trails/topo-pin.ts +42 -0
  132. package/src/trails/topo-read-support.ts +332 -0
  133. package/src/trails/topo-reports.ts +221 -0
  134. package/src/trails/topo-show.ts +58 -0
  135. package/src/trails/topo-store-support.ts +96 -0
  136. package/src/trails/topo-support.ts +274 -0
  137. package/src/trails/topo-unpin.ts +51 -0
  138. package/src/trails/topo-verify.ts +29 -0
  139. package/src/trails/topo.ts +73 -0
  140. package/src/trails/warden.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/trails",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.14",
4
4
  "bin": {
5
5
  "trails": "./bin/trails.ts"
6
6
  },
@@ -14,15 +14,16 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@clack/prompts": "^1.1.0",
17
- "@ontrails/cli": "^1.0.0-beta.12",
18
- "@ontrails/core": "^1.0.0-beta.12",
19
- "@ontrails/logging": "^1.0.0-beta.12",
20
- "@ontrails/schema": "^1.0.0-beta.12",
21
- "@ontrails/warden": "^1.0.0-beta.12",
17
+ "@ontrails/cli": "^1.0.0-beta.13",
18
+ "@ontrails/core": "^1.0.0-beta.13",
19
+ "@ontrails/logging": "^1.0.0-beta.13",
20
+ "@ontrails/schema": "^1.0.0-beta.13",
21
+ "@ontrails/tracker": "^1.0.0-beta.13",
22
+ "@ontrails/warden": "^1.0.0-beta.13",
22
23
  "commander": "^14.0.3",
23
24
  "zod": "^4.3.5"
24
25
  },
25
26
  "devDependencies": {
26
- "@ontrails/testing": "^1.0.0-beta.12"
27
+ "@ontrails/testing": "^1.0.0-beta.13"
27
28
  }
28
29
  }
@@ -0,0 +1,144 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import {
3
+ existsSync,
4
+ mkdirSync,
5
+ readFileSync,
6
+ rmSync,
7
+ writeFileSync,
8
+ } from 'node:fs';
9
+ import { join, resolve } from 'node:path';
10
+
11
+ import type { Result } from '@ontrails/core';
12
+ import { ValidationError } from '@ontrails/core';
13
+
14
+ import { draftPromoteTrail } from '../trails/draft-promote.js';
15
+
16
+ const repoTempDir = (): string =>
17
+ join(
18
+ resolve(import.meta.dir, '../..'),
19
+ '.tmp-tests',
20
+ `draft-promote-${Date.now()}-${Math.random().toString(36).slice(2)}`
21
+ );
22
+
23
+ const expectOk = <T>(result: Result<T, Error>): T => {
24
+ if (result.isErr()) {
25
+ throw result.error;
26
+ }
27
+ return result.value;
28
+ };
29
+
30
+ const expectErr = <E extends Error>(result: Result<unknown, E>): E => {
31
+ if (result.isOk()) {
32
+ throw new Error('expected result to be an error');
33
+ }
34
+ return result.error;
35
+ };
36
+
37
+ const writeDraftPromoteFixture = (dir: string): void => {
38
+ mkdirSync(join(dir, 'src'), { recursive: true });
39
+
40
+ writeFileSync(
41
+ join(dir, 'src', 'app.ts'),
42
+ `import { topo } from '@ontrails/core';
43
+ import { draftPrepare } from './_draft.prepare.js';
44
+ import { exportTrail } from './export.js';
45
+
46
+ export const app = topo('draft-test', { draftPrepare, exportTrail });
47
+ `
48
+ );
49
+
50
+ writeFileSync(
51
+ join(dir, 'src', '_draft.prepare.ts'),
52
+ `import { Result, trail } from '@ontrails/core';
53
+ import { z } from 'zod';
54
+
55
+ export const draftPrepare = trail('_draft.entity.prepare', {
56
+ blaze: async () => Result.ok({ ready: true }),
57
+ input: z.object({}),
58
+ output: z.object({ ready: z.boolean() }),
59
+ });
60
+ `
61
+ );
62
+
63
+ writeFileSync(
64
+ join(dir, 'src', 'export.ts'),
65
+ `import { Result, trail } from '@ontrails/core';
66
+ import { z } from 'zod';
67
+
68
+ export const exportTrail = trail('entity.export', {
69
+ blaze: async () => Result.ok({ exported: true }),
70
+ crosses: ['_draft.entity.prepare'],
71
+ input: z.object({}),
72
+ output: z.object({ exported: z.boolean() }),
73
+ });
74
+ `
75
+ );
76
+ };
77
+
78
+ const expectDraftPromoteResults = (dir: string): void => {
79
+ expect(existsSync(join(dir, 'src', '_draft.prepare.ts'))).toBe(false);
80
+ expect(existsSync(join(dir, 'src', 'prepare.ts'))).toBe(true);
81
+ expect(readFileSync(join(dir, 'src', 'prepare.ts'), 'utf8')).toContain(
82
+ "trail('entity.prepare'"
83
+ );
84
+ expect(readFileSync(join(dir, 'src', 'export.ts'), 'utf8')).toContain(
85
+ "crosses: ['entity.prepare']"
86
+ );
87
+ expect(readFileSync(join(dir, 'src', 'app.ts'), 'utf8')).toContain(
88
+ "from './prepare.js'"
89
+ );
90
+ };
91
+
92
+ describe('draft.promote', () => {
93
+ test('promotes draft ids, renames files, and updates imports', async () => {
94
+ const dir = repoTempDir();
95
+
96
+ try {
97
+ writeDraftPromoteFixture(dir);
98
+
99
+ const result = expectOk(
100
+ await draftPromoteTrail.blaze(
101
+ {
102
+ fromId: '_draft.entity.prepare',
103
+ renameFiles: true,
104
+ rootDir: dir,
105
+ toId: 'entity.prepare',
106
+ },
107
+ { cwd: dir } as never
108
+ )
109
+ );
110
+
111
+ expect(result.promotedEstablished).toBe(true);
112
+ expect(result.remainingDraftIds).toEqual([]);
113
+ expect(result.updatedFiles).toEqual(
114
+ expect.arrayContaining(['src/app.ts', 'src/export.ts'])
115
+ );
116
+ expect(result.renamedFiles).toEqual([
117
+ {
118
+ from: 'src/_draft.prepare.ts',
119
+ to: 'src/prepare.ts',
120
+ },
121
+ ]);
122
+ expectDraftPromoteResults(dir);
123
+ } finally {
124
+ rmSync(dir, { force: true, recursive: true });
125
+ }
126
+ });
127
+
128
+ test('returns ValidationError when rootDir does not exist', async () => {
129
+ const error = expectErr(
130
+ await draftPromoteTrail.blaze(
131
+ {
132
+ fromId: '_draft.entity.prepare',
133
+ renameFiles: true,
134
+ rootDir: join(repoTempDir(), 'missing'),
135
+ toId: 'entity.prepare',
136
+ },
137
+ { cwd: process.cwd() } as never
138
+ )
139
+ );
140
+
141
+ expect(error).toBeInstanceOf(ValidationError);
142
+ expect(error.message).toContain('rootDir does not exist');
143
+ });
144
+ });
@@ -1,8 +1,37 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
+ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
2
4
  import { resolve } from 'node:path';
3
5
 
4
6
  import { loadApp } from '../trails/load-app.js';
5
7
 
8
+ const writeLoadAppFixture = (cwd: string, name: string): void => {
9
+ writeFileSync(
10
+ resolve(cwd, 'src/app.ts'),
11
+ `export const app = {
12
+ name: '${name}',
13
+ trails: new Map(),
14
+ signals: new Map(),
15
+ provisions: new Map()
16
+ };`
17
+ );
18
+ };
19
+
20
+ const assertLoadAppCaching = async (cwd: string): Promise<void> => {
21
+ writeLoadAppFixture(cwd, 'first');
22
+
23
+ const first = await loadApp('./src/app.ts', cwd);
24
+
25
+ writeLoadAppFixture(cwd, 'second');
26
+
27
+ const cached = await loadApp('./src/app.ts', cwd);
28
+ const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
29
+
30
+ expect(first.name).toBe('first');
31
+ expect(cached.name).toBe('first');
32
+ expect(fresh.name).toBe('second');
33
+ };
34
+
6
35
  describe('loadApp', () => {
7
36
  test('resolves relative module paths from cwd', async () => {
8
37
  // import.meta.dir is src/__tests__/, go up two to get apps/trails/
@@ -12,4 +41,18 @@ describe('loadApp', () => {
12
41
  expect(app.name).toBe('trails');
13
42
  expect(app.get('survey')).toBeDefined();
14
43
  });
44
+
45
+ test('can bypass module caching with fresh loading', async () => {
46
+ const cwd = resolve(
47
+ tmpdir(),
48
+ `trails-load-app-${Date.now()}-${Math.random().toString(36).slice(2)}`
49
+ );
50
+
51
+ try {
52
+ mkdirSync(resolve(cwd, 'src'), { recursive: true });
53
+ await assertLoadAppCaching(cwd);
54
+ } finally {
55
+ rmSync(cwd, { force: true, recursive: true });
56
+ }
57
+ });
15
58
  });
@@ -1,4 +1,12 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
+ import {
3
+ existsSync,
4
+ mkdirSync,
5
+ readFileSync,
6
+ rmSync,
7
+ writeFileSync,
8
+ } from 'node:fs';
9
+ import { join, resolve } from 'node:path';
2
10
 
3
11
  import { Result, provision, topo, trail } from '@ontrails/core';
4
12
  import {
@@ -13,6 +21,7 @@ import {
13
21
  generateBriefReport,
14
22
  generateSurveyList,
15
23
  generateTrailDetail,
24
+ surveyTrail,
16
25
  } from '../trails/survey.js';
17
26
  import type {
18
27
  BriefReport,
@@ -68,6 +77,49 @@ const app = topo('test-app', {
68
77
  hello: helloTrail,
69
78
  });
70
79
 
80
+ const expectOk = <T>(result: Result<T, Error>): T => {
81
+ if (result.isErr()) {
82
+ throw result.error;
83
+ }
84
+ return result.value;
85
+ };
86
+
87
+ const writeSurveyAppFixture = (dir: string): void => {
88
+ mkdirSync(join(dir, 'src'), { recursive: true });
89
+ writeFileSync(
90
+ join(dir, 'src', 'app.ts'),
91
+ `import { Result, provision, topo, trail } from '@ontrails/core';
92
+ import { z } from 'zod';
93
+
94
+ const hello = trail('hello', {
95
+ blaze: async (input) => Result.ok({ message: \`Hello, \${input.name ?? 'world'}!\` }),
96
+ input: z.object({ name: z.string().optional() }),
97
+ intent: 'read',
98
+ output: z.object({ message: z.string() }),
99
+ provisions: [
100
+ provision('db.main', {
101
+ create: () => Result.ok({ source: 'factory' }),
102
+ }),
103
+ ],
104
+ });
105
+
106
+ const [dbMain] = hello.provisions;
107
+ if (!dbMain) {
108
+ throw new Error('expected hello to declare db.main');
109
+ }
110
+
111
+ export const app = topo('survey-fixture', { dbMain, hello });
112
+ `
113
+ );
114
+ };
115
+
116
+ const repoTempDir = (): string =>
117
+ join(
118
+ resolve(import.meta.dir, '../..'),
119
+ '.tmp-tests',
120
+ `trails-survey-${Date.now()}-${Math.random().toString(36).slice(2)}`
121
+ );
122
+
71
123
  // ---------------------------------------------------------------------------
72
124
  // Tests
73
125
  // ---------------------------------------------------------------------------
@@ -86,6 +138,7 @@ describe('trails survey', () => {
86
138
  const trailheadMap = generateTrailheadMap(app);
87
139
  const hello = trailheadMap.entries.find((e) => e.id === 'hello');
88
140
  expect(hello).toBeDefined();
141
+ expect(hello?.cli?.path).toEqual(['hello']);
89
142
  expect(hello?.kind).toBe('trail');
90
143
  expect(hello?.intent).toBe('read');
91
144
  expect(hello?.exampleCount).toBe(1);
@@ -214,3 +267,35 @@ describe('trails survey provisions section', () => {
214
267
  });
215
268
  });
216
269
  });
270
+
271
+ describe('trails survey generate', () => {
272
+ test('delegates to topo export and writes a structured lock', async () => {
273
+ const dir = repoTempDir();
274
+
275
+ try {
276
+ writeSurveyAppFixture(dir);
277
+
278
+ const generated = expectOk(
279
+ await surveyTrail.blaze({ generate: true, module: './src/app.ts' }, {
280
+ cwd: dir,
281
+ } as never)
282
+ ) as {
283
+ readonly hash: string;
284
+ readonly lockPath: string;
285
+ readonly mapPath: string;
286
+ };
287
+
288
+ expect(generated.hash).toHaveLength(64);
289
+ expect(existsSync(join(dir, '.trails', '_trailhead.json'))).toBe(true);
290
+ expect(existsSync(join(dir, '.trails', 'trails.lock'))).toBe(true);
291
+ expect(
292
+ JSON.parse(readFileSync(join(dir, '.trails', 'trails.lock'), 'utf8'))
293
+ ).toMatchObject({
294
+ hash: generated.hash,
295
+ version: 1,
296
+ });
297
+ } finally {
298
+ rmSync(dir, { force: true, recursive: true });
299
+ }
300
+ });
301
+ });