@james_sww/metaform-asset-distribution 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/codebase/codebase.json +13 -11
- package/codebase/template/.env.example +11 -1
- package/codebase/template/.metaform/template-overrides.json +24 -0
- package/codebase/template/index.html +1 -1
- package/codebase/template/src/components/common/empty-state.tsx +52 -0
- package/codebase/template/src/components/common/error-boundary.tsx +2 -2
- package/codebase/template/src/components/ui/alert.tsx +48 -50
- package/codebase/template/src/hooks/index.ts +2 -2
- package/codebase/template/src/integrations/platform.ts +65 -1
- package/codebase/template/src/layouts/role-workspace-shell.tsx +136 -48
- package/codebase/template/src/lib/http-client.ts +1 -1
- package/codebase/template/src/main.tsx +11 -1
- package/codebase/template/src/workspace/default-workspace.tsx +1 -1
- package/dist/application-source.d.ts +5 -3
- package/dist/application-source.js +43 -32
- package/dist/cli.js +1 -1
- package/dist/contracts.d.ts +6 -1
- package/dist/contracts.js +1 -1
- package/dist/export-source.js +3 -3
- package/dist/prepare.d.ts +1 -1
- package/dist/prepare.js +41 -25
- package/dist/source-map.d.ts +2 -1
- package/dist/source-map.js +10 -8
- package/dist/template.d.ts +1 -1
- package/dist/template.js +1 -1
- package/package.json +2 -2
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/catalog.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/common-semantic-region-scaffold.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/components-business-role-tasks-icons.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/components-business-role-tasks-types.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/components-common-semantic-region-contract.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/layouts-role-workspace-account.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/layouts-role-workspace-icons.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/layouts-role-workspace-routes.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/layouts-role-workspace-types.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/lib-utils.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/quality-role-task-groups.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/quality-role-task-overview.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/role-workspace-shell.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/styles-styles.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/styles-theme-tokens.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-avatar.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-badge.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-button.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-collapsible.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-dropdown-menu.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-empty.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-sheet.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-skeleton.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/r/ui-tooltip.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/registry.json +1 -0
- package/registry/47e2405d581daf6aa5433b033351b639e11f9730d174a0563b88e36bc06402f9/release.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/catalog.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/common-semantic-region-scaffold.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/components-business-role-tasks-icons.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/components-business-role-tasks-types.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/components-common-semantic-region-contract.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/layouts-role-workspace-account.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/layouts-role-workspace-icons.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/layouts-role-workspace-routes.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/layouts-role-workspace-types.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/lib-utils.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/quality-role-task-groups.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/quality-role-task-overview.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/role-workspace-shell.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/styles-styles.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/styles-theme-tokens.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-avatar.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-badge.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-button.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-collapsible.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-dropdown-menu.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-empty.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-sheet.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-skeleton.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/r/ui-tooltip.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/registry.json +1 -0
- package/registry/5bce235170d2de6e2c3b0cfe10d0596dd53189c83acb8d3e4256b11606d95a22/release.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/catalog.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/common-semantic-region-scaffold.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/components-business-role-tasks-icons.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/components-business-role-tasks-types.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/components-common-semantic-region-contract.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/lib-utils.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/quality-role-task-groups.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/quality-role-task-overview.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/styles-styles.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/styles-theme-tokens.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/ui-badge.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/ui-button.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/ui-collapsible.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/r/ui-empty.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/registry.json +1 -0
- package/registry/ac851c907cc97669042b64a5d30d9bec2017d07e43c8cd933db399f446c5bb86/release.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/catalog.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/common-semantic-region-scaffold.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/components-business-role-tasks-icons.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/components-business-role-tasks-types.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/components-common-semantic-region-contract.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/lib-utils.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/quality-role-task-groups.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/quality-role-task-overview.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/styles-styles.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/styles-theme-tokens.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/ui-badge.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/ui-button.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/ui-collapsible.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/r/ui-empty.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/registry.json +1 -0
- package/registry/f5db0c88ee95ccef50d6ced1f08e935c8c56006e337b978e332f0974b18d79b2/release.json +1 -0
- package/registry/release.json +1 -1
|
@@ -228,7 +228,7 @@ export class HttpClient {
|
|
|
228
228
|
|
|
229
229
|
// 创建默认实例
|
|
230
230
|
export const httpClient = new HttpClient({
|
|
231
|
-
baseURL: import.meta.env
|
|
231
|
+
baseURL: (import.meta as { env?: { VITE_API_BASE_URL?: string } }).env?.VITE_API_BASE_URL || '/api',
|
|
232
232
|
onRequest: async (config) => {
|
|
233
233
|
// 自动添加认证 token
|
|
234
234
|
const token = localStorage.getItem('auth_token');
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { createRoot } from "react-dom/client";
|
|
2
|
+
import { Toaster } from "sonner";
|
|
2
3
|
|
|
4
|
+
import { ErrorBoundary } from "./components/common/error-boundary";
|
|
5
|
+
import { ToastProvider } from "./contexts/toast-context";
|
|
3
6
|
import { DefaultWorkspace } from "./workspace/default-workspace";
|
|
4
7
|
import "./styles/index.css";
|
|
5
8
|
|
|
6
|
-
createRoot(document.getElementById("root")!).render(
|
|
9
|
+
createRoot(document.getElementById("root")!).render(
|
|
10
|
+
<ErrorBoundary>
|
|
11
|
+
<ToastProvider>
|
|
12
|
+
<DefaultWorkspace />
|
|
13
|
+
<Toaster position="top-right" richColors closeButton />
|
|
14
|
+
</ToastProvider>
|
|
15
|
+
</ErrorBoundary>,
|
|
16
|
+
);
|
|
@@ -23,7 +23,7 @@ export function DefaultWorkspace() {
|
|
|
23
23
|
}}
|
|
24
24
|
slots={{
|
|
25
25
|
content: (
|
|
26
|
-
<div className="mx-auto w-full max-w-6xl space-y-6
|
|
26
|
+
<div className="mx-auto w-full max-w-6xl space-y-6">
|
|
27
27
|
<h1 className="text-xl font-semibold text-foreground">
|
|
28
28
|
{contract.title}
|
|
29
29
|
</h1>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import type { ApplicationDesign } from
|
|
2
|
-
import { type RegistryRelease } from
|
|
3
|
-
export declare function generateApplicationFiles(design: ApplicationDesign, release: RegistryRelease
|
|
1
|
+
import type { ApplicationDesign } from "./application-design.js";
|
|
2
|
+
import { type RegistryRelease } from "./contracts.js";
|
|
3
|
+
export declare function generateApplicationFiles(design: ApplicationDesign, release: RegistryRelease, options?: {
|
|
4
|
+
accent?: string;
|
|
5
|
+
}): Record<string, string>;
|
|
@@ -1,64 +1,75 @@
|
|
|
1
|
-
import { posix } from
|
|
2
|
-
import { DistributionError } from
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { DistributionError } from "./contracts.js";
|
|
3
3
|
const literal = (value) => JSON.stringify(value, null, 2)
|
|
4
|
-
.replaceAll(
|
|
5
|
-
.replaceAll(
|
|
6
|
-
.replaceAll(
|
|
4
|
+
.replaceAll("<", "\\u003c")
|
|
5
|
+
.replaceAll("\u2028", "\\u2028")
|
|
6
|
+
.replaceAll("\u2029", "\\u2029");
|
|
7
7
|
function modulePath(from, to) {
|
|
8
|
-
let p = posix.relative(posix.dirname(from), to).replace(/\.tsx?$/,
|
|
9
|
-
if (!p.startsWith(
|
|
10
|
-
p =
|
|
8
|
+
let p = posix.relative(posix.dirname(from), to).replace(/\.tsx?$/, "");
|
|
9
|
+
if (!p.startsWith("."))
|
|
10
|
+
p = "./" + p;
|
|
11
11
|
return JSON.stringify(p);
|
|
12
12
|
}
|
|
13
|
-
function propsSource(value, events, path =
|
|
13
|
+
function propsSource(value, events, path = "") {
|
|
14
14
|
if (events.has(path))
|
|
15
15
|
return `(...args: unknown[]) => onAction(${literal(events.get(path))}, args[0])`;
|
|
16
16
|
if (Array.isArray(value))
|
|
17
|
-
return (
|
|
18
|
-
value
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
return ("[" +
|
|
18
|
+
value
|
|
19
|
+
.map((x, i) => propsSource(x, events, path ? path + "." + i : String(i)))
|
|
20
|
+
.join(",") +
|
|
21
|
+
"]");
|
|
22
|
+
if (value && typeof value === "object") {
|
|
21
23
|
const keys = new Set(Object.keys(value));
|
|
22
24
|
for (const eventPath of events.keys())
|
|
23
|
-
if (!path || eventPath.startsWith(path +
|
|
24
|
-
keys.add(eventPath.slice(path ? path.length + 1 : 0).split(
|
|
25
|
-
return (
|
|
25
|
+
if (!path || eventPath.startsWith(path + "."))
|
|
26
|
+
keys.add(eventPath.slice(path ? path.length + 1 : 0).split(".")[0]);
|
|
27
|
+
return ("{" +
|
|
26
28
|
[...keys]
|
|
27
|
-
.map((k) => `${literal(k)}:${propsSource(Object.hasOwn(value, k) ? value[k] : {}, events, path ? path +
|
|
28
|
-
.join(
|
|
29
|
-
|
|
29
|
+
.map((k) => `${literal(k)}:${propsSource(Object.hasOwn(value, k) ? value[k] : {}, events, path ? path + "." + k : k)}`)
|
|
30
|
+
.join(",") +
|
|
31
|
+
"}");
|
|
30
32
|
}
|
|
31
33
|
return literal(value);
|
|
32
34
|
}
|
|
33
|
-
export function generateApplicationFiles(design, release) {
|
|
35
|
+
export function generateApplicationFiles(design, release, options = {}) {
|
|
34
36
|
const files = {};
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
+
const accent = options.accent && /^[a-z][a-z0-9-]*$/.test(options.accent)
|
|
38
|
+
? ` data-accent="${options.accent}"`
|
|
39
|
+
: "";
|
|
40
|
+
const scaffold = "src/components/common/semantic-region/semantic-region-scaffold.tsx";
|
|
41
|
+
const types = "src/components/common/semantic-region/contract.ts";
|
|
37
42
|
const targets = [];
|
|
38
43
|
for (const role of design.roles) {
|
|
39
44
|
const pages = design.pages.filter((p) => p.roleKey === role.roleKey);
|
|
40
45
|
const regions = design.regions.filter((r) => pages.some((p) => p.id === r.contract.pageId));
|
|
41
46
|
const root = `src/features/${role.roleKey}`;
|
|
42
47
|
const entry = `${role.roleKey}/index.html`;
|
|
43
|
-
targets.push({
|
|
48
|
+
targets.push({
|
|
49
|
+
roleKey: role.roleKey,
|
|
50
|
+
entry,
|
|
51
|
+
path: `/${role.roleKey}/`,
|
|
52
|
+
featuresRoot: root,
|
|
53
|
+
});
|
|
44
54
|
files[entry] =
|
|
45
|
-
`<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${design.name.replace(/[<>&"']/g,
|
|
55
|
+
`<!doctype html><html lang="zh-CN"${accent}><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${design.name.replace(/[<>&"']/g, "")}</title></head><body><div id="root"></div><script type="module" src="/${root}/main.tsx"></script></body></html>\n`;
|
|
46
56
|
for (const r of regions) {
|
|
47
57
|
const componentPath = `${root}/regions/${r.contract.id}.tsx`;
|
|
48
58
|
const contractPath = `${root}/regions/${r.contract.id}.contract.ts`;
|
|
49
59
|
files[contractPath] =
|
|
50
60
|
`import type { SemanticRegionContract } from ${modulePath(contractPath, types)};\nexport const contract: SemanticRegionContract = ${literal(r.contract)};\n`;
|
|
51
61
|
const common = `import { contract } from './${r.contract.id}.contract';\nexport { contract };\nexport interface RegionProps { onAction(id: string, context?: unknown): void; context?: unknown }\n`;
|
|
52
|
-
if (r.implementation.kind ===
|
|
62
|
+
if (r.implementation.kind === "scaffold") {
|
|
53
63
|
files[componentPath] =
|
|
54
64
|
`import { SemanticRegionScaffold } from ${modulePath(componentPath, scaffold)};\n${common}export function Region({ onAction }: RegionProps) { return <SemanticRegionScaffold contract={contract} commands={{ onAction: (action) => onAction(action.id) }} />; }\n`;
|
|
55
65
|
}
|
|
56
66
|
else {
|
|
57
67
|
const impl = r.implementation;
|
|
58
68
|
const item = release.items.find((a) => a.assetId === impl.asset.id && a.version === impl.asset.version);
|
|
59
|
-
const source = item.files.find((f) => f.sourcePath === item.contractRef) ??
|
|
69
|
+
const source = item.files.find((f) => f.sourcePath === item.contractRef) ??
|
|
70
|
+
item.files[0];
|
|
60
71
|
if (!source)
|
|
61
|
-
throw new DistributionError(
|
|
72
|
+
throw new DistributionError("asset_entry_missing", [item.assetId]);
|
|
62
73
|
files[componentPath] =
|
|
63
74
|
`import { ${impl.exportName} } from ${modulePath(componentPath, source.targetPath)};\n${common}export function Region({ onAction }: RegionProps) { return <section data-region-id={contract.id} data-region-implementation="asset"><${impl.exportName} {...${propsSource(impl.props, new Map(impl.events.map((e) => [e.propPath, e.actionId])))}} /></section>; }\n`;
|
|
64
75
|
}
|
|
@@ -70,11 +81,11 @@ export function generateApplicationFiles(design, release) {
|
|
|
70
81
|
import { RoleWorkspaceShell } from '../../layouts/role-workspace-shell';
|
|
71
82
|
import { SemanticRegionScaffold } from '../../components/common/semantic-region/semantic-region-scaffold';
|
|
72
83
|
import { activeWorkspaceRoute, resolveWorkspacePage, workspaceRouteContract, type WorkspaceRouteMap } from '../../workspace/routes';
|
|
73
|
-
${regions.map((r, i) => `import { Region as Region${i}, contract as contract${i} } from './regions/${r.contract.id}';`).join(
|
|
84
|
+
${regions.map((r, i) => `import { Region as Region${i}, contract as contract${i} } from './regions/${r.contract.id}';`).join("\n")}
|
|
74
85
|
const pages = ${literal(pages)};
|
|
75
86
|
const workspaceRoutes: WorkspaceRouteMap = ${literal(role.workspaceRoutes ?? {})};
|
|
76
87
|
const mappedPages = new Set(Object.values(workspaceRoutes));
|
|
77
|
-
const regions = { ${regions.map((r, i) => `${literal(r.contract.id)}: { View: Region${i}, contract: contract${i} }`).join(
|
|
88
|
+
const regions = { ${regions.map((r, i) => `${literal(r.contract.id)}: { View: Region${i}, contract: contract${i} }`).join(",")} };
|
|
78
89
|
export function Workspace() {
|
|
79
90
|
const [state, setState] = useState<{pageId:string; contexts:Record<string,unknown>}>({pageId:${literal(role.entryPageId)},contexts:{}});
|
|
80
91
|
const [feedback, setFeedback] = useState('');
|
|
@@ -97,10 +108,10 @@ export function Workspace() {
|
|
|
97
108
|
}
|
|
98
109
|
return <RoleWorkspaceShell model={{productName:${literal(design.name)},workspaceTitle:${literal(role.label)},actorLabel:'未连接登录服务',roleLabel:${literal(role.label)},themes:pages.filter((p) => p.menu !== false && !mappedPages.has(p.id)).map((p) => ({id:p.id,label:p.title,availability:'implemented' as const})),activeThemeId:page ? activeWorkspaceRoute(page.id,workspaceRoutes) : state.pageId}}
|
|
99
110
|
commands={{onSelectTheme:selectPage}}
|
|
100
|
-
slots={{content:<div className="mx-auto w-full max-w-6xl space-y-6
|
|
111
|
+
slots={{content:<div className="mx-auto w-full max-w-6xl space-y-6"><header className="space-y-2"><p className="text-sm text-muted-foreground">应用设计底稿 · 真实业务数据尚未接入</p><h1 className="text-2xl font-semibold text-foreground">{page?.title ?? placeholder?.title ?? '待确认页面'}</h1></header>{feedback ? <p role="status" className="text-sm text-muted-foreground">{feedback}</p> : null}{page ? page.regionIds.map((id) => {const View = regions[id as keyof typeof regions].View; return <View key={id} context={state.contexts[page.id]} onAction={(actionId,context) => onAction(id,actionId,context)} />;}) : placeholder ? <SemanticRegionScaffold contract={placeholder} /> : <p>页面映射待确认</p>}</div>}} />;
|
|
101
112
|
}\n`;
|
|
102
113
|
}
|
|
103
|
-
files[
|
|
104
|
-
files[
|
|
114
|
+
files["role-targets.json"] = literal(targets) + "\n";
|
|
115
|
+
files["docs/application-design.json"] = literal(design) + "\n";
|
|
105
116
|
return files;
|
|
106
117
|
}
|
package/dist/cli.js
CHANGED
|
@@ -96,7 +96,7 @@ export async function runCLI(argv, io) {
|
|
|
96
96
|
else if (cmd === 'init')
|
|
97
97
|
output = await initProject({
|
|
98
98
|
projectRoot: root,
|
|
99
|
-
templateVersion: options.get('template')
|
|
99
|
+
templateVersion: options.get('template'),
|
|
100
100
|
codebaseRoot: options.get('codebase'),
|
|
101
101
|
});
|
|
102
102
|
else if (cmd === 'reconcile')
|
package/dist/contracts.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type SourceFile = {
|
|
|
14
14
|
contentBase64: string;
|
|
15
15
|
sha256: string;
|
|
16
16
|
bytes: number;
|
|
17
|
-
kind:
|
|
17
|
+
kind: "source" | "style" | "resource" | "license";
|
|
18
18
|
};
|
|
19
19
|
export type SourceItem = {
|
|
20
20
|
assetId: string;
|
|
@@ -35,6 +35,11 @@ export type RegistryRelease = {
|
|
|
35
35
|
id: string;
|
|
36
36
|
version: string;
|
|
37
37
|
sourceCommit: string;
|
|
38
|
+
sourceBaseline?: {
|
|
39
|
+
sourcesDigest: string;
|
|
40
|
+
contentDigest: string;
|
|
41
|
+
dirty?: boolean;
|
|
42
|
+
};
|
|
38
43
|
digest: string;
|
|
39
44
|
items: SourceItem[];
|
|
40
45
|
catalog?: CatalogSnapshot;
|
package/dist/contracts.js
CHANGED
|
@@ -2,7 +2,7 @@ export class DistributionError extends Error {
|
|
|
2
2
|
code;
|
|
3
3
|
paths;
|
|
4
4
|
constructor(code, paths = []) {
|
|
5
|
-
super(code + (paths.length ?
|
|
5
|
+
super(code + (paths.length ? ": " + paths.join(", ") : ""));
|
|
6
6
|
this.code = code;
|
|
7
7
|
this.paths = paths;
|
|
8
8
|
}
|
package/dist/export-source.js
CHANGED
|
@@ -111,7 +111,7 @@ export async function exportAssets(input) {
|
|
|
111
111
|
const imports = new Map(), dependencies = new Set();
|
|
112
112
|
function classify(specifier) {
|
|
113
113
|
if (specifier.startsWith('@metaform/design-system/'))
|
|
114
|
-
return ('
|
|
114
|
+
return ('vendor/design-system/src/' +
|
|
115
115
|
specifier.slice('@metaform/design-system/'.length));
|
|
116
116
|
if (specifier.startsWith('.'))
|
|
117
117
|
return posix.normalize(posix.join(posix.dirname(source), specifier));
|
|
@@ -165,7 +165,7 @@ export async function exportAssets(input) {
|
|
|
165
165
|
else
|
|
166
166
|
text = rewriteModule(text, source, (s) => imports.get(s) ?? s);
|
|
167
167
|
if (SEEDS[id]) {
|
|
168
|
-
const style = await collect('
|
|
168
|
+
const style = await collect('vendor/design-system/src/styles.css');
|
|
169
169
|
dependencies.add(style);
|
|
170
170
|
let cssImport = posix.relative(posix.dirname(target), 'src/styles/styles.css');
|
|
171
171
|
if (!cssImport.startsWith('.'))
|
|
@@ -183,6 +183,6 @@ export async function exportAssets(input) {
|
|
|
183
183
|
throw new DistributionError('asset_version', [ref.id]);
|
|
184
184
|
await collect(SEEDS[ref.id].source);
|
|
185
185
|
}
|
|
186
|
-
await collect('
|
|
186
|
+
await collect('vendor/design-system/src/styles.css');
|
|
187
187
|
return [...items.values()].sort((a, b) => a.assetId.localeCompare(b.assetId));
|
|
188
188
|
}
|
package/dist/prepare.d.ts
CHANGED
package/dist/prepare.js
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
import { readFile } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { validateApplicationDesign } from
|
|
4
|
-
import { generateApplicationFiles } from
|
|
5
|
-
import { planAdd } from
|
|
6
|
-
import { projectFiles } from
|
|
7
|
-
import { canonical, sha256, sourceFile, validateTargetPath } from
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { validateApplicationDesign } from "./application-design.js";
|
|
4
|
+
import { generateApplicationFiles } from "./application-source.js";
|
|
5
|
+
import { planAdd } from "./planner.js";
|
|
6
|
+
import { projectFiles } from "./provenance.js";
|
|
7
|
+
import { canonical, sha256, sourceFile, validateTargetPath, } from "./validate.js";
|
|
8
8
|
export async function planPrepare(input) {
|
|
9
9
|
const { projectRoot: root, release } = input;
|
|
10
10
|
const design = validateApplicationDesign(input.design, release);
|
|
11
|
-
const scaffold = release.items.find((a) => a.assetId ===
|
|
11
|
+
const scaffold = release.items.find((a) => a.assetId === "common.semantic-region-scaffold");
|
|
12
12
|
const refs = new Map();
|
|
13
|
-
refs.set(
|
|
14
|
-
id:
|
|
15
|
-
version: scaffold?.version ??
|
|
13
|
+
refs.set("common.semantic-region-scaffold", {
|
|
14
|
+
id: "common.semantic-region-scaffold",
|
|
15
|
+
version: scaffold?.version ?? "",
|
|
16
16
|
});
|
|
17
17
|
for (const r of design.regions)
|
|
18
|
-
if (r.implementation.kind ===
|
|
18
|
+
if (r.implementation.kind === "asset")
|
|
19
19
|
refs.set(r.implementation.asset.id, r.implementation.asset);
|
|
20
|
-
const plan = await planAdd({
|
|
20
|
+
const plan = await planAdd({
|
|
21
|
+
projectRoot: root,
|
|
22
|
+
release,
|
|
23
|
+
assets: [...refs.values()],
|
|
24
|
+
});
|
|
21
25
|
const existing = await projectFiles(root);
|
|
22
|
-
const baselinePath =
|
|
26
|
+
const baselinePath = ".metaform/application-baselines.json";
|
|
23
27
|
let previous = { files: {} };
|
|
24
28
|
if (existing[baselinePath])
|
|
25
|
-
previous = JSON.parse(await readFile(validateTargetPath(root, baselinePath),
|
|
26
|
-
const
|
|
29
|
+
previous = JSON.parse(await readFile(validateTargetPath(root, baselinePath), "utf8"));
|
|
30
|
+
const entryHtml = existing["index.html"]
|
|
31
|
+
? await readFile(join(root, "index.html"), "utf8")
|
|
32
|
+
: "";
|
|
33
|
+
const accent = entryHtml.match(/data-accent=["']([a-z][a-z0-9-]*)["']/)?.[1];
|
|
34
|
+
const generated = generateApplicationFiles(design, release, { accent });
|
|
27
35
|
const hashes = {};
|
|
28
36
|
for (const [path, content] of Object.entries(generated)) {
|
|
29
37
|
validateTargetPath(root, path);
|
|
@@ -34,35 +42,43 @@ export async function planPrepare(input) {
|
|
|
34
42
|
if (existing[path] &&
|
|
35
43
|
existing[path] !== hash &&
|
|
36
44
|
existing[path] !== previous.files[path] &&
|
|
37
|
-
!(path ===
|
|
45
|
+
!(path === "role-targets.json" &&
|
|
38
46
|
!existing[baselinePath] &&
|
|
39
|
-
(await readFile(join(root, path),
|
|
40
|
-
plan.conflicts.push({
|
|
47
|
+
(await readFile(join(root, path), "utf8")).trim() === "[]")) {
|
|
48
|
+
plan.conflicts.push({
|
|
49
|
+
code: "application_file_conflict",
|
|
50
|
+
path,
|
|
51
|
+
assetIds: [],
|
|
52
|
+
});
|
|
41
53
|
continue;
|
|
42
54
|
}
|
|
43
55
|
if (existing[path] !== hash)
|
|
44
56
|
plan.changes.push({
|
|
45
57
|
path,
|
|
46
58
|
beforeSha256: existing[path] ?? null,
|
|
47
|
-
after: sourceFile(
|
|
59
|
+
after: sourceFile("application-design/" + path, path, content),
|
|
48
60
|
});
|
|
49
61
|
}
|
|
50
62
|
for (const path of Object.keys(previous.files))
|
|
51
63
|
if (!(path in hashes))
|
|
52
|
-
plan.conflicts.push({
|
|
64
|
+
plan.conflicts.push({
|
|
65
|
+
code: "application_removal_requires_review",
|
|
66
|
+
path,
|
|
67
|
+
assetIds: [],
|
|
68
|
+
});
|
|
53
69
|
const metadata = JSON.stringify({
|
|
54
70
|
schemaVersion: 1,
|
|
55
|
-
phase:
|
|
71
|
+
phase: "before-s7",
|
|
56
72
|
designDigest: sha256(canonical(design)),
|
|
57
73
|
registryDigest: release.digest,
|
|
58
74
|
files: hashes,
|
|
59
|
-
}, null, 2) +
|
|
75
|
+
}, null, 2) + "\n";
|
|
60
76
|
if (existing[baselinePath] !== sha256(metadata))
|
|
61
77
|
plan.changes.push({
|
|
62
78
|
path: baselinePath,
|
|
63
79
|
beforeSha256: existing[baselinePath] ?? null,
|
|
64
|
-
after: sourceFile(
|
|
80
|
+
after: sourceFile("application-design/baseline", baselinePath, metadata),
|
|
65
81
|
});
|
|
66
|
-
plan.planDigest = sha256(canonical({ ...plan, planDigest:
|
|
82
|
+
plan.planDigest = sha256(canonical({ ...plan, planDigest: "" }));
|
|
67
83
|
return plan;
|
|
68
84
|
}
|
package/dist/source-map.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export declare const VERSION = "0.1.0";
|
|
2
|
+
export declare const DISTRIBUTED_ASSET_IDS: readonly ["common.semantic-region-scaffold", "quality.role-task-overview", "quality.role-task-groups"];
|
|
2
3
|
export declare const SEEDS: Record<string, {
|
|
3
4
|
source: string;
|
|
4
5
|
target: string;
|
|
5
6
|
exports: string[];
|
|
6
7
|
}>;
|
|
7
8
|
export declare const NPM_VERSIONS: Record<string, string>;
|
|
8
|
-
export declare const SOURCE_ROOTS: readonly [readonly ["
|
|
9
|
+
export declare const SOURCE_ROOTS: readonly [readonly ["platform/src/platform/", "src/layouts/"], readonly ["layout/src/semantic-region/", "src/components/common/semantic-region/"], readonly ["vendor/design-system/src/", "src/"], readonly ["business/quality/src/role-tasks/", "src/components/business/role-tasks/"]];
|
package/dist/source-map.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
export const VERSION = '0.1.0';
|
|
2
|
+
// 外壳只随基础模板交付;保留旧导出入口供兼容验证。
|
|
3
|
+
export const DISTRIBUTED_ASSET_IDS = ['common.semantic-region-scaffold', 'quality.role-task-overview', 'quality.role-task-groups'];
|
|
2
4
|
export const SEEDS = {
|
|
3
5
|
'common.semantic-region-scaffold': {
|
|
4
|
-
source: '
|
|
6
|
+
source: 'layout/src/semantic-region/semantic-region-scaffold.tsx',
|
|
5
7
|
target: 'src/components/common/semantic-region/semantic-region-scaffold.tsx',
|
|
6
8
|
exports: ['SemanticRegionScaffold'],
|
|
7
9
|
},
|
|
8
10
|
'role-workspace-shell': {
|
|
9
|
-
source: '
|
|
11
|
+
source: 'platform/src/platform/role-workspace-shell.tsx',
|
|
10
12
|
target: 'src/layouts/role-workspace-shell.tsx',
|
|
11
13
|
exports: ['RoleWorkspaceShell'],
|
|
12
14
|
},
|
|
13
15
|
'quality.role-task-overview': {
|
|
14
|
-
source: '
|
|
16
|
+
source: 'business/quality/src/role-tasks/role-task-overview.tsx',
|
|
15
17
|
target: 'src/components/business/role-tasks/role-task-overview.tsx',
|
|
16
18
|
exports: ['RoleTaskOverview'],
|
|
17
19
|
},
|
|
18
20
|
'quality.role-task-groups': {
|
|
19
|
-
source: '
|
|
21
|
+
source: 'business/quality/src/role-tasks/role-task-groups.tsx',
|
|
20
22
|
target: 'src/components/business/role-tasks/role-task-groups.tsx',
|
|
21
23
|
exports: ['RoleTaskGroups'],
|
|
22
24
|
},
|
|
@@ -32,11 +34,11 @@ export const NPM_VERSIONS = {
|
|
|
32
34
|
'tw-animate-css': '1.4.0',
|
|
33
35
|
};
|
|
34
36
|
export const SOURCE_ROOTS = [
|
|
35
|
-
['
|
|
36
|
-
['
|
|
37
|
-
['
|
|
37
|
+
['platform/src/platform/', 'src/layouts/'],
|
|
38
|
+
['layout/src/semantic-region/', 'src/components/common/semantic-region/'],
|
|
39
|
+
['vendor/design-system/src/', 'src/'],
|
|
38
40
|
[
|
|
39
|
-
'
|
|
41
|
+
'business/quality/src/role-tasks/',
|
|
40
42
|
'src/components/business/role-tasks/',
|
|
41
43
|
],
|
|
42
44
|
];
|
package/dist/template.d.ts
CHANGED
package/dist/template.js
CHANGED
|
@@ -22,7 +22,7 @@ export async function initProject(input) {
|
|
|
22
22
|
Array.isArray(manifest.files) ||
|
|
23
23
|
typeof manifest.files !== 'object')
|
|
24
24
|
throw new DistributionError('invalid_codebase');
|
|
25
|
-
if (manifest.version !== input.templateVersion)
|
|
25
|
+
if (input.templateVersion && manifest.version !== input.templateVersion)
|
|
26
26
|
throw new DistributionError('template_version');
|
|
27
27
|
const template = validateTargetPath(packageRoot, 'template');
|
|
28
28
|
const actual = await projectFiles(template);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@james_sww/metaform-asset-distribution",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"metaform-assets": "./dist/bin.js"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
|
-
"test": "node scripts/prepare-codebase.mjs && node scripts/prepare-contracts.mjs && vitest run",
|
|
36
|
+
"test": "node scripts/prepare-codebase.mjs && node scripts/prepare-contracts.mjs && vitest run --maxWorkers=1 --no-file-parallelism",
|
|
37
37
|
"typecheck": "node scripts/prepare-contracts.mjs && tsc --noEmit",
|
|
38
38
|
"build": "node scripts/prepare-contracts.mjs && tsc -p tsconfig.build.json",
|
|
39
39
|
"test:standalone": "node tests/run-standalone.mjs",
|