@sansavision/aurora 0.1.0-alpha.20260212.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/package.json +17 -0
- package/src/ai-diagnostics.ts +156 -0
- package/src/ai.ts +574 -0
- package/src/analyze.ts +669 -0
- package/src/bin/aurora.ts +15 -0
- package/src/build.ts +431 -0
- package/src/bun-test-shims.d.ts +17 -0
- package/src/create-feature.ts +419 -0
- package/src/create-route.ts +581 -0
- package/src/create.ts +425 -0
- package/src/dev.ts +126 -0
- package/src/devtools.ts +1143 -0
- package/src/doctor.ts +611 -0
- package/src/explain.ts +855 -0
- package/src/help.ts +39 -0
- package/src/index.ts +34 -0
- package/src/init.ts +1011 -0
- package/src/inspect-cache.ts +464 -0
- package/src/lsp-inline-hints.ts +254 -0
- package/src/node-shims.d.ts +26 -0
- package/src/process.d.ts +11 -0
- package/src/query-profiler.ts +520 -0
- package/src/realtime-monitor.ts +389 -0
- package/src/registry.ts +303 -0
- package/src/run.ts +37 -0
- package/src/start.ts +56 -0
- package/src/test.ts +289 -0
- package/templates/basic/README.md +16 -0
- package/templates/basic/package.json +10 -0
- package/templates/basic/src/actions/createMessage.action.server.ts +22 -0
- package/templates/basic/src/lib/auth.server.ts +11 -0
- package/templates/basic/src/queries/listMessages.server.ts +17 -0
- package/templates/basic/src/routes/index.tsx +12 -0
- package/templates/blog/README.md +17 -0
- package/templates/blog/package.json +12 -0
- package/templates/blog/public/assets/og-default.svg +17 -0
- package/templates/blog/src/content/loadPosts.server.ts +22 -0
- package/templates/blog/src/content/posts/hello-world.md +11 -0
- package/templates/blog/src/content/posts/release-notes.md +9 -0
- package/templates/blog/src/routes/index.tsx +22 -0
- package/templates/blog/src/routes/posts/[slug].tsx +19 -0
- package/templates/blog/src/seo/meta.ts +19 -0
- package/templates/dashboard/README.md +18 -0
- package/templates/dashboard/package.json +10 -0
- package/templates/dashboard/src/actions/acknowledgeAlert.action.server.ts +6 -0
- package/templates/dashboard/src/queries/getDashboardMetrics.server.ts +30 -0
- package/templates/dashboard/src/realtime/useDashboardRealtime.client.ts +13 -0
- package/templates/dashboard/src/routes/index.tsx +19 -0
- package/templates/dashboard/src/widgets/DataGrid.client.ts +8 -0
- package/templates/dashboard/src/widgets/MetricChart.client.ts +8 -0
- package/templates/desktop/README.md +18 -0
- package/templates/desktop/package.json +11 -0
- package/templates/desktop/src/actions/saveDesktopPreference.action.server.ts +28 -0
- package/templates/desktop/src/desktop/secureStorage.client.ts +20 -0
- package/templates/desktop/src/desktop/tauriBridge.client.ts +14 -0
- package/templates/desktop/src/queries/getDesktopSyncStatus.server.ts +9 -0
- package/templates/desktop/src/routes/index.tsx +27 -0
- package/templates/desktop/src/sync/offlineSyncBoundary.server.ts +27 -0
- package/templates/feature-skeleton/README.md +13 -0
- package/templates/feature-skeleton/actions/createFeature.action.server.ts +19 -0
- package/templates/feature-skeleton/index.ts +8 -0
- package/templates/feature-skeleton/queries/listFeature.server.ts +15 -0
- package/templates/feature-skeleton/realtime/useFeatureRealtime.client.ts +16 -0
- package/templates/feature-skeleton/template.manifest.json +15 -0
- package/templates/feature-skeleton/ui/FeatureView.client.tsx +14 -0
- package/templates/mobile/README.md +17 -0
- package/templates/mobile/package.json +11 -0
- package/templates/mobile/src/mobile/auth/session-handoff.client.ts +69 -0
- package/templates/mobile/src/mobile/generated/mobile-api-sdk.ts +62 -0
- package/templates/mobile/src/mobile/transport/mobile-api-transport.client.ts +122 -0
- package/templates/mobile/src/routes/index.tsx +134 -0
- package/templates/monorepo/README.md +18 -0
- package/templates/monorepo/apps/web/package.json +9 -0
- package/templates/monorepo/apps/web/src/routes/index.tsx +1 -0
- package/templates/monorepo/package.json +13 -0
- package/templates/monorepo/packages/shared/README.md +3 -0
- package/templates/monorepo/packages/ui/README.md +3 -0
- package/templates/saas/README.md +17 -0
- package/templates/saas/package.json +10 -0
- package/templates/saas/src/admin/getDashboard.server.ts +18 -0
- package/templates/saas/src/auth/session.server.ts +13 -0
- package/templates/saas/src/billing/checkout.server.ts +11 -0
- package/templates/saas/src/email/sendWelcome.server.ts +8 -0
- package/templates/saas/src/realtime/notifications.server.ts +8 -0
- package/templates/saas/src/routes/index.tsx +20 -0
- package/test/ai.test.ts +94 -0
- package/test/analyze.test.ts +301 -0
- package/test/build.test.ts +135 -0
- package/test/create-feature.test.ts +145 -0
- package/test/create-route.test.ts +117 -0
- package/test/create.test.ts +222 -0
- package/test/dev.test.ts +52 -0
- package/test/devtools.test.ts +130 -0
- package/test/doctor.test.ts +129 -0
- package/test/explain.test.ts +232 -0
- package/test/feature-skeleton.test.ts +53 -0
- package/test/fixtures/analyze/cache-input.invalid.json +1 -0
- package/test/fixtures/analyze/cache-input.missing-keyhash.v1.json +10 -0
- package/test/fixtures/analyze/cache-input.unsupported-version.v2.json +10 -0
- package/test/fixtures/analyze/cache-input.v1.json +12 -0
- package/test/fixtures/analyze/compiler-manifest/manifest.json +11 -0
- package/test/fixtures/analyze/guardrails-input.unsupported-version.v2.json +4 -0
- package/test/fixtures/analyze/guardrails-input.v1.json +49 -0
- package/test/fixtures/analyze/query-input.invalid-cache-status.v1.json +11 -0
- package/test/fixtures/analyze/query-input.unsupported-version.v2.json +11 -0
- package/test/fixtures/analyze/query-input.v1.json +18 -0
- package/test/fixtures/analyze/realtime-input.missing-lag-p95.v1.json +10 -0
- package/test/fixtures/analyze/realtime-input.unsupported-version.v2.json +8 -0
- package/test/fixtures/analyze/realtime-input.v1.json +12 -0
- package/test/fixtures/cache-inspector/cache-input.v1.json +23 -0
- package/test/fixtures/cache-inspector/invalid.json +1 -0
- package/test/fixtures/cache-inspector/snapshot.v1.json +34 -0
- package/test/fixtures/cache-inspector/unsupported-version.v2.json +13 -0
- package/test/fixtures/devtools/healthy.v1.json +130 -0
- package/test/fixtures/devtools/invalid.json +1 -0
- package/test/fixtures/devtools/unsupported-version.v2.json +8 -0
- package/test/fixtures/devtools/warn.v1.json +114 -0
- package/test/fixtures/doctor/clean/src/page.tsx +3 -0
- package/test/fixtures/doctor/findings/src/accessibility.client.tsx +7 -0
- package/test/fixtures/doctor/findings/src/migration.config.ts +3 -0
- package/test/fixtures/doctor/findings/src/page.client.tsx +5 -0
- package/test/fixtures/doctor/findings/src/perf.server.ts +15 -0
- package/test/fixtures/doctor/findings/src/routes.js +3 -0
- package/test/fixtures/doctor/findings/src/security.server.ts +7 -0
- package/test/fixtures/doctor/findings/src/users.server.ts +3 -0
- package/test/fixtures/doctor/governance/src/features/analytics/OWNERS.ts +2 -0
- package/test/fixtures/doctor/governance/src/features/analytics/page.tsx +3 -0
- package/test/fixtures/doctor/governance/src/features/billing/page.tsx +3 -0
- package/test/fixtures/explain/invalid.json +1 -0
- package/test/fixtures/explain/module-report.unsupported-version.v2.json +6 -0
- package/test/fixtures/explain/module-report.v1.json +72 -0
- package/test/fixtures/query-profiler/healthy.v1.json +11 -0
- package/test/fixtures/query-profiler/invalid.json +1 -0
- package/test/fixtures/query-profiler/unsupported-version.v2.json +6 -0
- package/test/fixtures/query-profiler/warning.v1.json +10 -0
- package/test/fixtures/realtime-monitor/healthy.v1.json +8 -0
- package/test/fixtures/realtime-monitor/invalid.json +1 -0
- package/test/fixtures/realtime-monitor/unsupported-version.v2.json +8 -0
- package/test/fixtures/realtime-monitor/warning.v1.json +8 -0
- package/test/help-parity.test.ts +104 -0
- package/test/init.test.ts +164 -0
- package/test/inspect-cache.test.ts +112 -0
- package/test/lsp-inline-hints.test.ts +65 -0
- package/test/query-profiler.test.ts +123 -0
- package/test/realtime-monitor.test.ts +115 -0
- package/test/registry.test.ts +41 -0
- package/test/start.test.ts +23 -0
- package/test/test-command.test.ts +65 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"explain": {
|
|
4
|
+
"module": "routes/dashboard/dashboard.server.ts",
|
|
5
|
+
"queries": [
|
|
6
|
+
{
|
|
7
|
+
"name": "listDashboardStats",
|
|
8
|
+
"realtime": "subscribed via tags"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "listAudits",
|
|
12
|
+
"auth": "admin"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"actions": [
|
|
16
|
+
{
|
|
17
|
+
"name": "refreshAll"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"warnings": [
|
|
21
|
+
"action refreshAll has no explicit errors() channel"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"waterfall": {
|
|
25
|
+
"requestId": "req-warn",
|
|
26
|
+
"operations": [
|
|
27
|
+
{
|
|
28
|
+
"name": "route.match",
|
|
29
|
+
"kind": "routing",
|
|
30
|
+
"startMs": 0,
|
|
31
|
+
"durationMs": 4,
|
|
32
|
+
"blocking": false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "listDashboardStats",
|
|
36
|
+
"kind": "query",
|
|
37
|
+
"startMs": 4,
|
|
38
|
+
"durationMs": 260,
|
|
39
|
+
"blocking": true
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "listAudits",
|
|
43
|
+
"kind": "query",
|
|
44
|
+
"startMs": 270,
|
|
45
|
+
"durationMs": 180,
|
|
46
|
+
"blocking": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "render",
|
|
50
|
+
"kind": "render",
|
|
51
|
+
"startMs": 460,
|
|
52
|
+
"durationMs": 92,
|
|
53
|
+
"blocking": true
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"phases": [
|
|
57
|
+
{
|
|
58
|
+
"name": "routing",
|
|
59
|
+
"durationMs": 4
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "data",
|
|
63
|
+
"durationMs": 440
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "render",
|
|
67
|
+
"durationMs": 92
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"performance": {
|
|
72
|
+
"routes": [
|
|
73
|
+
{
|
|
74
|
+
"route": "/dashboard",
|
|
75
|
+
"jsBytes": 210000,
|
|
76
|
+
"payloadBytes": 58000,
|
|
77
|
+
"lcpMs": 980
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"route": "/dashboard/audits",
|
|
81
|
+
"jsBytes": 170000,
|
|
82
|
+
"payloadBytes": 31000,
|
|
83
|
+
"lcpMs": 860
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"realtime": {
|
|
88
|
+
"connectionState": "reconnecting",
|
|
89
|
+
"eventsPerSecond": 4.2,
|
|
90
|
+
"lagP95Ms": 420,
|
|
91
|
+
"droppedRatio": 0.16,
|
|
92
|
+
"subscriptions": [
|
|
93
|
+
{
|
|
94
|
+
"tag": "dashboard:stats",
|
|
95
|
+
"channel": "dashboard.ws",
|
|
96
|
+
"state": "active",
|
|
97
|
+
"authScope": "admin"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"tag": "dashboard:alerts",
|
|
101
|
+
"channel": "dashboard.ws",
|
|
102
|
+
"state": "active"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"auth": {
|
|
107
|
+
"sessionStatus": "expired",
|
|
108
|
+
"routeAuth": "admin",
|
|
109
|
+
"permissions": [
|
|
110
|
+
"dashboard:read"
|
|
111
|
+
],
|
|
112
|
+
"tokenExpiresInSec": 120
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function listEverything(repo: { findMany: () => Promise<unknown[]> }): Promise<unknown[]> {
|
|
2
|
+
return repo.findMany();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export async function hydrateUsers(
|
|
6
|
+
ids: readonly string[],
|
|
7
|
+
api: { fetchUser: (id: string) => Promise<unknown> },
|
|
8
|
+
): Promise<unknown[]> {
|
|
9
|
+
const users: unknown[] = [];
|
|
10
|
+
for (const id of ids) {
|
|
11
|
+
users.push(await api.fetchUser(id));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return users;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "schemaVersion": 1, "module": "routes/example.server.ts", "queries": [
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"module": "routes/guestbook/guestbook.server.ts",
|
|
4
|
+
"queries": [
|
|
5
|
+
{
|
|
6
|
+
"name": "listMessages",
|
|
7
|
+
"key": {
|
|
8
|
+
"value": [
|
|
9
|
+
"routes/guestbook/guestbook.server",
|
|
10
|
+
"listMessages",
|
|
11
|
+
"hash(args)"
|
|
12
|
+
],
|
|
13
|
+
"source": "inferred"
|
|
14
|
+
},
|
|
15
|
+
"tags": {
|
|
16
|
+
"value": ["guestbook:messages"],
|
|
17
|
+
"source": "explicit"
|
|
18
|
+
},
|
|
19
|
+
"cache": {
|
|
20
|
+
"value": {
|
|
21
|
+
"staleTime": "10s",
|
|
22
|
+
"gcTime": "10m"
|
|
23
|
+
},
|
|
24
|
+
"source": "explicit"
|
|
25
|
+
},
|
|
26
|
+
"realtime": {
|
|
27
|
+
"value": "subscribed via tags",
|
|
28
|
+
"source": "inferred"
|
|
29
|
+
},
|
|
30
|
+
"auth": {
|
|
31
|
+
"value": "user",
|
|
32
|
+
"source": "inherited"
|
|
33
|
+
},
|
|
34
|
+
"mask": {
|
|
35
|
+
"value": "none",
|
|
36
|
+
"source": "none"
|
|
37
|
+
},
|
|
38
|
+
"estimatedPayloadBytes": 2458
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"actions": [
|
|
42
|
+
{
|
|
43
|
+
"name": "addMessage",
|
|
44
|
+
"invalidates": {
|
|
45
|
+
"value": ["guestbook:messages"],
|
|
46
|
+
"source": "explicit"
|
|
47
|
+
},
|
|
48
|
+
"publishes": {
|
|
49
|
+
"value": ["guestbook.messageAdded"],
|
|
50
|
+
"source": "explicit"
|
|
51
|
+
},
|
|
52
|
+
"auth": {
|
|
53
|
+
"value": "public",
|
|
54
|
+
"source": "explicit"
|
|
55
|
+
},
|
|
56
|
+
"rateLimit": {
|
|
57
|
+
"value": "20/10s",
|
|
58
|
+
"source": "explicit"
|
|
59
|
+
},
|
|
60
|
+
"input": {
|
|
61
|
+
"value": "{ text: string (1-200 chars) }",
|
|
62
|
+
"source": "explicit"
|
|
63
|
+
},
|
|
64
|
+
"errors": {
|
|
65
|
+
"value": [],
|
|
66
|
+
"source": "none"
|
|
67
|
+
},
|
|
68
|
+
"suggestions": ["consider adding .errors() for client-side error handling"]
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"warnings": []
|
|
72
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"samples": [
|
|
4
|
+
{ "name": "users.byId", "key": "users:u1", "ms": 10, "cache": "hit" },
|
|
5
|
+
{ "name": "users.byId", "key": "users:u2", "ms": 12, "cache": "hit" },
|
|
6
|
+
{ "name": "teams.list", "key": "teams:list", "ms": 35, "cache": "miss" },
|
|
7
|
+
{ "name": "teams.list", "key": "teams:list", "ms": 30, "cache": "stale" },
|
|
8
|
+
{ "name": "projects.list", "key": "projects:list", "ms": 25, "cache": "hit" },
|
|
9
|
+
{ "name": "projects.list", "key": "projects:list", "ms": 18, "cache": "hit" }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "schemaVersion": 1, "samples": [ { "name": "users.byId" }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"samples": [
|
|
4
|
+
{ "name": "users.byId", "key": "users:u1", "ms": 120, "cache": "miss" },
|
|
5
|
+
{ "name": "users.byId", "key": "users:u2", "ms": 150, "cache": "miss" },
|
|
6
|
+
{ "name": "teams.list", "key": "teams:list", "ms": 95, "cache": "hit" },
|
|
7
|
+
{ "name": "teams.list", "key": "teams:list", "ms": 180, "cache": "stale" },
|
|
8
|
+
{ "name": "projects.list", "key": "projects:list", "ms": 130, "cache": "miss" }
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "schemaVersion": 1, "rx": 1200, "tx": 1188
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { commandRegistry, renderCommandHelp, renderGlobalHelp } from "../src";
|
|
7
|
+
|
|
8
|
+
function parseDocumentedGlobalCommands(markdown: string): string[] {
|
|
9
|
+
const block = markdown.match(/## Global Commands\s+```([\s\S]*?)```/);
|
|
10
|
+
if (!block) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return block[1]
|
|
15
|
+
.split(/\r?\n/)
|
|
16
|
+
.map((line) => line.trim())
|
|
17
|
+
.filter((line) => line.startsWith("aurora "))
|
|
18
|
+
.map((line) => {
|
|
19
|
+
const tokens = line.split(/\s+/);
|
|
20
|
+
return tokens[1] ?? "";
|
|
21
|
+
})
|
|
22
|
+
.filter((command) => command.length > 0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseDocumentedSectionOptions(markdown: string, section: string): string[] {
|
|
26
|
+
const sectionHeading = `## ${section}`;
|
|
27
|
+
const sectionIndex = markdown.indexOf(sectionHeading);
|
|
28
|
+
if (sectionIndex < 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const fenceStart = markdown.indexOf("```", sectionIndex);
|
|
33
|
+
if (fenceStart < 0) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const fenceEnd = markdown.indexOf("```", fenceStart + 3);
|
|
38
|
+
if (fenceEnd < 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return markdown
|
|
43
|
+
.slice(fenceStart + 3, fenceEnd)
|
|
44
|
+
.split(/\r?\n/)
|
|
45
|
+
.map((line) => line.trim())
|
|
46
|
+
.filter((line) => line.startsWith("--"))
|
|
47
|
+
.map((line) => line.split(/\s{2,}/)[0] ?? line)
|
|
48
|
+
.filter((line) => line.length > 0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe("CLI/docs parity", () => {
|
|
52
|
+
const markdown = readFileSync(
|
|
53
|
+
join(import.meta.dir, "../../plan/aurora_cli_help.md"),
|
|
54
|
+
"utf8",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
it("supports every command documented in global command help", () => {
|
|
58
|
+
const documentedCommands = parseDocumentedGlobalCommands(markdown);
|
|
59
|
+
const implemented = new Set(commandRegistry.map((command) => command.name));
|
|
60
|
+
|
|
61
|
+
for (const documented of documentedCommands) {
|
|
62
|
+
expect(implemented.has(documented)).toBe(true);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("renders every documented command in global help output", () => {
|
|
67
|
+
const documentedCommands = parseDocumentedGlobalCommands(markdown);
|
|
68
|
+
const output = renderGlobalHelp();
|
|
69
|
+
|
|
70
|
+
for (const documented of documentedCommands) {
|
|
71
|
+
expect(output).toContain(documented);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("includes documented scaffold/core command options in command help", () => {
|
|
76
|
+
const cases = [
|
|
77
|
+
{ section: "create", commandName: "create" },
|
|
78
|
+
{ section: "init", commandName: "init" },
|
|
79
|
+
{ section: "create-route", commandName: "create-route" },
|
|
80
|
+
{ section: "create-feature", commandName: "create-feature" },
|
|
81
|
+
{ section: "dev", commandName: "dev" },
|
|
82
|
+
{ section: "devtools", commandName: "devtools" },
|
|
83
|
+
{ section: "build", commandName: "build" },
|
|
84
|
+
{ section: "analyze", commandName: "analyze" },
|
|
85
|
+
{ section: "ai", commandName: "ai" },
|
|
86
|
+
{ section: "explain", commandName: "explain" },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
for (const entry of cases) {
|
|
90
|
+
const command = commandRegistry.find((item) => item.name === entry.commandName);
|
|
91
|
+
expect(command).toBeDefined();
|
|
92
|
+
if (!command) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const help = renderCommandHelp(command);
|
|
97
|
+
const documentedFlags = parseDocumentedSectionOptions(markdown, entry.section);
|
|
98
|
+
|
|
99
|
+
for (const flag of documentedFlags) {
|
|
100
|
+
expect(help).toContain(flag);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { runAuroraCli } from "../src";
|
|
7
|
+
|
|
8
|
+
function createTempWorkspace(prefix: string): string {
|
|
9
|
+
const unique = `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1_000_000)}`;
|
|
10
|
+
const cwd = join("/tmp", unique);
|
|
11
|
+
mkdirSync(cwd, { recursive: true });
|
|
12
|
+
return cwd;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("aurora init", () => {
|
|
16
|
+
it("scaffolds a next.js migration suite with incremental mount and react interop bridge", () => {
|
|
17
|
+
const cwd = createTempWorkspace("aurora-init-next");
|
|
18
|
+
mkdirSync(join(cwd, "pages", "blog"), { recursive: true });
|
|
19
|
+
mkdirSync(join(cwd, "app", "dashboard"), { recursive: true });
|
|
20
|
+
writeFileSync(
|
|
21
|
+
join(cwd, "pages", "index.tsx"),
|
|
22
|
+
"export const getServerSideProps = async () => ({ props: {} });\n",
|
|
23
|
+
"utf8",
|
|
24
|
+
);
|
|
25
|
+
writeFileSync(
|
|
26
|
+
join(cwd, "pages", "blog", "[slug].tsx"),
|
|
27
|
+
"export default function BlogPost() { return null; }\n",
|
|
28
|
+
"utf8",
|
|
29
|
+
);
|
|
30
|
+
writeFileSync(
|
|
31
|
+
join(cwd, "app", "dashboard", "page.tsx"),
|
|
32
|
+
"export default function Dashboard() { return null; }\n",
|
|
33
|
+
"utf8",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const result = runAuroraCli(
|
|
37
|
+
["init", "--from", "next", "--out-dir", "migration", "--format", "json"],
|
|
38
|
+
{ cwd },
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
expect(result.exitCode).toBe(0);
|
|
42
|
+
const parsed = JSON.parse(result.stdout ?? "{}") as {
|
|
43
|
+
mode?: string;
|
|
44
|
+
framework?: string;
|
|
45
|
+
migrationMode?: string;
|
|
46
|
+
bridge?: string;
|
|
47
|
+
detectedRoutes?: number;
|
|
48
|
+
loaderCandidates?: number;
|
|
49
|
+
generatedFiles?: string[];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
expect(parsed.mode).toBe("init-migration");
|
|
53
|
+
expect(parsed.framework).toBe("next");
|
|
54
|
+
expect(parsed.migrationMode).toBe("incremental");
|
|
55
|
+
expect(parsed.bridge).toBe("react");
|
|
56
|
+
expect(parsed.detectedRoutes).toBe(3);
|
|
57
|
+
expect((parsed.loaderCandidates ?? 0) >= 1).toBe(true);
|
|
58
|
+
expect(parsed.generatedFiles?.includes("incremental/mount.server.ts")).toBe(true);
|
|
59
|
+
expect(parsed.generatedFiles?.includes("interop/react-bridge.tsx")).toBe(true);
|
|
60
|
+
expect(existsSync(join(cwd, "migration", "migration-checklist.md"))).toBe(true);
|
|
61
|
+
expect(existsSync(join(cwd, "migration", "incremental", "mount.server.ts"))).toBe(true);
|
|
62
|
+
expect(existsSync(join(cwd, "migration", "interop", "react-bridge.tsx"))).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("supports side-by-side dry-run migration for remix without writing files", () => {
|
|
66
|
+
const cwd = createTempWorkspace("aurora-init-remix");
|
|
67
|
+
mkdirSync(join(cwd, "app", "routes"), { recursive: true });
|
|
68
|
+
writeFileSync(
|
|
69
|
+
join(cwd, "app", "routes", "_index.tsx"),
|
|
70
|
+
"export const loader = async () => ({ ok: true });\n",
|
|
71
|
+
"utf8",
|
|
72
|
+
);
|
|
73
|
+
writeFileSync(
|
|
74
|
+
join(cwd, "app", "routes", "blog.$slug.tsx"),
|
|
75
|
+
"export const action = async () => ({ ok: true });\n",
|
|
76
|
+
"utf8",
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const result = runAuroraCli(
|
|
80
|
+
[
|
|
81
|
+
"init",
|
|
82
|
+
"--from",
|
|
83
|
+
"remix",
|
|
84
|
+
"--mode",
|
|
85
|
+
"side-by-side",
|
|
86
|
+
"--bridge",
|
|
87
|
+
"none",
|
|
88
|
+
"--out-dir",
|
|
89
|
+
"adoption",
|
|
90
|
+
"--dry-run",
|
|
91
|
+
"--format",
|
|
92
|
+
"json",
|
|
93
|
+
],
|
|
94
|
+
{ cwd },
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect(result.exitCode).toBe(0);
|
|
98
|
+
const parsed = JSON.parse(result.stdout ?? "{}") as {
|
|
99
|
+
framework?: string;
|
|
100
|
+
migrationMode?: string;
|
|
101
|
+
bridge?: string;
|
|
102
|
+
dryRun?: boolean;
|
|
103
|
+
detectedRoutes?: number;
|
|
104
|
+
generatedFiles?: string[];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
expect(parsed.framework).toBe("remix");
|
|
108
|
+
expect(parsed.migrationMode).toBe("side-by-side");
|
|
109
|
+
expect(parsed.bridge).toBe("none");
|
|
110
|
+
expect(parsed.dryRun).toBe(true);
|
|
111
|
+
expect(parsed.detectedRoutes).toBe(2);
|
|
112
|
+
expect(parsed.generatedFiles?.includes("incremental/mount.server.ts")).toBe(false);
|
|
113
|
+
expect(parsed.generatedFiles?.includes("interop/react-bridge.tsx")).toBe(false);
|
|
114
|
+
expect(existsSync(join(cwd, "adoption"))).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("maps sveltekit routes to aurora route conventions", () => {
|
|
118
|
+
const cwd = createTempWorkspace("aurora-init-sveltekit");
|
|
119
|
+
mkdirSync(join(cwd, "src", "routes", "blog", "[slug]"), { recursive: true });
|
|
120
|
+
writeFileSync(join(cwd, "src", "routes", "+page.svelte"), "<h1>Home</h1>\n", "utf8");
|
|
121
|
+
writeFileSync(
|
|
122
|
+
join(cwd, "src", "routes", "blog", "[slug]", "+page.svelte"),
|
|
123
|
+
"<h1>Blog</h1>\n",
|
|
124
|
+
"utf8",
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const result = runAuroraCli(
|
|
128
|
+
["init", "--from", "sveltekit", "--dry-run"],
|
|
129
|
+
{ cwd },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(result.exitCode).toBe(0);
|
|
133
|
+
expect(result.stdout).toContain("framework: sveltekit");
|
|
134
|
+
expect(result.stdout).toContain("/blog/:slug");
|
|
135
|
+
expect(result.stdout).toContain("output_files:");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("validates required flags and rejects invalid options", () => {
|
|
139
|
+
const cwd = createTempWorkspace("aurora-init-errors");
|
|
140
|
+
mkdirSync(join(cwd, "pages"), { recursive: true });
|
|
141
|
+
writeFileSync(join(cwd, "pages", "index.tsx"), "export default function Home() { return null; }\n", "utf8");
|
|
142
|
+
mkdirSync(join(cwd, "existing"), { recursive: true });
|
|
143
|
+
writeFileSync(join(cwd, "existing", "file.txt"), "occupied\n", "utf8");
|
|
144
|
+
|
|
145
|
+
const missingFrom = runAuroraCli(["init"], { cwd });
|
|
146
|
+
const invalidFrom = runAuroraCli(["init", "--from", "gatsby"], { cwd });
|
|
147
|
+
const unknownOption = runAuroraCli(["init", "--from", "next", "--unknown"], {
|
|
148
|
+
cwd,
|
|
149
|
+
});
|
|
150
|
+
const occupiedOutDir = runAuroraCli(
|
|
151
|
+
["init", "--from", "next", "--out-dir", "existing"],
|
|
152
|
+
{ cwd },
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(missingFrom.exitCode).toBe(2);
|
|
156
|
+
expect(missingFrom.stderr).toContain("--from is required");
|
|
157
|
+
expect(invalidFrom.exitCode).toBe(2);
|
|
158
|
+
expect(invalidFrom.stderr).toContain("invalid --from value 'gatsby'");
|
|
159
|
+
expect(unknownOption.exitCode).toBe(2);
|
|
160
|
+
expect(unknownOption.stderr).toContain("unknown option '--unknown'");
|
|
161
|
+
expect(occupiedOutDir.exitCode).toBe(2);
|
|
162
|
+
expect(occupiedOutDir.stderr).toContain("out-dir already exists and is not empty");
|
|
163
|
+
});
|
|
164
|
+
});
|