@jskit-ai/shell-web 0.1.163 → 0.1.164
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/fixtures/adaptive-shell/src/ScreenPage.vue +1 -1
- package/package.json +8 -253
- package/patterns/application-shell/PATTERN.md +66 -0
- package/{templates → patterns/application-shell/example}/expected-existing/src/pages/home/index.vue +8 -8
- package/{templates → patterns/application-shell/example}/src/pages/home/index.vue +8 -8
- package/{templates → patterns/application-shell/example}/src/pages/home/settings/general/index.vue +1 -1
- package/{templates → patterns/application-shell/example}/src/pages/home/settings.vue +8 -8
- package/patterns/page-and-placement/PATTERN.md +76 -0
- package/patterns/page-and-placement/example/packages/main/src/client/providers/MainClientProvider.js +14 -0
- package/patterns/page-and-placement/example/src/components/SyncStatusElement.vue +16 -0
- package/patterns/page-and-placement/example/src/pages/home/reports/activity.vue +8 -0
- package/patterns/page-and-placement/example/src/pages/home/reports/index.vue +7 -0
- package/patterns/page-and-placement/example/src/pages/home/reports/overview.vue +8 -0
- package/patterns/page-and-placement/example/src/pages/home/reports.vue +33 -0
- package/patterns/page-and-placement/example/src/placement.js +52 -0
- package/patterns/page-and-placement/example/src/placementTopology.js +29 -0
- package/src/client/bootstrap/bootstrapPayloadHandlerRegistry.js +30 -42
- package/src/client/bootstrap/index.js +2 -3
- package/src/client/index.js +2 -11
- package/src/client/placement/runtime.js +9 -12
- package/src/client/providers/ShellWebClientProvider.js +95 -129
- package/src/client/requestRecovery/runtime.js +9 -29
- package/src/client/runtime/bootstrapRuntime.js +18 -29
- package/src/test/adaptiveShellSmoke.js +3 -9
- package/test/bootstrapRuntime.test.js +10 -61
- package/test/pageAndPlacementPattern.test.js +38 -0
- package/test/placementRuntime.test.js +36 -50
- package/test/playwrightContract.test.js +2 -12
- package/test/provider.test.js +126 -737
- package/test/settingsPlacementContract.test.js +75 -126
- package/src/server/support/localLinkItemScaffolds.js +0 -80
- package/test/bootstrapClaimContract.test.js +0 -76
- package/test/linkItemScaffoldContract.test.js +0 -248
- /package/{templates → patterns/application-shell/example}/expected-existing/src/App.vue +0 -0
- /package/{templates → patterns/application-shell/example}/expected-existing/src/pages/home.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/App.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/components/ShellLayout.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/components/menus/MenuLinkItem.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/components/menus/SurfaceAwareMenuLinkItem.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/components/menus/TabLinkItem.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/error.js +0 -0
- /package/{templates → patterns/application-shell/example}/src/pages/home/settings/index.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/pages/home.vue +0 -0
- /package/{templates → patterns/application-shell/example}/src/placement.js +0 -0
- /package/{templates → patterns/application-shell/example}/src/placementTopology.js +0 -0
- /package/{templates → patterns/application-shell/example}/tests/e2e/adaptive-shell.spec.ts +0 -0
|
@@ -3,7 +3,6 @@ import path from "node:path";
|
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { assertGeneratedUiSourceContract } from "@jskit-ai/kernel/shared/support/generatedUiContract";
|
|
7
6
|
import packageJson from "../package.json" with { type: "json" };
|
|
8
7
|
|
|
9
8
|
const packageMetadata = packageJson.jskit;
|
|
@@ -47,24 +46,16 @@ function readPackageImportSpecifiers(source = "") {
|
|
|
47
46
|
);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
function findFileMutation(id) {
|
|
56
|
-
const files = packageMetadata?.mutations?.files;
|
|
57
|
-
return Array.isArray(files)
|
|
58
|
-
? files.find((entry) => String(entry?.id || "").trim() === id) || null
|
|
59
|
-
: null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
test("shell-web home settings template exposes surface-derived settings outlets", async () => {
|
|
63
|
-
const source = await readFile(path.join(PACKAGE_DIR, "templates", "src", "pages", "home", "settings.vue"), "utf8");
|
|
49
|
+
test("shell-web application pattern exposes surface-derived settings outlets", async () => {
|
|
50
|
+
const source = await readFile(
|
|
51
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "pages", "home", "settings.vue"),
|
|
52
|
+
"utf8"
|
|
53
|
+
);
|
|
64
54
|
|
|
65
55
|
assert.match(source, /target="home-settings:primary-menu"/);
|
|
66
|
-
assert.match(source, /
|
|
67
|
-
assert.match(source, /--
|
|
56
|
+
assert.match(source, /class="settings-shell d-flex flex-column ga-4"/);
|
|
57
|
+
assert.match(source, /--settings-shell-title-size/);
|
|
58
|
+
assert.doesNotMatch(source, /generated-ui/u);
|
|
68
59
|
assert.doesNotMatch(source, /default-link-component-token/);
|
|
69
60
|
assert.match(source, /<RouterView \/>/);
|
|
70
61
|
});
|
|
@@ -123,7 +114,10 @@ test("shell-web shell layout registers navigation at the app layout level", asyn
|
|
|
123
114
|
assert.match(source, /data-testid="jskit-shell-bottom-nav"/);
|
|
124
115
|
assert.match(source, /padding:\s*0\.75rem 1rem calc\(1rem \+ env\(safe-area-inset-bottom, 0px\)\)/);
|
|
125
116
|
|
|
126
|
-
const template = await readFile(
|
|
117
|
+
const template = await readFile(
|
|
118
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "components", "ShellLayout.vue"),
|
|
119
|
+
"utf8"
|
|
120
|
+
);
|
|
127
121
|
|
|
128
122
|
assert.match(template, /PackageShellLayout from "@jskit-ai\/shell-web\/client\/components\/ShellLayout"/);
|
|
129
123
|
assert.match(template, /drawerWidth, railWidth, navigationItemSpacing, and future shell props package-owned/);
|
|
@@ -150,8 +144,11 @@ test("shell-web error host keeps snackbar color stable while closing", async ()
|
|
|
150
144
|
assert.doesNotMatch(source, /resolveSeverityColor\(snackbarEntry\?\.severity\)/);
|
|
151
145
|
});
|
|
152
146
|
|
|
153
|
-
test("shell-web
|
|
154
|
-
const source = await readFile(
|
|
147
|
+
test("shell-web application pattern uses intent-driven default error presentation", async () => {
|
|
148
|
+
const source = await readFile(
|
|
149
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "error.js"),
|
|
150
|
+
"utf8"
|
|
151
|
+
);
|
|
155
152
|
|
|
156
153
|
assert.match(source, /resourceLoadChannel:\s*"silent"/);
|
|
157
154
|
assert.match(source, /actionFeedbackChannel:\s*"snackbar"/);
|
|
@@ -159,20 +156,19 @@ test("shell-web error template uses intent-driven default presentation", async (
|
|
|
159
156
|
assert.match(source, /blockingChannel:\s*"dialog"/);
|
|
160
157
|
});
|
|
161
158
|
|
|
162
|
-
test("shell-web
|
|
163
|
-
const source = await readFile(
|
|
159
|
+
test("shell-web application pattern includes adaptive shell Playwright coverage", async () => {
|
|
160
|
+
const source = await readFile(
|
|
161
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "tests", "e2e", "adaptive-shell.spec.ts"),
|
|
162
|
+
"utf8"
|
|
163
|
+
);
|
|
164
164
|
const helperSource = await readFile(path.join(PACKAGE_DIR, "src", "test", "adaptiveShellSmoke.js"), "utf8");
|
|
165
165
|
|
|
166
|
-
assertGeneratedUiSourceContract(helperSource, {
|
|
167
|
-
profile: "responsive-smoke",
|
|
168
|
-
sourceName: "adaptiveShellSmoke.js"
|
|
169
|
-
});
|
|
170
166
|
assert.match(source, /DEFAULT_VIEWPORTS, runAdaptiveShellSmokeCase/);
|
|
171
167
|
assert.match(source, /test\(`/);
|
|
172
168
|
assert.match(source, /runAdaptiveShellSmokeCase\(\{ page, expect, viewport \}\)/);
|
|
173
169
|
assert.doesNotMatch(source, /runAdaptiveShellSmoke\(\{/);
|
|
174
170
|
assert.match(source, /@jskit-ai\/shell-web\/test\/adaptiveShellSmoke/);
|
|
175
|
-
assert.match(helperSource, /
|
|
171
|
+
assert.match(helperSource, /adaptive shell smoke/);
|
|
176
172
|
assert.match(helperSource, /390/);
|
|
177
173
|
assert.match(helperSource, /1024/);
|
|
178
174
|
assert.match(helperSource, /1280/);
|
|
@@ -180,6 +176,8 @@ test("shell-web installs generated adaptive shell Playwright smoke coverage", as
|
|
|
180
176
|
assert.match(helperSource, /jskit-shell-drawer/);
|
|
181
177
|
assert.match(helperSource, /scrollWidth/);
|
|
182
178
|
assert.match(helperSource, /toBeGreaterThanOrEqual\(48\)/);
|
|
179
|
+
assert.match(helperSource, /getByRole\("button", \{ name: "Close navigation menu" \}\)/);
|
|
180
|
+
assert.doesNotMatch(helperSource, /\.v-navigation-drawer__scrim|generated-ui-screen/u);
|
|
183
181
|
|
|
184
182
|
const packageJson = JSON.parse(await readFile(path.join(PACKAGE_DIR, "package.json"), "utf8"));
|
|
185
183
|
assert.equal(packageJson?.exports?.["./test/adaptiveShellSmoke"], "./src/test/adaptiveShellSmoke.js");
|
|
@@ -296,22 +294,37 @@ test("shell-web route transition key preserves no-motion surfaces and animated p
|
|
|
296
294
|
);
|
|
297
295
|
});
|
|
298
296
|
|
|
299
|
-
test("shell-web settings landing page redirects to
|
|
300
|
-
const source = await readFile(
|
|
297
|
+
test("shell-web pattern settings landing page redirects to its child page", async () => {
|
|
298
|
+
const source = await readFile(
|
|
299
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "pages", "home", "settings", "index.vue"),
|
|
300
|
+
"utf8"
|
|
301
|
+
);
|
|
301
302
|
|
|
302
303
|
assert.match(source, /@jskit-ai\/kernel\/client\/pageRedirects/);
|
|
303
304
|
assert.match(source, /definePage/);
|
|
304
305
|
assert.match(source, /redirectToChild\("general"\)/);
|
|
305
306
|
});
|
|
306
307
|
|
|
307
|
-
test("shell-web settings
|
|
308
|
+
test("shell-web pattern settings page exposes an adaptive drawer preference", async () => {
|
|
308
309
|
const source = await readFile(
|
|
309
|
-
path.join(
|
|
310
|
+
path.join(
|
|
311
|
+
PACKAGE_DIR,
|
|
312
|
+
"patterns",
|
|
313
|
+
"application-shell",
|
|
314
|
+
"example",
|
|
315
|
+
"src",
|
|
316
|
+
"pages",
|
|
317
|
+
"home",
|
|
318
|
+
"settings",
|
|
319
|
+
"general",
|
|
320
|
+
"index.vue"
|
|
321
|
+
),
|
|
310
322
|
"utf8"
|
|
311
323
|
);
|
|
312
324
|
|
|
313
325
|
assert.match(source, /useShellLayoutState/);
|
|
314
|
-
assert.match(source, /
|
|
326
|
+
assert.match(source, /class="settings-general-screen d-flex flex-column ga-4"/);
|
|
327
|
+
assert.doesNotMatch(source, /generated-ui/u);
|
|
315
328
|
assert.match(source, /drawerDefaultOpen/);
|
|
316
329
|
assert.match(source, /setDrawerDefaultOpen/);
|
|
317
330
|
assert.match(source, /collapsed navigation remains available as a rail/);
|
|
@@ -321,8 +334,11 @@ test("shell-web settings general child page exposes an adaptive drawer preferenc
|
|
|
321
334
|
assert.doesNotMatch(source, /live in this browser only|tiny example|starter settings/);
|
|
322
335
|
});
|
|
323
336
|
|
|
324
|
-
test("shell-web
|
|
325
|
-
const source = await readFile(
|
|
337
|
+
test("shell-web application pattern demonstrates Home and Settings adaptive navigation", async () => {
|
|
338
|
+
const source = await readFile(
|
|
339
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "placement.js"),
|
|
340
|
+
"utf8"
|
|
341
|
+
);
|
|
326
342
|
|
|
327
343
|
assert.match(source, /id: "shell-web\.home\.menu\.home"/);
|
|
328
344
|
assert.match(source, /target: "shell\.primary-nav"/);
|
|
@@ -341,8 +357,11 @@ test("shell-web placement template seeds default Home and Settings adaptive navi
|
|
|
341
357
|
assert.doesNotMatch(source, /to: "\.\/general"/);
|
|
342
358
|
});
|
|
343
359
|
|
|
344
|
-
test("shell-web
|
|
345
|
-
const source = await readFile(
|
|
360
|
+
test("shell-web application pattern demonstrates semantic global actions", async () => {
|
|
361
|
+
const source = await readFile(
|
|
362
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "placementTopology.js"),
|
|
363
|
+
"utf8"
|
|
364
|
+
);
|
|
346
365
|
|
|
347
366
|
assert.match(source, /id: "shell\.global-actions"/);
|
|
348
367
|
assert.match(source, /description: "Global surface actions that should stay outside primary navigation\."/);
|
|
@@ -353,12 +372,12 @@ test("shell-web placement topology seeds global actions as a semantic shell plac
|
|
|
353
372
|
assert.match(source, /outlet: "shell-layout:supporting-side-panel"/);
|
|
354
373
|
});
|
|
355
374
|
|
|
356
|
-
test("shell-web packageMetadata pre-optimizes package subpaths reached
|
|
375
|
+
test("shell-web packageMetadata pre-optimizes package subpaths reached through dynamic shell modules", async () => {
|
|
357
376
|
const [providerSource, placementSource, placementTopologySource, errorSource] = await Promise.all([
|
|
358
377
|
readFile(path.join(PACKAGE_DIR, "src", "client", "providers", "ShellWebClientProvider.js"), "utf8"),
|
|
359
|
-
readFile(path.join(PACKAGE_DIR, "
|
|
360
|
-
readFile(path.join(PACKAGE_DIR, "
|
|
361
|
-
readFile(path.join(PACKAGE_DIR, "
|
|
378
|
+
readFile(path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "placement.js"), "utf8"),
|
|
379
|
+
readFile(path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "placementTopology.js"), "utf8"),
|
|
380
|
+
readFile(path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "error.js"), "utf8")
|
|
362
381
|
]);
|
|
363
382
|
|
|
364
383
|
assert.deepEqual(
|
|
@@ -389,30 +408,10 @@ test("shell-web packageMetadata pre-optimizes package subpaths reached only thro
|
|
|
389
408
|
]);
|
|
390
409
|
});
|
|
391
410
|
|
|
392
|
-
test("shell-web
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
"shell-web-page-home-settings-shell",
|
|
397
|
-
"shell-web-page-home-settings",
|
|
398
|
-
"shell-web-page-home-settings-general"
|
|
399
|
-
];
|
|
400
|
-
for (const mutationId of homePageMutationIds) {
|
|
401
|
-
assert.deepEqual(findFileMutation(mutationId)?.when, {
|
|
402
|
-
config: "surfaceDefinitions.home.enabled",
|
|
403
|
-
equals: "true"
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
assert.deepEqual(readClientContainerTokens(), [
|
|
408
|
-
"runtime.web-placement.client",
|
|
409
|
-
"runtime.web-bootstrap.client",
|
|
410
|
-
"runtime.web-refresh.client",
|
|
411
|
-
"runtime.web-async-module-recovery.client",
|
|
412
|
-
"runtime.web-request-recovery.client",
|
|
413
|
-
"runtime.web-error.client",
|
|
414
|
-
"runtime.web-error.presentation-store.client"
|
|
415
|
-
]);
|
|
411
|
+
test("shell-web metadata advertises adaptive shell outlets and pattern-backed links", () => {
|
|
412
|
+
assert.equal(packageMetadata?.mutations, undefined);
|
|
413
|
+
assert.equal(Object.hasOwn(packageMetadata?.metadata?.apiSummary || {}, "containerTokens"), false);
|
|
414
|
+
assert.deepEqual(packageMetadata?.capabilities?.provides, ["client.shell"]);
|
|
416
415
|
|
|
417
416
|
assert.deepEqual(
|
|
418
417
|
readOutlets("shell-layout:primary-bottom-nav"),
|
|
@@ -453,7 +452,7 @@ test("shell-web packageMetadata metadata advertises adaptive shell outlets, defa
|
|
|
453
452
|
{
|
|
454
453
|
target: "home-settings:primary-menu",
|
|
455
454
|
surfaces: ["home"],
|
|
456
|
-
source: "
|
|
455
|
+
source: "patterns/application-shell/example/src/pages/home/settings.vue"
|
|
457
456
|
}
|
|
458
457
|
]
|
|
459
458
|
);
|
|
@@ -467,7 +466,7 @@ test("shell-web packageMetadata metadata advertises adaptive shell outlets, defa
|
|
|
467
466
|
kind: "link",
|
|
468
467
|
surfaces: ["home"],
|
|
469
468
|
order: 50,
|
|
470
|
-
source: "
|
|
469
|
+
source: "patterns/application-shell/example/src/placement.js"
|
|
471
470
|
},
|
|
472
471
|
{
|
|
473
472
|
id: "shell-web.home.menu.settings",
|
|
@@ -475,7 +474,7 @@ test("shell-web packageMetadata metadata advertises adaptive shell outlets, defa
|
|
|
475
474
|
kind: "link",
|
|
476
475
|
surfaces: ["home"],
|
|
477
476
|
order: 100,
|
|
478
|
-
source: "
|
|
477
|
+
source: "patterns/application-shell/example/src/placement.js"
|
|
479
478
|
}
|
|
480
479
|
]
|
|
481
480
|
);
|
|
@@ -490,7 +489,7 @@ test("shell-web packageMetadata metadata advertises adaptive shell outlets, defa
|
|
|
490
489
|
kind: "link",
|
|
491
490
|
surfaces: ["home"],
|
|
492
491
|
order: 100,
|
|
493
|
-
source: "
|
|
492
|
+
source: "patterns/application-shell/example/src/placement.js"
|
|
494
493
|
}
|
|
495
494
|
]
|
|
496
495
|
);
|
|
@@ -519,67 +518,17 @@ test("shell-web packageMetadata metadata advertises adaptive shell outlets, defa
|
|
|
519
518
|
"shell-layout:supporting-side-panel"
|
|
520
519
|
);
|
|
521
520
|
|
|
522
|
-
assert.deepEqual(findFileMutation("shell-web-page-home-settings-shell"), {
|
|
523
|
-
from: "templates/src/pages/home/settings.vue",
|
|
524
|
-
toSurface: "home",
|
|
525
|
-
toSurfacePath: "settings.vue",
|
|
526
|
-
ownership: "app",
|
|
527
|
-
reason: "Install shell-driven home settings shell route with section navigation.",
|
|
528
|
-
category: "shell-web",
|
|
529
|
-
id: "shell-web-page-home-settings-shell",
|
|
530
|
-
when: {
|
|
531
|
-
config: "surfaceDefinitions.home.enabled",
|
|
532
|
-
equals: "true"
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
assert.deepEqual(findFileMutation("shell-web-page-home-settings"), {
|
|
537
|
-
from: "templates/src/pages/home/settings/index.vue",
|
|
538
|
-
toSurface: "home",
|
|
539
|
-
toSurfacePath: "settings/index.vue",
|
|
540
|
-
ownership: "app",
|
|
541
|
-
reason: "Install shell-driven home settings redirect so the starter settings shell lands on a real child page.",
|
|
542
|
-
category: "shell-web",
|
|
543
|
-
id: "shell-web-page-home-settings",
|
|
544
|
-
when: {
|
|
545
|
-
config: "surfaceDefinitions.home.enabled",
|
|
546
|
-
equals: "true"
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
assert.deepEqual(findFileMutation("shell-web-page-home-settings-general"), {
|
|
551
|
-
from: "templates/src/pages/home/settings/general/index.vue",
|
|
552
|
-
toSurface: "home",
|
|
553
|
-
toSurfacePath: "settings/general/index.vue",
|
|
554
|
-
ownership: "app",
|
|
555
|
-
reason: "Install shell-driven general settings child page with a tiny browser-local shell preference example.",
|
|
556
|
-
category: "shell-web",
|
|
557
|
-
id: "shell-web-page-home-settings-general",
|
|
558
|
-
when: {
|
|
559
|
-
config: "surfaceDefinitions.home.enabled",
|
|
560
|
-
equals: "true"
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
assert.deepEqual(findFileMutation("shell-web-test-adaptive-shell-smoke"), {
|
|
565
|
-
from: "templates/tests/e2e/adaptive-shell.spec.ts",
|
|
566
|
-
to: "tests/e2e/adaptive-shell.spec.ts",
|
|
567
|
-
ownership: "app",
|
|
568
|
-
reason: "Install compact/medium/expanded Playwright smoke coverage for the adaptive shell.",
|
|
569
|
-
category: "shell-web",
|
|
570
|
-
id: "shell-web-test-adaptive-shell-smoke"
|
|
571
|
-
});
|
|
572
521
|
});
|
|
573
522
|
|
|
574
|
-
test("shell-web home
|
|
575
|
-
const source = await readFile(
|
|
523
|
+
test("shell-web pattern home page relies on adaptive navigation instead of dead feature buttons", async () => {
|
|
524
|
+
const source = await readFile(
|
|
525
|
+
path.join(PACKAGE_DIR, "patterns", "application-shell", "example", "src", "pages", "home", "index.vue"),
|
|
526
|
+
"utf8"
|
|
527
|
+
);
|
|
576
528
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
});
|
|
581
|
-
assert.match(source, /generated-ui-screen generated-ui-screen--app home-surface-screen/);
|
|
582
|
-
assert.match(source, /--generated-ui-screen-title-size/);
|
|
529
|
+
assert.match(source, /class="home-surface-screen d-flex flex-column ga-4"/);
|
|
530
|
+
assert.match(source, /--home-surface-title-size/);
|
|
531
|
+
assert.doesNotMatch(source, /generated-ui/u);
|
|
583
532
|
assert.match(source, /Core services are available\./);
|
|
584
533
|
assert.match(source, /to="\/home\/settings\/general"/);
|
|
585
534
|
assert.doesNotMatch(source, /Use bottom navigation|Replace this content|Main public surface/);
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
const PACKAGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
6
|
-
|
|
7
|
-
function createLocalLinkItemDefinition({
|
|
8
|
-
token = "",
|
|
9
|
-
componentFile = "",
|
|
10
|
-
componentName = "",
|
|
11
|
-
templateFile = ""
|
|
12
|
-
} = {}) {
|
|
13
|
-
return Object.freeze({
|
|
14
|
-
token: String(token || "").trim(),
|
|
15
|
-
componentFile: String(componentFile || "").trim(),
|
|
16
|
-
componentName: String(componentName || "").trim(),
|
|
17
|
-
templateFile: String(templateFile || "").trim()
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const LOCAL_LINK_ITEM_COMPONENT_DEFINITIONS = Object.freeze([
|
|
22
|
-
createLocalLinkItemDefinition({
|
|
23
|
-
token: "local.main.ui.menu-link-item",
|
|
24
|
-
componentFile: "src/components/menus/MenuLinkItem.vue",
|
|
25
|
-
componentName: "MenuLinkItem",
|
|
26
|
-
templateFile: "templates/src/components/menus/MenuLinkItem.vue"
|
|
27
|
-
}),
|
|
28
|
-
createLocalLinkItemDefinition({
|
|
29
|
-
token: "local.main.ui.surface-aware-menu-link-item",
|
|
30
|
-
componentFile: "src/components/menus/SurfaceAwareMenuLinkItem.vue",
|
|
31
|
-
componentName: "SurfaceAwareMenuLinkItem",
|
|
32
|
-
templateFile: "templates/src/components/menus/SurfaceAwareMenuLinkItem.vue"
|
|
33
|
-
}),
|
|
34
|
-
createLocalLinkItemDefinition({
|
|
35
|
-
token: "local.main.ui.tab-link-item",
|
|
36
|
-
componentFile: "src/components/menus/TabLinkItem.vue",
|
|
37
|
-
componentName: "TabLinkItem",
|
|
38
|
-
templateFile: "templates/src/components/menus/TabLinkItem.vue"
|
|
39
|
-
})
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
const LOCAL_LINK_ITEM_COMPONENT_TOKENS = Object.freeze(
|
|
43
|
-
LOCAL_LINK_ITEM_COMPONENT_DEFINITIONS.map((entry) => entry.token)
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
function findLocalLinkItemDefinition(componentToken = "") {
|
|
47
|
-
const normalizedComponentToken = String(componentToken || "").trim();
|
|
48
|
-
return LOCAL_LINK_ITEM_COMPONENT_DEFINITIONS.find((entry) => entry.token === normalizedComponentToken) || null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function resolveLocalLinkItemDefinition(componentTokenOrDefinition = "") {
|
|
52
|
-
if (
|
|
53
|
-
componentTokenOrDefinition &&
|
|
54
|
-
typeof componentTokenOrDefinition === "object" &&
|
|
55
|
-
!Array.isArray(componentTokenOrDefinition)
|
|
56
|
-
) {
|
|
57
|
-
return componentTokenOrDefinition;
|
|
58
|
-
}
|
|
59
|
-
return findLocalLinkItemDefinition(componentTokenOrDefinition);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function resolveLocalLinkItemTemplateAbsolutePath(componentTokenOrDefinition = "") {
|
|
63
|
-
const definition = resolveLocalLinkItemDefinition(componentTokenOrDefinition);
|
|
64
|
-
if (!definition) {
|
|
65
|
-
throw new Error(`Unknown local link-item scaffold: ${String(componentTokenOrDefinition || "").trim() || "(empty)"}.`);
|
|
66
|
-
}
|
|
67
|
-
return path.join(PACKAGE_DIR, definition.templateFile);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function readLocalLinkItemComponentSource(componentTokenOrDefinition = "") {
|
|
71
|
-
return await readFile(resolveLocalLinkItemTemplateAbsolutePath(componentTokenOrDefinition), "utf8");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export {
|
|
75
|
-
LOCAL_LINK_ITEM_COMPONENT_DEFINITIONS,
|
|
76
|
-
LOCAL_LINK_ITEM_COMPONENT_TOKENS,
|
|
77
|
-
findLocalLinkItemDefinition,
|
|
78
|
-
readLocalLinkItemComponentSource,
|
|
79
|
-
resolveLocalLinkItemTemplateAbsolutePath
|
|
80
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import test from "node:test";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import packageJson from "../package.json" with { type: "json" };
|
|
7
|
-
|
|
8
|
-
const packageMetadata = packageJson.jskit;
|
|
9
|
-
|
|
10
|
-
const TEST_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
const PACKAGE_DIR = path.resolve(TEST_DIRECTORY, "..");
|
|
12
|
-
const CREATE_APP_TEMPLATE_DIR = path.resolve(PACKAGE_DIR, "..", "..", "tooling", "create-app", "templates", "minimal-shell");
|
|
13
|
-
|
|
14
|
-
function findFileMutation(id) {
|
|
15
|
-
const files = packageMetadata?.mutations?.files;
|
|
16
|
-
return Array.isArray(files)
|
|
17
|
-
? files.find((entry) => String(entry?.id || "").trim() === id) || null
|
|
18
|
-
: null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
test("shell-web claims starter shell files as app-owned scaffolds", () => {
|
|
22
|
-
assert.deepEqual(findFileMutation("shell-web-app-root"), {
|
|
23
|
-
from: "templates/src/App.vue",
|
|
24
|
-
to: "src/App.vue",
|
|
25
|
-
ownership: "app",
|
|
26
|
-
expectedExistingFrom: "templates/expected-existing/src/App.vue",
|
|
27
|
-
reason: "Install full-width shell app root with shell-web error host and edge-to-edge layout.",
|
|
28
|
-
category: "shell-web",
|
|
29
|
-
id: "shell-web-app-root"
|
|
30
|
-
});
|
|
31
|
-
assert.deepEqual(findFileMutation("shell-web-page-home-wrapper"), {
|
|
32
|
-
from: "templates/src/pages/home.vue",
|
|
33
|
-
toSurface: "home",
|
|
34
|
-
toSurfaceRoot: true,
|
|
35
|
-
ownership: "app",
|
|
36
|
-
expectedExistingFrom: "templates/expected-existing/src/pages/home.vue",
|
|
37
|
-
reason: "Install shell-driven home wrapper page.",
|
|
38
|
-
category: "shell-web",
|
|
39
|
-
id: "shell-web-page-home-wrapper",
|
|
40
|
-
when: {
|
|
41
|
-
config: "surfaceDefinitions.home.enabled",
|
|
42
|
-
equals: "true"
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
assert.deepEqual(findFileMutation("shell-web-page-home"), {
|
|
46
|
-
from: "templates/src/pages/home/index.vue",
|
|
47
|
-
toSurface: "home",
|
|
48
|
-
toSurfacePath: "index.vue",
|
|
49
|
-
ownership: "app",
|
|
50
|
-
expectedExistingFrom: "templates/expected-existing/src/pages/home/index.vue",
|
|
51
|
-
reason: "Install shell-driven home surface starter page.",
|
|
52
|
-
category: "shell-web",
|
|
53
|
-
id: "shell-web-page-home",
|
|
54
|
-
when: {
|
|
55
|
-
config: "surfaceDefinitions.home.enabled",
|
|
56
|
-
equals: "true"
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("shell-web expected-existing starter files stay aligned with create-app minimal-shell", async () => {
|
|
62
|
-
const comparedFiles = [
|
|
63
|
-
"src/App.vue",
|
|
64
|
-
"src/pages/home.vue",
|
|
65
|
-
"src/pages/home/index.vue"
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
for (const relativeFile of comparedFiles) {
|
|
69
|
-
const shellWebExpectedSource = await readFile(
|
|
70
|
-
path.join(PACKAGE_DIR, "templates", "expected-existing", relativeFile),
|
|
71
|
-
"utf8"
|
|
72
|
-
);
|
|
73
|
-
const createAppSource = await readFile(path.join(CREATE_APP_TEMPLATE_DIR, relativeFile), "utf8");
|
|
74
|
-
assert.equal(shellWebExpectedSource, createAppSource, relativeFile);
|
|
75
|
-
}
|
|
76
|
-
});
|