@ibgib/space-gib 0.0.33 → 0.0.34
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/dist/client/bootstrap.mjs +24 -51
- package/dist/client/chunk-25PXC4HP.mjs +9914 -0
- package/dist/client/chunk-RXWLL2AI.mjs +30 -0
- package/dist/client/css/activity-bar.css +417 -0
- package/dist/client/css/base.css +167 -0
- package/dist/client/css/components.css +218 -0
- package/dist/client/css/cosmic.css +557 -0
- package/dist/client/css/dev-tools.css +163 -0
- package/dist/client/css/landing.css +184 -0
- package/dist/client/css/layout.css +896 -0
- package/dist/client/css/onboarding.css +181 -0
- package/dist/client/css/repos.css +740 -0
- package/dist/client/css/variables.css +64 -0
- package/dist/client/index.html +202 -31
- package/dist/client/index.mjs +32 -32
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +11 -1056
- package/dist/respec-gib.node.mjs +5 -0
- package/dist/server/server.mjs +6879 -3109
- package/package.json +6 -6
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/cosmos/seed-cosmos-workspace.mts +69 -0
- package/src/client/css/activity-bar.css +417 -0
- package/src/client/css/base.css +167 -0
- package/src/client/css/components.css +218 -0
- package/src/client/css/cosmic.css +557 -0
- package/src/client/css/dev-tools.css +163 -0
- package/src/client/css/landing.css +184 -0
- package/src/client/css/layout.css +896 -0
- package/src/client/css/onboarding.css +181 -0
- package/src/client/css/repos.css +740 -0
- package/src/client/css/variables.css +64 -0
- package/src/client/dev-tools/vcs-workspace.mts +3 -3
- package/src/client/index.html +202 -31
- package/src/client/style.css +11 -1056
- package/src/client/ui/component/chat-view/IMPLEMENTATION.md +48 -0
- package/src/client/ui/component/chat-view/chat-view.css +381 -0
- package/src/client/ui/component/chat-view/chat-view.html +104 -0
- package/src/client/ui/component/chat-view/chat-view.mts +277 -0
- package/src/client/ui/component/chat-view/index.mts +9 -0
- package/src/client/ui/component/clone/IMPLEMENTATION.md +68 -0
- package/src/client/ui/component/clone/clone-constants.mts +16 -0
- package/src/client/ui/component/clone/clone-types.mts +60 -0
- package/src/client/ui/component/clone/clone.css +383 -0
- package/src/client/ui/component/clone/clone.html +89 -0
- package/src/client/ui/component/clone/clone.mts +620 -0
- package/src/client/ui/component/clone/index.mts +11 -0
- package/src/client/ui/component/code-editor/IMPLEMENTATION.md +89 -0
- package/src/client/ui/component/code-editor/code-editor.css +275 -0
- package/src/client/ui/component/code-editor/code-editor.html +54 -0
- package/src/client/ui/component/code-editor/code-editor.mts +427 -0
- package/src/client/ui/component/code-editor/index.mts +9 -0
- package/src/client/ui/component/cosmos-navigator/IMPLEMENTATION.md +31 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +864 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +97 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +1084 -0
- package/src/client/ui/component/cosmos-navigator/index.mts +18 -0
- package/src/client/ui/component/file-explorer/IMPLEMENTATION.md +42 -0
- package/src/client/ui/component/file-explorer/file-explorer.css +256 -0
- package/src/client/ui/component/file-explorer/file-explorer.html +75 -0
- package/src/client/ui/component/file-explorer/file-explorer.mts +346 -0
- package/src/client/ui/component/file-explorer/index.mts +9 -0
- package/src/client/ui/component/nested-chat/IMPLEMENTATION.md +18 -0
- package/src/client/ui/component/nested-chat/chat/IMPLEMENTATION.md +14 -0
- package/src/client/ui/component/nested-chat/chat/chat-constants.mts +14 -0
- package/src/client/ui/component/nested-chat/chat/chat-helpers.mts +66 -0
- package/src/client/ui/component/nested-chat/chat/chat.css +654 -0
- package/src/client/ui/component/nested-chat/chat/chat.html +90 -0
- package/src/client/ui/component/nested-chat/chat/chat.mts +646 -0
- package/src/client/ui/component/nested-chat/chat/index.mts +7 -0
- package/src/client/ui/component/nested-chat/index.mts +14 -0
- package/src/client/ui/component/nested-chat/nested-chat-constants.mts +12 -0
- package/src/client/ui/component/nested-chat/nested-chat-types.mts +53 -0
- package/src/client/ui/component/nested-chat/nested-chat.css +142 -0
- package/src/client/ui/component/nested-chat/nested-chat.html +11 -0
- package/src/client/ui/component/nested-chat/nested-chat.mts +393 -0
- package/src/client/ui/component/notes-explorer/index.mts +9 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.css +313 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.html +136 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.mts +240 -0
- package/src/client/ui/component/notes-inspector/index.mts +9 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.css +244 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.html +97 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.mts +152 -0
- package/src/client/ui/component/pitch/IMPLEMENTATION.md +48 -0
- package/src/client/ui/component/pitch/index.mts +9 -0
- package/src/client/ui/component/pitch/pitch.css +295 -0
- package/src/client/ui/component/pitch/pitch.html +97 -0
- package/src/client/ui/component/pitch/pitch.mts +135 -0
- package/src/client/ui/component/timeline/IMPLEMENTATION.md +33 -0
- package/src/client/ui/component/timeline/index.mts +9 -0
- package/src/client/ui/component/timeline/timeline.css +264 -0
- package/src/client/ui/component/timeline/timeline.html +23 -0
- package/src/client/ui/component/timeline/timeline.mts +317 -0
- package/src/client/ui/component/timeline-item-details/IMPLEMENTATION.md +28 -0
- package/src/client/ui/component/timeline-item-details/index.mts +9 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.css +286 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.html +64 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.mts +194 -0
- package/src/client/ui/router/index.mts +3 -0
- package/src/client/ui/router/space-gib-router-helpers.mts +272 -0
- package/src/client/ui/router/space-gib-router-helpers.respec.mts +353 -0
- package/src/client/ui/router/space-gib-router-service.mts +186 -0
- package/src/client/ui/router/space-gib-router-types.mts +93 -0
- package/src/client/ui/shell/cosmic-big-bang.mts +844 -0
- package/src/client/ui/shell/space-gib-shell-constants.mts +7 -0
- package/src/client/ui/shell/space-gib-shell-service.mts +1728 -31
- package/src/server/server.mts +20 -1
- package/tsconfig.test.json +5 -1
- package/dist/client/chunk-CRJV762I.mjs +0 -3102
- package/dist/client/chunk-LXRCF5OS.mjs +0 -25
- package/dist/client/chunk-UBDQUZZV.mjs +0 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module client/ui/router/space-gib-router-helpers
|
|
3
|
+
*
|
|
4
|
+
* Route parsing and formatting helpers for the Space-Gib Client Router.
|
|
5
|
+
* Pure isomorphic functions with zero DOM dependency.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
SpaceGibRouteInfo, SpaceGibTenant,
|
|
10
|
+
} from './space-gib-router-types.mjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Safely decodes a URI component, returning the raw string if decoding fails.
|
|
14
|
+
*/
|
|
15
|
+
function safeDecode(str: string): string {
|
|
16
|
+
try {
|
|
17
|
+
return decodeURIComponent(str);
|
|
18
|
+
} catch {
|
|
19
|
+
return str;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Parses a browser pathname into a structured SpaceGibRouteInfo.
|
|
25
|
+
*
|
|
26
|
+
* Supports:
|
|
27
|
+
* - Polycosmos: / or /polycosmos or /@:siteUsername or /keystone/:keystoneTjp
|
|
28
|
+
* - Cosmos: /:cosmos or /@:siteUsername/:cosmos or /keystone/:keystoneTjp/:cosmos
|
|
29
|
+
* - Code Galaxy: /:cosmos/code/:galaxyId[/:branch[/*filePath]]
|
|
30
|
+
* - Notes Galaxy: /:cosmos/notes/:galaxyId[/:topicTjp]
|
|
31
|
+
* - Raw Addr (Snapshot): /:cosmos/:spaceId/addr/:ibGibAddr
|
|
32
|
+
* - Raw Tjp (Living Tip): /:cosmos/:spaceId/tjp/:tjpAddr
|
|
33
|
+
* - Admin Review: /admin/review[/:tjpGib]
|
|
34
|
+
*/
|
|
35
|
+
export function parseSpaceGibRoute(pathname: string): SpaceGibRouteInfo {
|
|
36
|
+
let p = (pathname || '').trim();
|
|
37
|
+
|
|
38
|
+
let queryObj: Record<string, string> | undefined;
|
|
39
|
+
const qIdx = p.indexOf('?');
|
|
40
|
+
if (qIdx !== -1) {
|
|
41
|
+
const qStr = p.substring(qIdx + 1);
|
|
42
|
+
p = p.substring(0, qIdx);
|
|
43
|
+
const searchParams = new URLSearchParams(qStr);
|
|
44
|
+
const q: Record<string, string> = {};
|
|
45
|
+
searchParams.forEach((val, key) => {
|
|
46
|
+
q[key] = val;
|
|
47
|
+
});
|
|
48
|
+
if (Object.keys(q).length > 0) {
|
|
49
|
+
queryObj = q;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const hIdx = p.indexOf('#');
|
|
53
|
+
if (hIdx !== -1) { p = p.substring(0, hIdx); }
|
|
54
|
+
|
|
55
|
+
if (!p || p === '/') {
|
|
56
|
+
return { kind: 'polycosmos' };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Special Route: /admin/review
|
|
60
|
+
if (p === '/admin/review') {
|
|
61
|
+
return { kind: 'admin-review' };
|
|
62
|
+
}
|
|
63
|
+
if (p.startsWith('/admin/review/')) {
|
|
64
|
+
const tjpGib = safeDecode(p.slice('/admin/review/'.length)).trim();
|
|
65
|
+
return { kind: 'admin-review', ...(tjpGib ? { tjpGib } : {}) };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const rawSegments = p.split('/').filter(s => s.length > 0);
|
|
69
|
+
if (rawSegments.length === 0) {
|
|
70
|
+
return { kind: 'polycosmos' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Extract tenant prefix if present (@username or /keystone/tjp)
|
|
74
|
+
let tenant: SpaceGibTenant | undefined;
|
|
75
|
+
let segIdx = 0;
|
|
76
|
+
|
|
77
|
+
if (rawSegments[0].startsWith('@')) {
|
|
78
|
+
const username = safeDecode(rawSegments[0].slice(1)).trim();
|
|
79
|
+
if (username) {
|
|
80
|
+
tenant = { type: 'username', siteUsername: username };
|
|
81
|
+
segIdx = 1;
|
|
82
|
+
}
|
|
83
|
+
} else if (rawSegments[0] === 'keystone' && rawSegments.length > 1) {
|
|
84
|
+
const keystoneTjp = safeDecode(rawSegments[1]).trim();
|
|
85
|
+
if (keystoneTjp) {
|
|
86
|
+
tenant = { type: 'keystone', keystoneTjp };
|
|
87
|
+
segIdx = 2;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const remaining = rawSegments.slice(segIdx);
|
|
92
|
+
|
|
93
|
+
// If only tenant specifier was given (e.g. /@bill or /keystone/tjp123)
|
|
94
|
+
if (remaining.length === 0) {
|
|
95
|
+
return { kind: 'polycosmos', ...(tenant ? { tenant } : {}) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (remaining.length === 1 && remaining[0] === 'polycosmos') {
|
|
99
|
+
return { kind: 'polycosmos', ...(tenant ? { tenant } : {}) };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const cosmos = safeDecode(remaining[0]).trim();
|
|
103
|
+
|
|
104
|
+
if (remaining.length === 1) {
|
|
105
|
+
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const second = safeDecode(remaining[1]).trim();
|
|
109
|
+
|
|
110
|
+
// Code Galaxy: /:cosmos/code/:galaxyId[/:branch[/*filePath]]
|
|
111
|
+
if (second === 'code') {
|
|
112
|
+
const galaxyId = remaining[2] ? safeDecode(remaining[2]).trim() : '';
|
|
113
|
+
if (!galaxyId) {
|
|
114
|
+
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
115
|
+
}
|
|
116
|
+
const branch = remaining[3] ? safeDecode(remaining[3]).trim() : undefined;
|
|
117
|
+
const filePath = remaining.length > 4 ? remaining.slice(4).map(safeDecode).join('/') : undefined;
|
|
118
|
+
return {
|
|
119
|
+
kind: 'code-galaxy',
|
|
120
|
+
...(tenant ? { tenant } : {}),
|
|
121
|
+
cosmos,
|
|
122
|
+
galaxyId,
|
|
123
|
+
...(branch ? { branch } : {}),
|
|
124
|
+
...(filePath ? { filePath } : {}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Notes Galaxy: /:cosmos/notes/:galaxyId[/tjp/:tjp1/:tjp2...] or [/addr/:addr1/:addr2...] or [/:topicTjp]
|
|
129
|
+
if (second === 'notes') {
|
|
130
|
+
const galaxyId = remaining[2] ? safeDecode(remaining[2]).trim() : '';
|
|
131
|
+
if (!galaxyId) {
|
|
132
|
+
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let trailMode: 'tjp' | 'addr' | undefined;
|
|
136
|
+
let trail: string[] | undefined;
|
|
137
|
+
let topicTjp: string | undefined;
|
|
138
|
+
|
|
139
|
+
if (remaining.length > 3) {
|
|
140
|
+
const modeCandidate = safeDecode(remaining[3]).trim();
|
|
141
|
+
if (modeCandidate === 'tjp' || modeCandidate === 'addr') {
|
|
142
|
+
trailMode = modeCandidate;
|
|
143
|
+
const trailSegments = remaining.slice(4).map(s => safeDecode(s).trim()).filter(s => s.length > 0);
|
|
144
|
+
if (trailSegments.length > 0) {
|
|
145
|
+
trail = trailSegments;
|
|
146
|
+
topicTjp = trailSegments[0];
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// Backward compatibility / shorthand: /notes/:galaxyId/:topicTjp
|
|
150
|
+
topicTjp = modeCandidate;
|
|
151
|
+
trailMode = 'tjp';
|
|
152
|
+
trail = [modeCandidate];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
kind: 'notes-galaxy',
|
|
158
|
+
...(tenant ? { tenant } : {}),
|
|
159
|
+
cosmos,
|
|
160
|
+
galaxyId,
|
|
161
|
+
...(trailMode ? { trailMode } : {}),
|
|
162
|
+
...(trail ? { trail } : {}),
|
|
163
|
+
...(topicTjp ? { topicTjp } : {}),
|
|
164
|
+
...(queryObj ? { query: queryObj } : {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Mechanism 1: Space-Qualified Raw Addrs
|
|
169
|
+
// /:cosmos/:spaceId/addr/:ibGibAddr
|
|
170
|
+
// /:cosmos/:spaceId/tjp/:tjpAddr
|
|
171
|
+
if (remaining.length >= 4) {
|
|
172
|
+
const third = safeDecode(remaining[2]).trim();
|
|
173
|
+
const spaceId = second;
|
|
174
|
+
if (third === 'addr') {
|
|
175
|
+
const ibGibAddr = safeDecode(remaining.slice(3).join('/')).trim();
|
|
176
|
+
return {
|
|
177
|
+
kind: 'raw-addr',
|
|
178
|
+
...(tenant ? { tenant } : {}),
|
|
179
|
+
cosmos,
|
|
180
|
+
spaceId,
|
|
181
|
+
ibGibAddr,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (third === 'tjp') {
|
|
185
|
+
const tjpAddr = safeDecode(remaining.slice(3).join('/')).trim();
|
|
186
|
+
return {
|
|
187
|
+
kind: 'raw-tjp',
|
|
188
|
+
...(tenant ? { tenant } : {}),
|
|
189
|
+
cosmos,
|
|
190
|
+
spaceId,
|
|
191
|
+
tjpAddr,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Fallback: Cosmos route
|
|
197
|
+
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Formats a SpaceGibRouteInfo into a canonical URL pathname.
|
|
202
|
+
*/
|
|
203
|
+
export function formatSpaceGibRoute(route: SpaceGibRouteInfo): string {
|
|
204
|
+
if (route.kind === 'admin-review') {
|
|
205
|
+
return `/admin/review${route.tjpGib ? `/${encodeURIComponent(route.tjpGib)}` : ''}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let prefix = '';
|
|
209
|
+
if (route.tenant) {
|
|
210
|
+
if (route.tenant.type === 'username') {
|
|
211
|
+
prefix = `/@${encodeURIComponent(route.tenant.siteUsername)}`;
|
|
212
|
+
} else if (route.tenant.type === 'keystone') {
|
|
213
|
+
prefix = `/keystone/${encodeURIComponent(route.tenant.keystoneTjp)}`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
switch (route.kind) {
|
|
218
|
+
case 'polycosmos':
|
|
219
|
+
return prefix ? `${prefix}/polycosmos` : '/';
|
|
220
|
+
|
|
221
|
+
case 'cosmos':
|
|
222
|
+
return `${prefix}/${encodeURIComponent(route.cosmos)}`;
|
|
223
|
+
|
|
224
|
+
case 'code-galaxy': {
|
|
225
|
+
let res = `${prefix}/${encodeURIComponent(route.cosmos)}/code/${encodeURIComponent(route.galaxyId)}`;
|
|
226
|
+
if (route.branch) {
|
|
227
|
+
res += `/${encodeURIComponent(route.branch)}`;
|
|
228
|
+
if (route.filePath) {
|
|
229
|
+
res += `/${route.filePath.split('/').map(encodeURIComponent).join('/')}`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return res;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
case 'notes-galaxy': {
|
|
236
|
+
let res = `${prefix}/${encodeURIComponent(route.cosmos)}/notes/${encodeURIComponent(route.galaxyId)}`;
|
|
237
|
+
if (route.trail && route.trail.length > 0) {
|
|
238
|
+
const mode = route.trailMode || 'tjp';
|
|
239
|
+
res += `/${mode}/${route.trail.map(encodeURIComponent).join('/')}`;
|
|
240
|
+
} else if (route.topicTjp) {
|
|
241
|
+
res += `/${encodeURIComponent(route.topicTjp)}`;
|
|
242
|
+
}
|
|
243
|
+
if (route.query && Object.keys(route.query).length > 0) {
|
|
244
|
+
const sp = new URLSearchParams();
|
|
245
|
+
for (const [k, v] of Object.entries(route.query)) {
|
|
246
|
+
if (v !== undefined) { sp.set(k, v); }
|
|
247
|
+
}
|
|
248
|
+
const qs = sp.toString();
|
|
249
|
+
if (qs) { res += `?${qs}`; }
|
|
250
|
+
}
|
|
251
|
+
return res;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case 'raw-addr':
|
|
255
|
+
return `${prefix}/${encodeURIComponent(route.cosmos)}/${encodeURIComponent(route.spaceId)}/addr/${encodeURIComponent(route.ibGibAddr)}`;
|
|
256
|
+
|
|
257
|
+
case 'raw-tjp':
|
|
258
|
+
return `${prefix}/${encodeURIComponent(route.cosmos)}/${encodeURIComponent(route.spaceId)}/tjp/${encodeURIComponent(route.tjpAddr)}`;
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
return '/';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Compares two routes for equivalence by comparing their canonical formatted paths.
|
|
267
|
+
*/
|
|
268
|
+
export function isSameRoute(a?: SpaceGibRouteInfo, b?: SpaceGibRouteInfo): boolean {
|
|
269
|
+
if (!a && !b) { return true; }
|
|
270
|
+
if (!a || !b) { return false; }
|
|
271
|
+
return formatSpaceGibRoute(a) === formatSpaceGibRoute(b);
|
|
272
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import {
|
|
2
|
+
respecfully, iReckon, ifWe, ifWeMight // don't remove unused ifWe or ifWeMight
|
|
3
|
+
} from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
4
|
+
const sir = `[${import.meta.url}]`;
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
parseSpaceGibRoute,
|
|
8
|
+
formatSpaceGibRoute,
|
|
9
|
+
isSameRoute,
|
|
10
|
+
} from './space-gib-router-helpers.mjs';
|
|
11
|
+
import {
|
|
12
|
+
SpaceGibRouteInfo,
|
|
13
|
+
PolycosmosRouteInfo,
|
|
14
|
+
CosmosRouteInfo,
|
|
15
|
+
CodeGalaxyRouteInfo,
|
|
16
|
+
NotesGalaxyRouteInfo,
|
|
17
|
+
RawAddrRouteInfo,
|
|
18
|
+
RawTjpRouteInfo,
|
|
19
|
+
} from './space-gib-router-types.mjs';
|
|
20
|
+
|
|
21
|
+
await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
|
|
22
|
+
|
|
23
|
+
await respecfully(sir, 'Polycosmos Routes', async () => {
|
|
24
|
+
await ifWe(sir, 'parses root / as polycosmos', async () => {
|
|
25
|
+
const route = parseSpaceGibRoute('/');
|
|
26
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
27
|
+
iReckon(sir, (route as PolycosmosRouteInfo).tenant).willEqual(undefined);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await ifWe(sir, 'parses empty path as polycosmos', async () => {
|
|
31
|
+
const route = parseSpaceGibRoute('');
|
|
32
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
await ifWe(sir, 'parses /polycosmos as polycosmos', async () => {
|
|
36
|
+
const route = parseSpaceGibRoute('/polycosmos');
|
|
37
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await ifWe(sir, 'parses /@bill as polycosmos with username tenant', async () => {
|
|
41
|
+
const route = parseSpaceGibRoute('/@bill');
|
|
42
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
43
|
+
const tenant = (route as PolycosmosRouteInfo).tenant;
|
|
44
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
45
|
+
if (tenant && tenant.type === 'username') {
|
|
46
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await ifWe(sir, 'parses /@bill/polycosmos as polycosmos with username tenant', async () => {
|
|
51
|
+
const route = parseSpaceGibRoute('/@bill/polycosmos');
|
|
52
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
53
|
+
const tenant = (route as PolycosmosRouteInfo).tenant;
|
|
54
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
55
|
+
if (tenant && tenant.type === 'username') {
|
|
56
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await ifWe(sir, 'parses /keystone/tjp123 as polycosmos with keystone tenant', async () => {
|
|
61
|
+
const route = parseSpaceGibRoute('/keystone/tjp123');
|
|
62
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
63
|
+
const tenant = (route as PolycosmosRouteInfo).tenant;
|
|
64
|
+
iReckon(sir, tenant?.type).willEqual('keystone');
|
|
65
|
+
if (tenant && tenant.type === 'keystone') {
|
|
66
|
+
iReckon(sir, tenant.keystoneTjp).willEqual('tjp123');
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await ifWe(sir, 'parses /keystone/tjp123/polycosmos as polycosmos with keystone tenant', async () => {
|
|
71
|
+
const route = parseSpaceGibRoute('/keystone/tjp123/polycosmos');
|
|
72
|
+
iReckon(sir, route.kind).willEqual('polycosmos');
|
|
73
|
+
const tenant = (route as PolycosmosRouteInfo).tenant;
|
|
74
|
+
iReckon(sir, tenant?.type).willEqual('keystone');
|
|
75
|
+
if (tenant && tenant.type === 'keystone') {
|
|
76
|
+
iReckon(sir, tenant.keystoneTjp).willEqual('tjp123');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await respecfully(sir, 'Cosmos Routes', async () => {
|
|
82
|
+
await ifWe(sir, 'parses /my-cosmos as cosmos', async () => {
|
|
83
|
+
const route = parseSpaceGibRoute('/my-cosmos');
|
|
84
|
+
iReckon(sir, route.kind).willEqual('cosmos');
|
|
85
|
+
iReckon(sir, (route as CosmosRouteInfo).cosmos).willEqual('my-cosmos');
|
|
86
|
+
iReckon(sir, (route as CosmosRouteInfo).tenant).willEqual(undefined);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await ifWe(sir, 'parses /@bill/my-cosmos as cosmos with username tenant', async () => {
|
|
90
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos');
|
|
91
|
+
iReckon(sir, route.kind).willEqual('cosmos');
|
|
92
|
+
iReckon(sir, (route as CosmosRouteInfo).cosmos).willEqual('my-cosmos');
|
|
93
|
+
const tenant = (route as CosmosRouteInfo).tenant;
|
|
94
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
95
|
+
if (tenant && tenant.type === 'username') {
|
|
96
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await ifWe(sir, 'parses /keystone/tjp123/my-cosmos as cosmos with keystone tenant', async () => {
|
|
101
|
+
const route = parseSpaceGibRoute('/keystone/tjp123/my-cosmos');
|
|
102
|
+
iReckon(sir, route.kind).willEqual('cosmos');
|
|
103
|
+
iReckon(sir, (route as CosmosRouteInfo).cosmos).willEqual('my-cosmos');
|
|
104
|
+
const tenant = (route as CosmosRouteInfo).tenant;
|
|
105
|
+
iReckon(sir, tenant?.type).willEqual('keystone');
|
|
106
|
+
if (tenant && tenant.type === 'keystone') {
|
|
107
|
+
iReckon(sir, tenant.keystoneTjp).willEqual('tjp123');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await respecfully(sir, 'Code Galaxy Routes', async () => {
|
|
113
|
+
await ifWe(sir, 'parses /my-cosmos/code/code-1 with galaxyId', async () => {
|
|
114
|
+
const route = parseSpaceGibRoute('/my-cosmos/code/code-1');
|
|
115
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
116
|
+
const cg = route as CodeGalaxyRouteInfo;
|
|
117
|
+
iReckon(sir, cg.cosmos).willEqual('my-cosmos');
|
|
118
|
+
iReckon(sir, cg.galaxyId).willEqual('code-1');
|
|
119
|
+
iReckon(sir, cg.branch).willEqual(undefined);
|
|
120
|
+
iReckon(sir, cg.filePath).willEqual(undefined);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await ifWe(sir, 'parses /my-cosmos/code/code-1/main with branch', async () => {
|
|
124
|
+
const route = parseSpaceGibRoute('/my-cosmos/code/code-1/main');
|
|
125
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
126
|
+
const cg = route as CodeGalaxyRouteInfo;
|
|
127
|
+
iReckon(sir, cg.cosmos).willEqual('my-cosmos');
|
|
128
|
+
iReckon(sir, cg.galaxyId).willEqual('code-1');
|
|
129
|
+
iReckon(sir, cg.branch).willEqual('main');
|
|
130
|
+
iReckon(sir, cg.filePath).willEqual(undefined);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await ifWe(sir, 'parses /my-cosmos/code/code-1/main/src/index.ts with branch and deep filePath', async () => {
|
|
134
|
+
const route = parseSpaceGibRoute('/my-cosmos/code/code-1/main/src/index.ts');
|
|
135
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
136
|
+
const cg = route as CodeGalaxyRouteInfo;
|
|
137
|
+
iReckon(sir, cg.cosmos).willEqual('my-cosmos');
|
|
138
|
+
iReckon(sir, cg.galaxyId).willEqual('code-1');
|
|
139
|
+
iReckon(sir, cg.branch).willEqual('main');
|
|
140
|
+
iReckon(sir, cg.filePath).willEqual('src/index.ts');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await ifWe(sir, 'parses /@bill/my-cosmos/code/code-1/feat-x/src/deep/nested/file.mts with tenant and deep path', async () => {
|
|
144
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos/code/code-1/feat-x/src/deep/nested/file.mts');
|
|
145
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
146
|
+
const cg = route as CodeGalaxyRouteInfo;
|
|
147
|
+
const tenant = cg.tenant;
|
|
148
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
149
|
+
if (tenant && tenant.type === 'username') {
|
|
150
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
151
|
+
}
|
|
152
|
+
iReckon(sir, cg.cosmos).willEqual('my-cosmos');
|
|
153
|
+
iReckon(sir, cg.galaxyId).willEqual('code-1');
|
|
154
|
+
iReckon(sir, cg.branch).willEqual('feat-x');
|
|
155
|
+
iReckon(sir, cg.filePath).willEqual('src/deep/nested/file.mts');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
await respecfully(sir, 'Notes Galaxy Routes', async () => {
|
|
160
|
+
await ifWe(sir, 'parses /my-cosmos/notes/notes-1 with galaxyId', async () => {
|
|
161
|
+
const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1');
|
|
162
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
163
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
164
|
+
iReckon(sir, ng.cosmos).willEqual('my-cosmos');
|
|
165
|
+
iReckon(sir, ng.galaxyId).willEqual('notes-1');
|
|
166
|
+
iReckon(sir, ng.topicTjp).willEqual(undefined);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
await ifWe(sir, 'parses /my-cosmos/notes/notes-1/topic_abc with topicTjp', async () => {
|
|
170
|
+
const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1/topic_abc');
|
|
171
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
172
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
173
|
+
iReckon(sir, ng.cosmos).willEqual('my-cosmos');
|
|
174
|
+
iReckon(sir, ng.galaxyId).willEqual('notes-1');
|
|
175
|
+
iReckon(sir, ng.topicTjp).willEqual('topic_abc');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
await ifWe(sir, 'parses /@bill/my-cosmos/notes/notes-1/topic_abc with tenant and topicTjp', async () => {
|
|
179
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/topic_abc');
|
|
180
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
181
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
182
|
+
const tenant = ng.tenant;
|
|
183
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
184
|
+
if (tenant && tenant.type === 'username') {
|
|
185
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
186
|
+
}
|
|
187
|
+
iReckon(sir, ng.cosmos).willEqual('my-cosmos');
|
|
188
|
+
iReckon(sir, ng.galaxyId).willEqual('notes-1');
|
|
189
|
+
iReckon(sir, ng.topicTjp).willEqual('topic_abc');
|
|
190
|
+
iReckon(sir, ng.trailMode).willEqual('tjp');
|
|
191
|
+
iReckon(sir, ng.trail?.length).willEqual(1);
|
|
192
|
+
iReckon(sir, ng.trail?.[0]).willEqual('topic_abc');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
await ifWe(sir, 'parses /@bill/my-cosmos/notes/notes-1/tjp/topic_1/reply_2/reply_3 as n-depth tjp trail', async () => {
|
|
196
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/tjp/topic_1/reply_2/reply_3');
|
|
197
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
198
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
199
|
+
iReckon(sir, ng.cosmos).willEqual('my-cosmos');
|
|
200
|
+
iReckon(sir, ng.galaxyId).willEqual('notes-1');
|
|
201
|
+
iReckon(sir, ng.trailMode).willEqual('tjp');
|
|
202
|
+
iReckon(sir, ng.trail?.length).willEqual(3);
|
|
203
|
+
iReckon(sir, ng.trail?.[0]).willEqual('topic_1');
|
|
204
|
+
iReckon(sir, ng.trail?.[1]).willEqual('reply_2');
|
|
205
|
+
iReckon(sir, ng.trail?.[2]).willEqual('reply_3');
|
|
206
|
+
iReckon(sir, ng.topicTjp).willEqual('topic_1');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
await ifWe(sir, 'parses /my-cosmos/notes/notes-1/addr/hash1/hash2 as n-depth reified addr trail', async () => {
|
|
210
|
+
const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1/addr/hash1/hash2');
|
|
211
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
212
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
213
|
+
iReckon(sir, ng.cosmos).willEqual('my-cosmos');
|
|
214
|
+
iReckon(sir, ng.galaxyId).willEqual('notes-1');
|
|
215
|
+
iReckon(sir, ng.trailMode).willEqual('addr');
|
|
216
|
+
iReckon(sir, ng.trail?.length).willEqual(2);
|
|
217
|
+
iReckon(sir, ng.trail?.[0]).willEqual('hash1');
|
|
218
|
+
iReckon(sir, ng.trail?.[1]).willEqual('hash2');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await ifWe(sir, 'parses query params for right-panel inspector and lenses', async () => {
|
|
222
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/tjp/topic_1?inspect=src%2Findex.ts%23L10&lens=issues');
|
|
223
|
+
iReckon(sir, route.kind).willEqual('notes-galaxy');
|
|
224
|
+
const ng = route as NotesGalaxyRouteInfo;
|
|
225
|
+
iReckon(sir, ng.query?.inspect).willEqual('src/index.ts#L10');
|
|
226
|
+
iReckon(sir, ng.query?.lens).willEqual('issues');
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
await respecfully(sir, 'Mechanism 1: Space-Qualified Raw Addrs', async () => {
|
|
231
|
+
await ifWe(sir, 'parses /:cosmos/:spaceId/addr/:ibGibAddr snapshot route', async () => {
|
|
232
|
+
const route = parseSpaceGibRoute('/my-cosmos/space-1/addr/comment%20hello^gib_1');
|
|
233
|
+
iReckon(sir, route.kind).willEqual('raw-addr');
|
|
234
|
+
const ra = route as RawAddrRouteInfo;
|
|
235
|
+
iReckon(sir, ra.cosmos).willEqual('my-cosmos');
|
|
236
|
+
iReckon(sir, ra.spaceId).willEqual('space-1');
|
|
237
|
+
iReckon(sir, ra.ibGibAddr).willEqual('comment hello^gib_1');
|
|
238
|
+
iReckon(sir, ra.tenant).willEqual(undefined);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
await ifWe(sir, 'parses /@bill/:cosmos/:spaceId/addr/:ibGibAddr with tenant', async () => {
|
|
242
|
+
const route = parseSpaceGibRoute('/@bill/my-cosmos/space-1/addr/comment%20hello^gib_1');
|
|
243
|
+
iReckon(sir, route.kind).willEqual('raw-addr');
|
|
244
|
+
const ra = route as RawAddrRouteInfo;
|
|
245
|
+
const tenant = ra.tenant;
|
|
246
|
+
iReckon(sir, tenant?.type).willEqual('username');
|
|
247
|
+
if (tenant && tenant.type === 'username') {
|
|
248
|
+
iReckon(sir, tenant.siteUsername).willEqual('bill');
|
|
249
|
+
}
|
|
250
|
+
iReckon(sir, ra.cosmos).willEqual('my-cosmos');
|
|
251
|
+
iReckon(sir, ra.spaceId).willEqual('space-1');
|
|
252
|
+
iReckon(sir, ra.ibGibAddr).willEqual('comment hello^gib_1');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
await ifWe(sir, 'parses /:cosmos/:spaceId/tjp/:tjpAddr living tip route', async () => {
|
|
256
|
+
const route = parseSpaceGibRoute('/my-cosmos/space-1/tjp/tjp_living_tip');
|
|
257
|
+
iReckon(sir, route.kind).willEqual('raw-tjp');
|
|
258
|
+
const rt = route as RawTjpRouteInfo;
|
|
259
|
+
iReckon(sir, rt.cosmos).willEqual('my-cosmos');
|
|
260
|
+
iReckon(sir, rt.spaceId).willEqual('space-1');
|
|
261
|
+
iReckon(sir, rt.tjpAddr).willEqual('tjp_living_tip');
|
|
262
|
+
iReckon(sir, rt.tenant).willEqual(undefined);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
await ifWe(sir, 'parses /keystone/tjp123/:cosmos/:spaceId/tjp/:tjpAddr with keystone tenant', async () => {
|
|
266
|
+
const route = parseSpaceGibRoute('/keystone/tjp123/my-cosmos/space-1/tjp/tjp_living_tip');
|
|
267
|
+
iReckon(sir, route.kind).willEqual('raw-tjp');
|
|
268
|
+
const rt = route as RawTjpRouteInfo;
|
|
269
|
+
const tenant = rt.tenant;
|
|
270
|
+
iReckon(sir, tenant?.type).willEqual('keystone');
|
|
271
|
+
if (tenant && tenant.type === 'keystone') {
|
|
272
|
+
iReckon(sir, tenant.keystoneTjp).willEqual('tjp123');
|
|
273
|
+
}
|
|
274
|
+
iReckon(sir, rt.cosmos).willEqual('my-cosmos');
|
|
275
|
+
iReckon(sir, rt.spaceId).willEqual('space-1');
|
|
276
|
+
iReckon(sir, rt.tjpAddr).willEqual('tjp_living_tip');
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await respecfully(sir, 'Admin Review Routes', async () => {
|
|
281
|
+
await ifWe(sir, 'parses /admin/review', async () => {
|
|
282
|
+
const route = parseSpaceGibRoute('/admin/review');
|
|
283
|
+
iReckon(sir, route.kind).willEqual('admin-review');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
await ifWe(sir, 'parses /admin/review/:tjpGib', async () => {
|
|
287
|
+
const route = parseSpaceGibRoute('/admin/review/tjp_challenge_999');
|
|
288
|
+
iReckon(sir, route.kind).willEqual('admin-review');
|
|
289
|
+
if (route.kind === 'admin-review') {
|
|
290
|
+
iReckon(sir, route.tjpGib).willEqual('tjp_challenge_999');
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
await respecfully(sir, 'Formatting and Round-Trip Equivalence', async () => {
|
|
296
|
+
const testCases: SpaceGibRouteInfo[] = [
|
|
297
|
+
{ kind: 'polycosmos' },
|
|
298
|
+
{ kind: 'polycosmos', tenant: { type: 'username', siteUsername: 'bill' } },
|
|
299
|
+
{ kind: 'polycosmos', tenant: { type: 'keystone', keystoneTjp: 'tjp_genesis' } },
|
|
300
|
+
{ kind: 'cosmos', cosmos: 'cosmos-alpha' },
|
|
301
|
+
{ kind: 'cosmos', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'cosmos-alpha' },
|
|
302
|
+
{ kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1' },
|
|
303
|
+
{ kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'main' },
|
|
304
|
+
{ kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'main', filePath: 'src/core/index.ts' },
|
|
305
|
+
{ kind: 'code-galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'dev', filePath: 'lib/utils.ts' },
|
|
306
|
+
{ kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1' },
|
|
307
|
+
{ kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
|
|
308
|
+
{ kind: 'notes-galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
|
|
309
|
+
{ kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 't1', trailMode: 'tjp', trail: ['t1', 't2', 't3'] },
|
|
310
|
+
{ kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', trailMode: 'addr', trail: ['a1', 'a2'] },
|
|
311
|
+
{ kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 't1', trailMode: 'tjp', trail: ['t1'], query: { inspect: 'src/index.ts#L10', lens: 'issues' } },
|
|
312
|
+
{ kind: 'raw-addr', cosmos: 'my-cosmos', spaceId: 'branch_space_main', ibGibAddr: 'comment hello world^gib_1' },
|
|
313
|
+
{ kind: 'raw-addr', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', spaceId: 'branch_space_main', ibGibAddr: 'comment hello world^gib_1' },
|
|
314
|
+
{ kind: 'raw-tjp', cosmos: 'my-cosmos', spaceId: 'branch_space_main', tjpAddr: 'tjp_dna_123' },
|
|
315
|
+
{ kind: 'admin-review' },
|
|
316
|
+
{ kind: 'admin-review', tjpGib: 'tjp_review_abc' },
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
for (const originalRoute of testCases) {
|
|
320
|
+
await ifWe(sir, `round-trips ${originalRoute.kind} correctly`, async () => {
|
|
321
|
+
const formatted = formatSpaceGibRoute(originalRoute);
|
|
322
|
+
const parsed = parseSpaceGibRoute(formatted);
|
|
323
|
+
iReckon(sir, isSameRoute(originalRoute, parsed)).willEqual(true);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
await respecfully(sir, 'Edge Cases & Robustness', async () => {
|
|
329
|
+
await ifWe(sir, 'handles trailing slashes', async () => {
|
|
330
|
+
const route = parseSpaceGibRoute('/my-cosmos/code/code-1/');
|
|
331
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
332
|
+
iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
await ifWe(sir, 'strips query parameters', async () => {
|
|
336
|
+
const route = parseSpaceGibRoute('/my-cosmos/code/code-1?branch=main&debug=true');
|
|
337
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
338
|
+
iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
await ifWe(sir, 'strips hash fragments', async () => {
|
|
342
|
+
const route = parseSpaceGibRoute('/my-cosmos#section2');
|
|
343
|
+
iReckon(sir, route.kind).willEqual('cosmos');
|
|
344
|
+
iReckon(sir, (route as CosmosRouteInfo).cosmos).willEqual('my-cosmos');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
await ifWe(sir, 'handles multiple consecutive slashes gracefully', async () => {
|
|
348
|
+
const route = parseSpaceGibRoute('///my-cosmos///code///code-1///');
|
|
349
|
+
iReckon(sir, route.kind).willEqual('code-galaxy');
|
|
350
|
+
iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
});
|