@shipfox/client-shell 0.2.0
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/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/dist/components/main-layout.d.ts +11 -0
- package/dist/components/main-layout.d.ts.map +1 -0
- package/dist/components/main-layout.js +39 -0
- package/dist/components/main-layout.js.map +1 -0
- package/dist/components/nav-bar.d.ts +4 -0
- package/dist/components/nav-bar.d.ts.map +1 -0
- package/dist/components/nav-bar.js +62 -0
- package/dist/components/nav-bar.js.map +1 -0
- package/dist/components/nav-tabs.d.ts +6 -0
- package/dist/components/nav-tabs.d.ts.map +1 -0
- package/dist/components/nav-tabs.js +38 -0
- package/dist/components/nav-tabs.js.map +1 -0
- package/dist/components/not-found-page.d.ts +2 -0
- package/dist/components/not-found-page.d.ts.map +1 -0
- package/dist/components/not-found-page.js +25 -0
- package/dist/components/not-found-page.js.map +1 -0
- package/dist/components/settings-nav.d.ts +5 -0
- package/dist/components/settings-nav.d.ts.map +1 -0
- package/dist/components/settings-nav.js +45 -0
- package/dist/components/settings-nav.js.map +1 -0
- package/dist/components/user-menu.d.ts +2 -0
- package/dist/components/user-menu.d.ts.map +1 -0
- package/dist/components/user-menu.js +76 -0
- package/dist/components/user-menu.js.map +1 -0
- package/dist/components/workspace-crumb.d.ts +7 -0
- package/dist/components/workspace-crumb.d.ts.map +1 -0
- package/dist/components/workspace-crumb.js +54 -0
- package/dist/components/workspace-crumb.js.map +1 -0
- package/dist/components/workspace-switcher.d.ts +5 -0
- package/dist/components/workspace-switcher.d.ts.map +1 -0
- package/dist/components/workspace-switcher.js +90 -0
- package/dist/components/workspace-switcher.js.map +1 -0
- package/dist/compose/compose-routes.d.ts +6 -0
- package/dist/compose/compose-routes.d.ts.map +1 -0
- package/dist/compose/compose-routes.js +53 -0
- package/dist/compose/compose-routes.js.map +1 -0
- package/dist/compose/errors.d.ts +26 -0
- package/dist/compose/errors.d.ts.map +1 -0
- package/dist/compose/errors.js +39 -0
- package/dist/compose/errors.js.map +1 -0
- package/dist/compose/merge-config.d.ts +4 -0
- package/dist/compose/merge-config.d.ts.map +1 -0
- package/dist/compose/merge-config.js +28 -0
- package/dist/compose/merge-config.js.map +1 -0
- package/dist/compose/normalize-route-path.d.ts +2 -0
- package/dist/compose/normalize-route-path.d.ts.map +1 -0
- package/dist/compose/normalize-route-path.js +7 -0
- package/dist/compose/normalize-route-path.js.map +1 -0
- package/dist/compose/validate-providers.d.ts +3 -0
- package/dist/compose/validate-providers.d.ts.map +1 -0
- package/dist/compose/validate-providers.js +32 -0
- package/dist/compose/validate-providers.js.map +1 -0
- package/dist/compose/validate-registries.d.ts +4 -0
- package/dist/compose/validate-registries.d.ts.map +1 -0
- package/dist/compose/validate-registries.js +50 -0
- package/dist/compose/validate-registries.js.map +1 -0
- package/dist/config/shell-config.d.ts +10 -0
- package/dist/config/shell-config.d.ts.map +1 -0
- package/dist/config/shell-config.js +12 -0
- package/dist/config/shell-config.js.map +1 -0
- package/dist/contract.d.ts +39 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +5 -0
- package/dist/contract.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/active-workspace.d.ts +4 -0
- package/dist/runtime/active-workspace.d.ts.map +1 -0
- package/dist/runtime/active-workspace.js +15 -0
- package/dist/runtime/active-workspace.js.map +1 -0
- package/dist/runtime/anchor-paths.d.ts +9 -0
- package/dist/runtime/anchor-paths.d.ts.map +1 -0
- package/dist/runtime/anchor-paths.js +18 -0
- package/dist/runtime/anchor-paths.js.map +1 -0
- package/dist/runtime/anchors.d.ts +19 -0
- package/dist/runtime/anchors.d.ts.map +1 -0
- package/dist/runtime/anchors.js +125 -0
- package/dist/runtime/anchors.js.map +1 -0
- package/dist/runtime/assemble-route-tree.d.ts +10 -0
- package/dist/runtime/assemble-route-tree.d.ts.map +1 -0
- package/dist/runtime/assemble-route-tree.js +30 -0
- package/dist/runtime/assemble-route-tree.js.map +1 -0
- package/dist/runtime/auth.d.ts +50 -0
- package/dist/runtime/auth.d.ts.map +1 -0
- package/dist/runtime/auth.js +194 -0
- package/dist/runtime/auth.js.map +1 -0
- package/dist/runtime/chrome-context.d.ts +10 -0
- package/dist/runtime/chrome-context.d.ts.map +1 -0
- package/dist/runtime/chrome-context.js +16 -0
- package/dist/runtime/chrome-context.js.map +1 -0
- package/dist/runtime/compose-client-app.d.ts +13 -0
- package/dist/runtime/compose-client-app.d.ts.map +1 -0
- package/dist/runtime/compose-client-app.js +93 -0
- package/dist/runtime/compose-client-app.js.map +1 -0
- package/dist/runtime/define-route.d.ts +19 -0
- package/dist/runtime/define-route.d.ts.map +1 -0
- package/dist/runtime/define-route.js +12 -0
- package/dist/runtime/define-route.js.map +1 -0
- package/dist/runtime/index.d.ts +20 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +21 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/last-workspace.d.ts +4 -0
- package/dist/runtime/last-workspace.d.ts.map +1 -0
- package/dist/runtime/last-workspace.js +20 -0
- package/dist/runtime/last-workspace.js.map +1 -0
- package/dist/runtime/nav-order.d.ts +7 -0
- package/dist/runtime/nav-order.d.ts.map +1 -0
- package/dist/runtime/nav-order.js +8 -0
- package/dist/runtime/nav-order.js.map +1 -0
- package/dist/runtime/provider-stack.d.ts +14 -0
- package/dist/runtime/provider-stack.d.ts.map +1 -0
- package/dist/runtime/provider-stack.js +28 -0
- package/dist/runtime/provider-stack.js.map +1 -0
- package/dist/runtime/registries.d.ts +4 -0
- package/dist/runtime/registries.d.ts.map +1 -0
- package/dist/runtime/registries.js +23 -0
- package/dist/runtime/registries.js.map +1 -0
- package/dist/runtime/router-context.d.ts +9 -0
- package/dist/runtime/router-context.d.ts.map +1 -0
- package/dist/runtime/router-context.js +3 -0
- package/dist/runtime/router-context.js.map +1 -0
- package/dist/runtime/workspace-setup.d.ts +18 -0
- package/dist/runtime/workspace-setup.d.ts.map +1 -0
- package/dist/runtime/workspace-setup.js +64 -0
- package/dist/runtime/workspace-setup.js.map +1 -0
- package/dist/testing/index.d.ts +17 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +35 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/dist/vite/evaluate-features.d.ts +8 -0
- package/dist/vite/evaluate-features.d.ts.map +1 -0
- package/dist/vite/evaluate-features.js +80 -0
- package/dist/vite/evaluate-features.js.map +1 -0
- package/dist/vite/generate.d.ts +9 -0
- package/dist/vite/generate.d.ts.map +1 -0
- package/dist/vite/generate.js +80 -0
- package/dist/vite/generate.js.map +1 -0
- package/dist/vite/index.d.ts +2 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +3 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/plugin.d.ts +7 -0
- package/dist/vite/plugin.d.ts.map +1 -0
- package/dist/vite/plugin.js +77 -0
- package/dist/vite/plugin.js.map +1 -0
- package/package.json +113 -0
- package/src/components/main-layout.tsx +45 -0
- package/src/components/nav-bar.tsx +41 -0
- package/src/components/nav-tabs.test.tsx +60 -0
- package/src/components/nav-tabs.tsx +47 -0
- package/src/components/not-found-page.tsx +14 -0
- package/src/components/settings-nav.tsx +35 -0
- package/src/components/user-menu.tsx +59 -0
- package/src/components/workspace-crumb.tsx +43 -0
- package/src/components/workspace-switcher.tsx +75 -0
- package/src/compose/compose-routes.test.ts +112 -0
- package/src/compose/compose-routes.ts +60 -0
- package/src/compose/errors.ts +54 -0
- package/src/compose/merge-config.test.ts +26 -0
- package/src/compose/merge-config.ts +27 -0
- package/src/compose/normalize-route-path.ts +6 -0
- package/src/compose/validate-providers.test.ts +31 -0
- package/src/compose/validate-providers.ts +36 -0
- package/src/compose/validate-registries.test.ts +92 -0
- package/src/compose/validate-registries.ts +61 -0
- package/src/config/config-screen.test.tsx +37 -0
- package/src/config/shell-config.ts +10 -0
- package/src/contract.ts +47 -0
- package/src/index.ts +1 -0
- package/src/runtime/active-workspace.ts +13 -0
- package/src/runtime/anchor-paths.ts +18 -0
- package/src/runtime/anchors.tsx +106 -0
- package/src/runtime/assemble-route-tree.ts +42 -0
- package/src/runtime/auth.tsx +213 -0
- package/src/runtime/chrome-context.tsx +22 -0
- package/src/runtime/compose-client-app.tsx +122 -0
- package/src/runtime/define-route.test.ts +15 -0
- package/src/runtime/define-route.ts +33 -0
- package/src/runtime/index.ts +19 -0
- package/src/runtime/last-workspace.ts +22 -0
- package/src/runtime/nav-order.ts +1 -0
- package/src/runtime/provider-stack.tsx +39 -0
- package/src/runtime/providers.test.tsx +51 -0
- package/src/runtime/registries.test.tsx +100 -0
- package/src/runtime/registries.ts +42 -0
- package/src/runtime/router-context.ts +9 -0
- package/src/runtime/routes.test.tsx +48 -0
- package/src/runtime/workspace-setup.tsx +61 -0
- package/src/testing/index.test.tsx +57 -0
- package/src/testing/index.tsx +51 -0
- package/src/vite/evaluate-features.test.ts +34 -0
- package/src/vite/evaluate-features.ts +93 -0
- package/src/vite/generate.test.ts +22 -0
- package/src/vite/generate.ts +99 -0
- package/src/vite/generated-router.test.tsx +58 -0
- package/src/vite/index.ts +1 -0
- package/src/vite/plugin.test.ts +181 -0
- package/src/vite/plugin.ts +114 -0
- package/src/vite/validate.test.ts +166 -0
- package/test/default-route-impl.tsx +3 -0
- package/test/external/FINDINGS.md +53 -0
- package/test/external/README.md +39 -0
- package/test/external/fixture/index.html +12 -0
- package/test/external/fixture/package.json +32 -0
- package/test/external/fixture/src/app.fixture.tsx +72 -0
- package/test/external/fixture/src/features/override-impl.tsx +12 -0
- package/test/external/fixture/src/features/override.tsx +20 -0
- package/test/external/fixture/src/features.collision.ts +15 -0
- package/test/external/fixture/src/features.ts +4 -0
- package/test/external/fixture/src/link-typecheck.tsx +10 -0
- package/test/external/fixture/src/main.tsx +4 -0
- package/test/external/fixture/tsconfig.json +15 -0
- package/test/external/fixture/vite.config.ts +10 -0
- package/test/external/fixture/vitest.config.ts +15 -0
- package/test/external/toy-feature/CHANGELOG.md +15 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-biome-check +43 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-biome-format +43 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-biome-lint +43 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-swc +43 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-tsc-check +43 -0
- package/test/external/toy-feature/node_modules/.bin/shipfox-tsc-emit +43 -0
- package/test/external/toy-feature/package.json +57 -0
- package/test/external/toy-feature/src/config.ts +5 -0
- package/test/external/toy-feature/src/index.ts +64 -0
- package/test/external/toy-feature/src/provider.tsx +33 -0
- package/test/external/toy-feature/src/routes/insights.tsx +7 -0
- package/test/external/toy-feature/src/routes/settings.tsx +7 -0
- package/test/external/toy-feature/tsconfig.build.json +5 -0
- package/test/external/toy-feature/tsconfig.json +1 -0
- package/test/external/verify.mjs +318 -0
- package/test/fixtures/features.ts +56 -0
- package/test/named-route-impl.tsx +3 -0
- package/test/not-route-impl.ts +1 -0
- package/test/render.tsx +67 -0
- package/test/search-route-impl.tsx +7 -0
- package/test/setup.ts +3 -0
- package/test/typecheck/shipfox-app.gen.ts +85 -0
- package/test/typecheck/types.tsx +18 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +1 -0
- package/tsconfig.test.json +12 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {composeRoutes} from '#compose/compose-routes.js';
|
|
3
|
+
import {mergeConfigShapes} from '#compose/merge-config.js';
|
|
4
|
+
import {validateProviderIds} from '#compose/validate-providers.js';
|
|
5
|
+
import {validateNavigation, validateSettingsSections} from '#compose/validate-registries.js';
|
|
6
|
+
import {defineClientFeature} from '#contract.js';
|
|
7
|
+
|
|
8
|
+
const route = {path: '/projects', parent: 'root' as const, impl: '#test/default-route-impl.js'};
|
|
9
|
+
|
|
10
|
+
describe('composition validation', () => {
|
|
11
|
+
test('accepts non-conflicting feature contributions', () => {
|
|
12
|
+
const features = [
|
|
13
|
+
defineClientFeature({
|
|
14
|
+
id: 'acme.projects',
|
|
15
|
+
routes: [
|
|
16
|
+
route,
|
|
17
|
+
{
|
|
18
|
+
path: '/workspaces/$wid/settings/members',
|
|
19
|
+
parent: 'workspaceSettings',
|
|
20
|
+
impl: '#test/default-route-impl.js',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
providers: [{id: 'acme-theme', Component: () => null}],
|
|
24
|
+
navigation: [{id: 'projects', scope: 'workspace', label: 'Projects', to: '/projects'}],
|
|
25
|
+
settingsSections: [
|
|
26
|
+
{id: 'members', pathSegment: 'members', label: 'Members', icon: 'users'},
|
|
27
|
+
],
|
|
28
|
+
configShape: {projectId: z.string()},
|
|
29
|
+
}),
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const routes = composeRoutes(features);
|
|
33
|
+
|
|
34
|
+
expect(() => validateProviderIds(features)).not.toThrow();
|
|
35
|
+
expect(() =>
|
|
36
|
+
validateNavigation(
|
|
37
|
+
features,
|
|
38
|
+
routes.map(({path}) => path),
|
|
39
|
+
),
|
|
40
|
+
).not.toThrow();
|
|
41
|
+
expect(() =>
|
|
42
|
+
validateSettingsSections(
|
|
43
|
+
features,
|
|
44
|
+
routes.map(({path}) => path),
|
|
45
|
+
),
|
|
46
|
+
).not.toThrow();
|
|
47
|
+
expect(() => mergeConfigShapes(features)).not.toThrow();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('reports route collisions with both feature ids', () => {
|
|
51
|
+
const features = [
|
|
52
|
+
defineClientFeature({id: 'shipfox.projects', routes: [route]}),
|
|
53
|
+
defineClientFeature({id: 'acme.projects', routes: [route]}),
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
expect(() => composeRoutes(features)).toThrow(
|
|
57
|
+
'Route "/projects" is contributed by both features "shipfox.projects" and "acme.projects". Set override: true to replace it explicitly.',
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('reports dangling and competing overrides with their feature ids', () => {
|
|
62
|
+
const dangling = [
|
|
63
|
+
defineClientFeature({id: 'acme.projects', routes: [{...route, override: true}]}),
|
|
64
|
+
];
|
|
65
|
+
const competing = [
|
|
66
|
+
defineClientFeature({id: 'shipfox.projects', routes: [route]}),
|
|
67
|
+
defineClientFeature({id: 'acme.one', routes: [{...route, override: true}]}),
|
|
68
|
+
defineClientFeature({id: 'acme.two', routes: [{...route, override: true}]}),
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
expect(() => composeRoutes(dangling)).toThrow(
|
|
72
|
+
'Route override for "/projects" from feature "acme.projects" has no route to replace.',
|
|
73
|
+
);
|
|
74
|
+
expect(() => composeRoutes(competing)).toThrow(
|
|
75
|
+
'Route "/projects" has competing overrides from features "acme.one" and "acme.two".',
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('reports reserved and duplicate provider ids', () => {
|
|
80
|
+
const reserved = [
|
|
81
|
+
defineClientFeature({id: 'acme.theme', providers: [{id: 'theme', Component: () => null}]}),
|
|
82
|
+
];
|
|
83
|
+
const duplicate = [
|
|
84
|
+
defineClientFeature({id: 'acme.one', providers: [{id: 'flags', Component: () => null}]}),
|
|
85
|
+
defineClientFeature({id: 'acme.two', providers: [{id: 'flags', Component: () => null}]}),
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
expect(() => validateProviderIds(reserved)).toThrow(
|
|
89
|
+
'Provider id "theme" in feature "acme.theme" is reserved by the shell.',
|
|
90
|
+
);
|
|
91
|
+
expect(() => validateProviderIds(duplicate)).toThrow(
|
|
92
|
+
'Provider id "flags" is contributed by both features "acme.one" and "acme.two".',
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('reports duplicate and missing navigation entries', () => {
|
|
97
|
+
const duplicate = [
|
|
98
|
+
defineClientFeature({
|
|
99
|
+
id: 'acme.one',
|
|
100
|
+
navigation: [{id: 'projects', scope: 'workspace', label: 'Projects', to: '/projects'}],
|
|
101
|
+
}),
|
|
102
|
+
defineClientFeature({
|
|
103
|
+
id: 'acme.two',
|
|
104
|
+
navigation: [{id: 'projects', scope: 'workspace', label: 'Projects', to: '/projects'}],
|
|
105
|
+
}),
|
|
106
|
+
];
|
|
107
|
+
const missing = [
|
|
108
|
+
defineClientFeature({
|
|
109
|
+
id: 'acme.insights',
|
|
110
|
+
navigation: [{id: 'insights', scope: 'workspace', label: 'Insights', to: '/insights'}],
|
|
111
|
+
}),
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
expect(() => validateNavigation(duplicate, ['/projects'])).toThrow(
|
|
115
|
+
'Navigation entry "projects" is contributed by both features "acme.one" and "acme.two".',
|
|
116
|
+
);
|
|
117
|
+
expect(() => validateNavigation(missing, [])).toThrow(
|
|
118
|
+
'Navigation entry "insights" in feature "acme.insights" targets missing route "/insights".',
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('reports duplicate and missing settings sections', () => {
|
|
123
|
+
const duplicate = [
|
|
124
|
+
defineClientFeature({
|
|
125
|
+
id: 'acme.one',
|
|
126
|
+
settingsSections: [
|
|
127
|
+
{id: 'members', pathSegment: 'members', label: 'Members', icon: 'users'},
|
|
128
|
+
],
|
|
129
|
+
}),
|
|
130
|
+
defineClientFeature({
|
|
131
|
+
id: 'acme.two',
|
|
132
|
+
settingsSections: [
|
|
133
|
+
{id: 'members', pathSegment: 'members', label: 'Members', icon: 'users'},
|
|
134
|
+
],
|
|
135
|
+
}),
|
|
136
|
+
];
|
|
137
|
+
const missing = [
|
|
138
|
+
defineClientFeature({
|
|
139
|
+
id: 'acme.insights',
|
|
140
|
+
settingsSections: [
|
|
141
|
+
{id: 'insights', pathSegment: 'insights', label: 'Insights', icon: 'chart-line'},
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
expect(() =>
|
|
147
|
+
validateSettingsSections(duplicate, ['/workspaces/$wid/settings/members']),
|
|
148
|
+
).toThrow(
|
|
149
|
+
'Settings section "members" is contributed by both features "acme.one" and "acme.two".',
|
|
150
|
+
);
|
|
151
|
+
expect(() => validateSettingsSections(missing, [])).toThrow(
|
|
152
|
+
'Settings section "insights" in feature "acme.insights" requires route "/workspaces/$wid/settings/insights".',
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('reports duplicate config keys', () => {
|
|
157
|
+
const features = [
|
|
158
|
+
defineClientFeature({id: 'acme.one', configShape: {token: z.string()}}),
|
|
159
|
+
defineClientFeature({id: 'acme.two', configShape: {token: z.string()}}),
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
expect(() => mergeConfigShapes(features)).toThrow(
|
|
163
|
+
'Config key "token" is contributed by both features "acme.one" and "acme.two". Reuse the same schema instance to intentionally share it.',
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# External composition findings
|
|
2
|
+
|
|
3
|
+
Both the linked iteration mode and packed-tarball exit gate passed on 2026-07-16. The verifier
|
|
4
|
+
computed and installed a 12-package `@shipfox/*` runtime closure.
|
|
5
|
+
|
|
6
|
+
## Declaration portability
|
|
7
|
+
|
|
8
|
+
The packed consumer's `tsc --noEmit` accepted a typed `Link` and `useSearch` for the added
|
|
9
|
+
`/workspaces/$wid/insights` route. The generated router also resolved the toy package's emitted
|
|
10
|
+
default `defineRoute(...)` declarations and the shell's anchor return types from `dist`.
|
|
11
|
+
|
|
12
|
+
The packed verifier also checks that every installed `#*` import map defaults to `./dist/*` and
|
|
13
|
+
that representative shell and toy-feature public entrypoints resolve beneath `dist`. This keeps the
|
|
14
|
+
proof valid even while the tarballs still include source files.
|
|
15
|
+
|
|
16
|
+
The proof exposed two package-boundary gaps before it passed:
|
|
17
|
+
|
|
18
|
+
- Compiled client packages still mapped internal `#*` imports directly to `src`. Their package
|
|
19
|
+
manifests now use `workspace-source` and `development` for source, and `default` for `dist`.
|
|
20
|
+
- The inferred anchor declarations name `@tanstack/router-core`. The shell now declares that direct
|
|
21
|
+
dependency so isolated pnpm consumers can resolve it.
|
|
22
|
+
|
|
23
|
+
The fixture did not need `@storybook/react` at runtime or during its consumer type-check. The
|
|
24
|
+
`ShellProviders` declaration's type-only Storybook import is erased at runtime; the fixture uses the
|
|
25
|
+
same `skipLibCheck` setting as the existing external-consumer verifier.
|
|
26
|
+
|
|
27
|
+
## Development-mode coverage
|
|
28
|
+
|
|
29
|
+
The gate intentionally proves production builds and default package resolution; it does not start a
|
|
30
|
+
Vite development server. The `development` condition still resolves to the TypeScript source that
|
|
31
|
+
the packages currently ship. Plugin watch and regeneration behavior remains covered by ENG-961's
|
|
32
|
+
focused tests. If published packages stop including source, external development-mode support needs
|
|
33
|
+
a separate product decision and proof rather than making this release gate longer.
|
|
34
|
+
|
|
35
|
+
## Generated-file developer experience
|
|
36
|
+
|
|
37
|
+
The generated file keeps both forms of route implementation specifier readable:
|
|
38
|
+
|
|
39
|
+
- App-local implementations use a path relative to `src/shipfox-app.gen.ts`, such as
|
|
40
|
+
`./features/override-impl`.
|
|
41
|
+
- Packaged implementations use an exported package subpath, such as
|
|
42
|
+
`@shipfox/client-shell-fixture-feature/routes/insights`.
|
|
43
|
+
|
|
44
|
+
The app's Node-evaluated feature manifest imports local TypeScript modules without a `.js` suffix so
|
|
45
|
+
jiti resolves the source file. Route implementation modules are never evaluated by jiti.
|
|
46
|
+
|
|
47
|
+
## Collision diagnostic
|
|
48
|
+
|
|
49
|
+
The rejected build returned this diagnostic and a non-zero status:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
Route "/workspaces/$wid/insights" is contributed by both features "fixture.toy-feature" and "fixture.unapproved-collision". Set override: true to replace it explicitly.
|
|
53
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# External client runtime fixture
|
|
2
|
+
|
|
3
|
+
This fixture packs the published client runtime closure into a Vite application outside the pnpm
|
|
4
|
+
workspace. It is a manual structural gate and does not add a CI job.
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
Build runtime files, declarations, and the closure helper before running either mode:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
turbo build type:emit \
|
|
12
|
+
--filter='./libs/client/**' \
|
|
13
|
+
--filter=@shipfox/application-release
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Run the fast linked mode
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
node libs/client/shell/test/external/verify.mjs --link
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This copies the Vite template to a temporary directory and links the workspace-built closure. It
|
|
23
|
+
runs a Vite build and resolves every non-pattern declaration entry point from the consumer.
|
|
24
|
+
|
|
25
|
+
## Run the packed exit gate
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
node libs/client/shell/test/external/verify.mjs
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This computes the runtime workspace closure from the client roots in
|
|
32
|
+
`publication-closure.json`, packs every package, and installs only those tarballs for
|
|
33
|
+
`@shipfox/*` dependencies. It repeats the linked checks against default `dist` exports and
|
|
34
|
+
verifies no candidate package came from the workspace or registry.
|
|
35
|
+
|
|
36
|
+
Both modes remove their temporary directories after completion. The behavioral composition fixture
|
|
37
|
+
and required CI gate are part of ENG-995; neither mode needs browser E2E infrastructure or adds
|
|
38
|
+
work to the normal CI test graph. Its source files and Vitest wiring remain in the fixture template
|
|
39
|
+
for that follow-up.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Shipfox client composition fixture</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shipfox-client-shell-external-fixture",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"type": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tanstack/react-query": "5.101.0",
|
|
13
|
+
"@tanstack/react-router": "1.170.16",
|
|
14
|
+
"@tanstack/router-core": "1.171.13",
|
|
15
|
+
"jotai": "2.20.1",
|
|
16
|
+
"react": "19.2.7",
|
|
17
|
+
"react-dom": "19.2.7",
|
|
18
|
+
"zod": "4.4.3"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
22
|
+
"@testing-library/react": "16.3.2",
|
|
23
|
+
"@types/node": "24.13.2",
|
|
24
|
+
"@types/react": "19.2.17",
|
|
25
|
+
"@types/react-dom": "19.2.3",
|
|
26
|
+
"@vitejs/plugin-react": "6.0.2",
|
|
27
|
+
"jsdom": "29.1.1",
|
|
28
|
+
"typescript": "6.0.3",
|
|
29
|
+
"vite": "8.0.16",
|
|
30
|
+
"vitest": "4.1.9"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import {getLoadedConfig} from '@shipfox/client-config';
|
|
3
|
+
import type {ProviderProbeEntry} from '@shipfox/client-shell-fixture-feature';
|
|
4
|
+
import {QueryClient} from '@tanstack/react-query';
|
|
5
|
+
import {createMemoryHistory} from '@tanstack/react-router';
|
|
6
|
+
import {act, render, screen, waitFor} from '@testing-library/react';
|
|
7
|
+
import {createClientAppElement} from './main.js';
|
|
8
|
+
import {router} from './shipfox-app.gen.js';
|
|
9
|
+
|
|
10
|
+
test('proves the external composition contract', async () => {
|
|
11
|
+
window.matchMedia = vi.fn((query: string) => ({
|
|
12
|
+
matches: false,
|
|
13
|
+
media: query,
|
|
14
|
+
onchange: null,
|
|
15
|
+
addListener: vi.fn(),
|
|
16
|
+
removeListener: vi.fn(),
|
|
17
|
+
addEventListener: vi.fn(),
|
|
18
|
+
removeEventListener: vi.fn(),
|
|
19
|
+
dispatchEvent: vi.fn(() => false),
|
|
20
|
+
}));
|
|
21
|
+
window.scrollTo = vi.fn();
|
|
22
|
+
window.__SHIPFOX_CONFIG__ = undefined;
|
|
23
|
+
const missingConfig = render(createClientAppElement(), {reactStrictMode: true});
|
|
24
|
+
|
|
25
|
+
expect(await screen.findByRole('heading', {name: 'Configuration error'})).toBeVisible();
|
|
26
|
+
expect(screen.getByText('fixtureGreeting')).toBeVisible();
|
|
27
|
+
missingConfig.unmount();
|
|
28
|
+
|
|
29
|
+
window.__SHIPFOX_CONFIG__ = {FIXTURE_GREETING: 'Hello from the fixture'};
|
|
30
|
+
let providers: readonly ProviderProbeEntry[] = [];
|
|
31
|
+
router.update({
|
|
32
|
+
history: createMemoryHistory({initialEntries: ['/workspaces/workspace/insights']}),
|
|
33
|
+
});
|
|
34
|
+
render(
|
|
35
|
+
createClientAppElement({
|
|
36
|
+
onProviders: (entries) => {
|
|
37
|
+
providers = entries;
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
{reactStrictMode: true},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(await screen.findByRole('heading', {name: 'Overridden insights'})).toBeVisible();
|
|
44
|
+
expect(screen.queryByRole('heading', {name: 'Toy insights'})).not.toBeInTheDocument();
|
|
45
|
+
expect(screen.getAllByRole('tab').map((tab) => tab.textContent)).toEqual([
|
|
46
|
+
'Insights first',
|
|
47
|
+
'Insights second',
|
|
48
|
+
]);
|
|
49
|
+
await waitFor(() => expect(providers.map(({id}) => id)).toEqual(['toy-feature', 'app-feature']));
|
|
50
|
+
const queryClients = providers.map(({queryClient}) => queryClient);
|
|
51
|
+
expect(queryClients).toHaveLength(2);
|
|
52
|
+
expect(queryClients[0]).toBeInstanceOf(QueryClient);
|
|
53
|
+
expect(queryClients[1]).toBe(queryClients[0]);
|
|
54
|
+
expect(getLoadedConfig<{fixtureGreeting: string}>().fixtureGreeting).toBe(
|
|
55
|
+
'Hello from the fixture',
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
await act(() =>
|
|
59
|
+
router.navigate({
|
|
60
|
+
to: '/workspaces/$wid/settings/primary',
|
|
61
|
+
params: {wid: 'workspace'},
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
expect(await screen.findByRole('heading', {name: 'Toy settings'})).toBeVisible();
|
|
66
|
+
expect(
|
|
67
|
+
Array.from(
|
|
68
|
+
screen.getByRole('navigation', {name: 'Workspace settings'}).querySelectorAll('a'),
|
|
69
|
+
(link) => link.textContent,
|
|
70
|
+
),
|
|
71
|
+
).toEqual(['Primary settings', 'Secondary settings']);
|
|
72
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {defineRoute} from '@shipfox/client-shell/runtime';
|
|
2
|
+
|
|
3
|
+
function OverriddenInsights() {
|
|
4
|
+
return <h1>Overridden insights</h1>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default defineRoute({
|
|
8
|
+
component: OverriddenInsights,
|
|
9
|
+
validateSearch: (search: Record<string, unknown>) => ({
|
|
10
|
+
view: search.view === 'compact' ? ('compact' as const) : ('full' as const),
|
|
11
|
+
}),
|
|
12
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {defineClientFeature} from '@shipfox/client-shell';
|
|
2
|
+
import {ProviderProbe} from '@shipfox/client-shell-fixture-feature';
|
|
3
|
+
import {createElement, type PropsWithChildren} from 'react';
|
|
4
|
+
|
|
5
|
+
function AppFeatureProvider({children}: PropsWithChildren) {
|
|
6
|
+
return createElement(ProviderProbe, {id: 'app-feature'}, children);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const overrideFeature = defineClientFeature({
|
|
10
|
+
id: 'fixture.app-override',
|
|
11
|
+
routes: [
|
|
12
|
+
{
|
|
13
|
+
path: '/workspaces/$wid/insights',
|
|
14
|
+
parent: 'workspaceLayout',
|
|
15
|
+
override: true,
|
|
16
|
+
impl: './features/override-impl',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
providers: [{id: 'fixture-app-provider', Component: AppFeatureProvider}],
|
|
20
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {defineClientFeature} from '@shipfox/client-shell';
|
|
2
|
+
import {toyFeature} from '@shipfox/client-shell-fixture-feature';
|
|
3
|
+
|
|
4
|
+
const collisionFeature = defineClientFeature({
|
|
5
|
+
id: 'fixture.unapproved-collision',
|
|
6
|
+
routes: [
|
|
7
|
+
{
|
|
8
|
+
path: '/workspaces/$wid/insights',
|
|
9
|
+
parent: 'workspaceLayout',
|
|
10
|
+
impl: './features/override-impl',
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const features = [toyFeature, collisionFeature];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {Link, useSearch} from '@tanstack/react-router';
|
|
2
|
+
|
|
3
|
+
export function InsightsLink() {
|
|
4
|
+
const search = useSearch({from: '/workspaces/$wid/insights'});
|
|
5
|
+
return (
|
|
6
|
+
<Link to="/workspaces/$wid/insights" params={{wid: 'workspace'}} search={{view: search.view}}>
|
|
7
|
+
Insights
|
|
8
|
+
</Link>
|
|
9
|
+
);
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"strict": true,
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"types": ["node", "vite/client", "vitest/globals"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/main.tsx", "types.ts", "vite.config.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
import {defineConfig} from 'vite';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
build: {chunkSizeWarningLimit: 4_000},
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
resolve: {
|
|
8
|
+
dedupe: ['react', 'react-dom', '@tanstack/react-query', '@tanstack/react-router', 'jotai'],
|
|
9
|
+
},
|
|
10
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
import {defineConfig} from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
resolve: {
|
|
7
|
+
dedupe: ['react', 'react-dom', '@tanstack/react-query', '@tanstack/react-router', 'jotai'],
|
|
8
|
+
},
|
|
9
|
+
test: {
|
|
10
|
+
environment: 'jsdom',
|
|
11
|
+
globals: true,
|
|
12
|
+
include: ['src/app.fixture.tsx'],
|
|
13
|
+
server: {deps: {inline: true}},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @shipfox/client-shell-fixture-feature
|
|
2
|
+
|
|
3
|
+
## 0.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [3d064b8]
|
|
8
|
+
- Updated dependencies [6bc2e45]
|
|
9
|
+
- @shipfox/client-shell@0.2.0
|
|
10
|
+
|
|
11
|
+
## 0.0.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- @shipfox/client-shell@0.0.2
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
basedir_win="$basedir"
|
|
4
|
+
exe=""
|
|
5
|
+
msys=""
|
|
6
|
+
|
|
7
|
+
case `uname -a` in
|
|
8
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
9
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
10
|
+
basedir_win=`cygpath -w "$basedir"`
|
|
11
|
+
fi
|
|
12
|
+
exe=".exe"
|
|
13
|
+
msys="true"
|
|
14
|
+
;;
|
|
15
|
+
*WSL2*)
|
|
16
|
+
if command -v wslpath > /dev/null 2>&1; then
|
|
17
|
+
basedir_win="$(wslpath -w "$basedir" 2> /dev/null)"
|
|
18
|
+
if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then
|
|
19
|
+
basedir_win="$basedir"
|
|
20
|
+
else
|
|
21
|
+
exe=".exe"
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
if [ -z "$NODE_PATH" ]; then
|
|
28
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules"
|
|
29
|
+
else
|
|
30
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
31
|
+
fi
|
|
32
|
+
if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then
|
|
33
|
+
exec "$basedir/node.exe" "$basedir_win/../@shipfox/biome/bin/biome-check.js" "$@"
|
|
34
|
+
elif [ -x "$basedir/node" ]; then
|
|
35
|
+
exec "$basedir/node" "$basedir/../@shipfox/biome/bin/biome-check.js" "$@"
|
|
36
|
+
elif command -v node >/dev/null 2>&1; then
|
|
37
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-check.js" "$@"
|
|
38
|
+
elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then
|
|
39
|
+
exec node.exe "$basedir_win/../@shipfox/biome/bin/biome-check.js" "$@"
|
|
40
|
+
else
|
|
41
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-check.js" "$@"
|
|
42
|
+
fi
|
|
43
|
+
# cmd-shim-target=/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/libs/client/shell/test/external/toy-feature/node_modules/@shipfox/biome/bin/biome-check.js
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
basedir_win="$basedir"
|
|
4
|
+
exe=""
|
|
5
|
+
msys=""
|
|
6
|
+
|
|
7
|
+
case `uname -a` in
|
|
8
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
9
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
10
|
+
basedir_win=`cygpath -w "$basedir"`
|
|
11
|
+
fi
|
|
12
|
+
exe=".exe"
|
|
13
|
+
msys="true"
|
|
14
|
+
;;
|
|
15
|
+
*WSL2*)
|
|
16
|
+
if command -v wslpath > /dev/null 2>&1; then
|
|
17
|
+
basedir_win="$(wslpath -w "$basedir" 2> /dev/null)"
|
|
18
|
+
if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then
|
|
19
|
+
basedir_win="$basedir"
|
|
20
|
+
else
|
|
21
|
+
exe=".exe"
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
if [ -z "$NODE_PATH" ]; then
|
|
28
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules"
|
|
29
|
+
else
|
|
30
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
31
|
+
fi
|
|
32
|
+
if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then
|
|
33
|
+
exec "$basedir/node.exe" "$basedir_win/../@shipfox/biome/bin/biome-format.js" "$@"
|
|
34
|
+
elif [ -x "$basedir/node" ]; then
|
|
35
|
+
exec "$basedir/node" "$basedir/../@shipfox/biome/bin/biome-format.js" "$@"
|
|
36
|
+
elif command -v node >/dev/null 2>&1; then
|
|
37
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-format.js" "$@"
|
|
38
|
+
elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then
|
|
39
|
+
exec node.exe "$basedir_win/../@shipfox/biome/bin/biome-format.js" "$@"
|
|
40
|
+
else
|
|
41
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-format.js" "$@"
|
|
42
|
+
fi
|
|
43
|
+
# cmd-shim-target=/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/libs/client/shell/test/external/toy-feature/node_modules/@shipfox/biome/bin/biome-format.js
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
basedir_win="$basedir"
|
|
4
|
+
exe=""
|
|
5
|
+
msys=""
|
|
6
|
+
|
|
7
|
+
case `uname -a` in
|
|
8
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
9
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
10
|
+
basedir_win=`cygpath -w "$basedir"`
|
|
11
|
+
fi
|
|
12
|
+
exe=".exe"
|
|
13
|
+
msys="true"
|
|
14
|
+
;;
|
|
15
|
+
*WSL2*)
|
|
16
|
+
if command -v wslpath > /dev/null 2>&1; then
|
|
17
|
+
basedir_win="$(wslpath -w "$basedir" 2> /dev/null)"
|
|
18
|
+
if [ $? -ne 0 ] || [ -z "$basedir_win" ]; then
|
|
19
|
+
basedir_win="$basedir"
|
|
20
|
+
else
|
|
21
|
+
exe=".exe"
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
if [ -z "$NODE_PATH" ]; then
|
|
28
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules"
|
|
29
|
+
else
|
|
30
|
+
export NODE_PATH="/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
31
|
+
fi
|
|
32
|
+
if [ -n "$exe" ] && [ -x "$basedir/node.exe" ]; then
|
|
33
|
+
exec "$basedir/node.exe" "$basedir_win/../@shipfox/biome/bin/biome-lint.js" "$@"
|
|
34
|
+
elif [ -x "$basedir/node" ]; then
|
|
35
|
+
exec "$basedir/node" "$basedir/../@shipfox/biome/bin/biome-lint.js" "$@"
|
|
36
|
+
elif command -v node >/dev/null 2>&1; then
|
|
37
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-lint.js" "$@"
|
|
38
|
+
elif [ -n "$exe" ] && command -v node.exe >/dev/null 2>&1; then
|
|
39
|
+
exec node.exe "$basedir_win/../@shipfox/biome/bin/biome-lint.js" "$@"
|
|
40
|
+
else
|
|
41
|
+
exec node "$basedir/../@shipfox/biome/bin/biome-lint.js" "$@"
|
|
42
|
+
fi
|
|
43
|
+
# cmd-shim-target=/Users/noe.charmet/conductor/workspaces/platform-v1/singapore/libs/client/shell/test/external/toy-feature/node_modules/@shipfox/biome/bin/biome-lint.js
|