@plitzi/sdk-server 0.32.5 → 0.32.7
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/CHANGELOG.md +20 -0
- package/dist/core/services/mcp.js +1 -1
- package/dist/helpers/buildServerInfo.js +3 -9
- package/dist/index.js +2 -1
- package/dist/modules/ai/toolkit.js +1 -0
- package/dist/modules/mcp/catalogs/builtinCallbacks.js +204 -0
- package/dist/modules/mcp/catalogs/builtinComponents.js +170 -0
- package/dist/modules/mcp/catalogs/builtinElementCallbacks.js +50 -0
- package/dist/modules/mcp/catalogs/builtinTransformers.js +148 -0
- package/dist/modules/mcp/catalogs/builtinUtilities.js +90 -0
- package/dist/modules/mcp/{tools/operations/style → catalogs}/cssCatalog.js +75 -2
- package/dist/modules/mcp/catalogs/observed.js +90 -0
- package/dist/modules/mcp/catalogs/paramSpec.js +69 -0
- package/dist/modules/mcp/catalogs/registry.js +89 -0
- package/dist/modules/mcp/handler.js +41 -13
- package/dist/modules/mcp/helpers/agentPrompt.js +104 -0
- package/dist/modules/mcp/helpers/guide.js +334 -15
- package/dist/modules/mcp/helpers/interactions.js +123 -0
- package/dist/modules/mcp/helpers/log.js +54 -0
- package/dist/modules/mcp/helpers/space.js +184 -33
- package/dist/modules/mcp/helpers/uris.js +44 -0
- package/dist/modules/mcp/resources/canonical.js +6 -21
- package/dist/modules/mcp/resources/core.js +4 -3
- package/dist/modules/mcp/resources/primer.js +13 -8
- package/dist/modules/mcp/resources/register.js +37 -5
- package/dist/modules/mcp/resources/schema.js +30 -20
- package/dist/modules/mcp/resources/style.js +18 -11
- package/dist/modules/mcp/server.js +29 -8
- package/dist/modules/mcp/tools/apply/dispatch.js +38 -18
- package/dist/modules/mcp/tools/apply/index.js +19 -4
- package/dist/modules/mcp/tools/apply/writeResult.js +2 -1
- package/dist/modules/mcp/tools/index.js +3 -1
- package/dist/modules/mcp/tools/operations/index.js +13 -2
- package/dist/modules/mcp/tools/operations/schema/bindings/deleteBinding.js +32 -0
- package/dist/modules/mcp/tools/operations/schema/bindings/patchBinding.js +36 -0
- package/dist/modules/mcp/tools/operations/schema/bindings/upsertBinding.js +47 -0
- package/dist/modules/mcp/tools/operations/schema/{deleteElement.js → elements/deleteElement.js} +10 -6
- package/dist/modules/mcp/tools/operations/schema/{moveElement.js → elements/moveElement.js} +8 -6
- package/dist/modules/mcp/tools/operations/schema/{patchElement.js → elements/patchElement.js} +19 -7
- package/dist/modules/mcp/tools/operations/schema/{upsertElement.js → elements/upsertElement.js} +11 -5
- package/dist/modules/mcp/tools/operations/schema/{deleteFolder.js → folders/deleteFolder.js} +4 -4
- package/dist/modules/mcp/tools/operations/schema/{upsertFolder.js → folders/upsertFolder.js} +4 -4
- package/dist/modules/mcp/tools/operations/schema/interactions/deleteInteraction.js +52 -0
- package/dist/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.js +47 -0
- package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.js +43 -0
- package/dist/modules/mcp/tools/operations/schema/operations.js +25 -11
- package/dist/modules/mcp/tools/operations/schema/{deletePage.js → pages/deletePage.js} +8 -5
- package/dist/modules/mcp/tools/operations/schema/pages/upsertPage.js +75 -0
- package/dist/modules/mcp/tools/operations/schema/settings/patchSettings.js +45 -0
- package/dist/modules/mcp/tools/operations/schema/shared.js +94 -2
- package/dist/modules/mcp/tools/operations/schema/translator.js +77 -10
- package/dist/modules/mcp/tools/operations/schema/{deleteVariable.js → variables/deleteVariable.js} +3 -3
- package/dist/modules/mcp/tools/operations/schema/{upsertVariable.js → variables/upsertVariable.js} +4 -4
- package/dist/modules/mcp/tools/operations/schema/write.js +78 -13
- package/dist/modules/mcp/tools/operations/style/{deleteDefinition.js → definitions/deleteDefinition.js} +4 -3
- package/dist/modules/mcp/tools/operations/style/{patchDefinition.js → definitions/patchDefinition.js} +6 -5
- package/dist/modules/mcp/tools/operations/style/{upsertDefinition.js → definitions/upsertDefinition.js} +5 -4
- package/dist/modules/mcp/tools/operations/style/{deleteGlobalStyle.js → globalStyles/deleteGlobalStyle.js} +4 -3
- package/dist/modules/mcp/tools/operations/style/{patchGlobalStyle.js → globalStyles/patchGlobalStyle.js} +6 -5
- package/dist/modules/mcp/tools/operations/style/{upsertGlobalStyle.js → globalStyles/upsertGlobalStyle.js} +5 -4
- package/dist/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.js +21 -0
- package/dist/modules/mcp/tools/operations/style/idStyles/patchIdStyle.js +28 -0
- package/dist/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.js +24 -0
- package/dist/modules/mcp/tools/operations/style/operations.js +14 -8
- package/dist/modules/mcp/tools/operations/style/translator.js +25 -1
- package/dist/modules/mcp/tools/operations/style/{deleteStyleVariable.js → variables/deleteStyleVariable.js} +4 -4
- package/dist/modules/mcp/tools/operations/style/{upsertStyleVariable.js → variables/upsertStyleVariable.js} +4 -4
- package/dist/modules/mcp/tools/operations/style/write.js +19 -11
- package/dist/modules/mcp/tools/read.js +1 -1
- package/dist/modules/mcp/tools/render.js +114 -0
- package/dist/modules/mcp/tools/search.js +34 -27
- package/dist/modules/mcp/tools/shared/tool.js +1 -0
- package/dist/modules/mcp/tools/shared/validator/audit.js +124 -0
- package/dist/modules/mcp/tools/shared/validator/batch.js +30 -0
- package/dist/modules/mcp/tools/shared/validator/bindings.js +70 -0
- package/dist/modules/mcp/tools/shared/validator/context.js +35 -0
- package/dist/modules/mcp/tools/shared/validator/css.js +47 -0
- package/dist/modules/mcp/tools/shared/validator/elements.js +55 -0
- package/dist/modules/mcp/tools/shared/validator/index.js +226 -0
- package/dist/modules/mcp/tools/shared/validator/interactions.js +106 -0
- package/dist/modules/mcp/tools/shared/validator/refs.js +28 -0
- package/dist/modules/mcp/tools/validate.js +23 -3
- package/dist/modules/ssr/preview.js +1 -1
- package/dist/modules/ssr/views/template.ejs +2 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/modules/mcp/catalogs/builtinCallbacks.d.ts +23 -0
- package/dist/src/modules/mcp/catalogs/builtinComponents.d.ts +4 -0
- package/dist/src/modules/mcp/catalogs/builtinElementCallbacks.d.ts +20 -0
- package/dist/src/modules/mcp/catalogs/builtinTransformers.d.ts +28 -0
- package/dist/src/modules/mcp/catalogs/builtinTransformers.test.d.ts +1 -0
- package/dist/src/modules/mcp/catalogs/builtinUtilities.d.ts +18 -0
- package/dist/src/modules/mcp/{tools/operations/style → catalogs}/cssCatalog.d.ts +5 -1
- package/dist/src/modules/mcp/catalogs/index.d.ts +9 -0
- package/dist/src/modules/mcp/catalogs/observed.d.ts +48 -0
- package/dist/src/modules/mcp/catalogs/paramSpec.d.ts +42 -0
- package/dist/src/modules/mcp/catalogs/registry.d.ts +35 -0
- package/dist/src/modules/mcp/handler.d.ts +2 -2
- package/dist/src/modules/mcp/helpers/agentPrompt.d.ts +4 -0
- package/dist/src/modules/mcp/helpers/guide.d.ts +2 -1
- package/dist/src/modules/mcp/helpers/index.d.ts +4 -0
- package/dist/src/modules/mcp/helpers/interactions.d.ts +30 -0
- package/dist/src/modules/mcp/helpers/log.d.ts +8 -0
- package/dist/src/modules/mcp/helpers/log.test.d.ts +1 -0
- package/dist/src/modules/mcp/helpers/space.d.ts +68 -11
- package/dist/src/modules/mcp/helpers/uris.d.ts +28 -0
- package/dist/src/modules/mcp/index.d.ts +1 -1
- package/dist/src/modules/mcp/mcp.bench.d.ts +1 -0
- package/dist/src/modules/mcp/resources/canonical.d.ts +0 -1
- package/dist/src/modules/mcp/resources/index.d.ts +2 -3
- package/dist/src/modules/mcp/resources/primer.d.ts +2 -1
- package/dist/src/modules/mcp/resources/register.d.ts +2 -2
- package/dist/src/modules/mcp/server.d.ts +5 -2
- package/dist/src/modules/mcp/tools/apply/index.d.ts +191 -2
- package/dist/src/modules/mcp/tools/index.d.ts +1 -0
- package/dist/src/modules/mcp/tools/operations/index.d.ts +383 -4
- package/dist/src/modules/mcp/tools/operations/schema/bindings/deleteBinding.d.ts +17 -0
- package/dist/src/modules/mcp/tools/operations/schema/bindings/patchBinding.d.ts +25 -0
- package/dist/src/modules/mcp/tools/operations/schema/bindings/upsertBinding.d.ts +27 -0
- package/dist/src/modules/mcp/tools/operations/schema/{deleteElement.d.ts → elements/deleteElement.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/{moveElement.d.ts → elements/moveElement.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/{patchElement.d.ts → elements/patchElement.d.ts} +7 -2
- package/dist/src/modules/mcp/tools/operations/schema/{upsertElement.d.ts → elements/upsertElement.d.ts} +3 -3
- package/dist/src/modules/mcp/tools/operations/schema/{deleteFolder.d.ts → folders/deleteFolder.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/{upsertFolder.d.ts → folders/upsertFolder.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/index.d.ts +17 -11
- package/dist/src/modules/mcp/tools/operations/schema/interactions/deleteInteraction.d.ts +12 -0
- package/dist/src/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.d.ts +18 -0
- package/dist/src/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +27 -0
- package/dist/src/modules/mcp/tools/operations/schema/operations.d.ts +131 -0
- package/dist/src/modules/mcp/tools/operations/schema/{deletePage.d.ts → pages/deletePage.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/{upsertPage.d.ts → pages/upsertPage.d.ts} +3 -2
- package/dist/src/modules/mcp/tools/operations/schema/settings/patchSettings.d.ts +34 -0
- package/dist/src/modules/mcp/tools/operations/schema/shared.d.ts +53 -0
- package/dist/src/modules/mcp/tools/operations/schema/translator.d.ts +5 -2
- package/dist/src/modules/mcp/tools/operations/schema/{deleteVariable.d.ts → variables/deleteVariable.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/{upsertVariable.d.ts → variables/upsertVariable.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/schema/write.d.ts +38 -8
- package/dist/src/modules/mcp/tools/operations/style/{deleteDefinition.d.ts → definitions/deleteDefinition.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/{patchDefinition.d.ts → definitions/patchDefinition.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/{upsertDefinition.d.ts → definitions/upsertDefinition.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/{deleteGlobalStyle.d.ts → globalStyles/deleteGlobalStyle.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/{patchGlobalStyle.d.ts → globalStyles/patchGlobalStyle.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/{upsertGlobalStyle.d.ts → globalStyles/upsertGlobalStyle.d.ts} +2 -2
- package/dist/src/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.d.ts +9 -0
- package/dist/src/modules/mcp/tools/operations/style/idStyles/patchIdStyle.d.ts +37 -0
- package/dist/src/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.d.ts +37 -0
- package/dist/src/modules/mcp/tools/operations/style/index.d.ts +11 -9
- package/dist/src/modules/mcp/tools/operations/style/operations.d.ts +70 -2
- package/dist/src/modules/mcp/tools/operations/style/shared.d.ts +1 -1
- package/dist/src/modules/mcp/tools/operations/style/translator.d.ts +4 -1
- package/dist/src/modules/mcp/tools/operations/style/{deleteStyleVariable.d.ts → variables/deleteStyleVariable.d.ts} +3 -3
- package/dist/src/modules/mcp/tools/operations/style/{upsertStyleVariable.d.ts → variables/upsertStyleVariable.d.ts} +3 -3
- package/dist/src/modules/mcp/tools/operations/style/write.d.ts +2 -7
- package/dist/src/modules/mcp/tools/preview.d.ts +191 -2
- package/dist/src/modules/mcp/tools/render.d.ts +434 -0
- package/dist/src/modules/mcp/tools/render.test.d.ts +1 -0
- package/dist/src/modules/mcp/tools/screenshot.d.ts +191 -2
- package/dist/src/modules/mcp/tools/shared/tool.d.ts +4 -0
- package/dist/src/modules/mcp/tools/shared/validator/audit.d.ts +4 -0
- package/dist/src/modules/mcp/tools/shared/validator/batch.d.ts +5 -0
- package/dist/src/modules/mcp/tools/shared/validator/bindings.d.ts +6 -0
- package/dist/src/modules/mcp/tools/shared/validator/context.d.ts +34 -0
- package/dist/src/modules/mcp/tools/shared/validator/css.d.ts +4 -0
- package/dist/src/modules/mcp/tools/shared/validator/elements.d.ts +6 -0
- package/dist/src/modules/mcp/tools/shared/validator/index.d.ts +8 -0
- package/dist/src/modules/mcp/tools/shared/validator/interactions.d.ts +3 -0
- package/dist/src/modules/mcp/tools/shared/validator/refs.d.ts +4 -0
- package/dist/src/modules/mcp/tools/validate.d.ts +191 -2
- package/dist/src/modules/mcp/types/aiSchema.d.ts +93 -1
- package/package.json +12 -10
- package/dist/modules/mcp/tools/operations/schema/registry.js +0 -55
- package/dist/modules/mcp/tools/operations/schema/upsertPage.js +0 -64
- package/dist/modules/mcp/tools/shared/validator.js +0 -262
- package/dist/src/modules/mcp/tools/operations/schema/registry.d.ts +0 -22
- package/dist/src/modules/mcp/tools/shared/validator.d.ts +0 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { computeVersion } from "../helpers/computeVersion.js";
|
|
2
|
-
import { elementRefOf, getPageElements, isPageElement, pageRefOf, pageRefOfElement } from "../helpers/space.js";
|
|
2
|
+
import { elementRefOf, getPageElements, isPageElement, nameOf, pageRefOf, pageRefOfElement } from "../helpers/space.js";
|
|
3
|
+
import { elementUri, pageUri } from "../helpers/uris.js";
|
|
3
4
|
import { definitionRefs, definitionToAI } from "./operations/style/translator.js";
|
|
4
|
-
import {
|
|
5
|
+
import { elementView, pageSkeletonToAI } from "./operations/schema/translator.js";
|
|
5
6
|
import { defineTool } from "./shared/tool.js";
|
|
6
7
|
import { z } from "zod";
|
|
7
8
|
//#region src/modules/mcp/tools/search.ts
|
|
@@ -15,21 +16,20 @@ var searchShape = {
|
|
|
15
16
|
limit: z.number().int().min(1).max(100).optional().describe("Max element hits to return (default 50). Response echoes total and, if more remain, nextOffset."),
|
|
16
17
|
offset: z.number().int().min(0).optional().describe("Element hits to skip (default 0). Page by re-calling with offset = nextOffset until it is absent.")
|
|
17
18
|
};
|
|
18
|
-
var labelOf = (el) => (typeof el.attributes.name === "string" ? el.attributes.name : void 0) ?? el.definition.label;
|
|
19
19
|
var breadcrumb = (schema, el) => {
|
|
20
20
|
const chain = [];
|
|
21
21
|
let current = el;
|
|
22
22
|
const guard = /* @__PURE__ */ new Set();
|
|
23
23
|
while (current && !guard.has(current.id)) {
|
|
24
24
|
guard.add(current.id);
|
|
25
|
-
chain.push(
|
|
25
|
+
chain.push(nameOf(current));
|
|
26
26
|
current = current.definition.parentId ? schema.flat[current.definition.parentId] : void 0;
|
|
27
27
|
}
|
|
28
28
|
return chain.reverse();
|
|
29
29
|
};
|
|
30
30
|
var search = (input, space, env) => {
|
|
31
31
|
const query = input.query.toLowerCase();
|
|
32
|
-
const
|
|
32
|
+
const matched = [];
|
|
33
33
|
for (const el of Object.values(space.schema.flat)) {
|
|
34
34
|
if (isPageElement(space.schema, el)) continue;
|
|
35
35
|
if (input.filters?.type && el.definition.type !== input.filters.type) continue;
|
|
@@ -40,22 +40,33 @@ var search = (input, space, env) => {
|
|
|
40
40
|
if (el.definition.type.toLowerCase().includes(query)) matches.push(`type: ${el.definition.type}`);
|
|
41
41
|
for (const [key, value] of Object.entries(el.attributes)) if (String(value).toLowerCase().includes(query)) matches.push(`${key}: ${String(value).slice(0, 100)}`);
|
|
42
42
|
if (matches.length === 0) continue;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
results.push({
|
|
43
|
+
matched.push({
|
|
44
|
+
el,
|
|
46
45
|
pageRef,
|
|
47
|
-
ref,
|
|
48
|
-
|
|
49
|
-
pageUri: `plitzi://schema/${env}/pages/${pageRef}`,
|
|
50
|
-
stateVersion: computeVersion(detail),
|
|
51
|
-
parentRef: detail.parentRef,
|
|
52
|
-
path: breadcrumb(space.schema, el),
|
|
53
|
-
label: el.definition.label,
|
|
54
|
-
type: el.definition.type,
|
|
55
|
-
matches,
|
|
56
|
-
detail: input.include === "detail" ? detail : void 0
|
|
46
|
+
ref: elementRefOf(el),
|
|
47
|
+
matches
|
|
57
48
|
});
|
|
58
49
|
}
|
|
50
|
+
const offset = input.offset ?? 0;
|
|
51
|
+
const limit = input.limit ?? 50;
|
|
52
|
+
const total = matched.length;
|
|
53
|
+
const nextOffset = offset + limit < total ? offset + limit : void 0;
|
|
54
|
+
const results = matched.slice(offset, offset + limit).map((hit) => {
|
|
55
|
+
const { detail, version } = elementView(space.schema, hit.el, space.style);
|
|
56
|
+
return {
|
|
57
|
+
pageRef: hit.pageRef,
|
|
58
|
+
ref: hit.ref,
|
|
59
|
+
uri: elementUri(env, hit.ref),
|
|
60
|
+
pageUri: pageUri(env, hit.pageRef),
|
|
61
|
+
stateVersion: version,
|
|
62
|
+
parentRef: detail.parentRef,
|
|
63
|
+
path: breadcrumb(space.schema, hit.el),
|
|
64
|
+
label: hit.el.definition.label,
|
|
65
|
+
type: hit.el.definition.type,
|
|
66
|
+
matches: hit.matches,
|
|
67
|
+
detail: input.include === "detail" ? detail : void 0
|
|
68
|
+
};
|
|
69
|
+
});
|
|
59
70
|
const definitions = [];
|
|
60
71
|
for (const ref of definitionRefs(space.style)) {
|
|
61
72
|
if (ref.toLowerCase().includes(query)) {
|
|
@@ -66,7 +77,7 @@ var search = (input, space, env) => {
|
|
|
66
77
|
}
|
|
67
78
|
const pages = [];
|
|
68
79
|
for (const page of getPageElements(space.schema)) {
|
|
69
|
-
const label =
|
|
80
|
+
const label = nameOf(page);
|
|
70
81
|
const slug = typeof page.attributes.slug === "string" ? page.attributes.slug : "";
|
|
71
82
|
const matches = [];
|
|
72
83
|
if (label.toLowerCase().includes(query)) matches.push(`label: ${label}`);
|
|
@@ -75,19 +86,15 @@ var search = (input, space, env) => {
|
|
|
75
86
|
const ref = pageRefOf(page);
|
|
76
87
|
pages.push({
|
|
77
88
|
ref,
|
|
78
|
-
uri:
|
|
79
|
-
stateVersion: computeVersion(pageSkeletonToAI(space.schema, page)),
|
|
89
|
+
uri: pageUri(env, ref),
|
|
90
|
+
stateVersion: computeVersion(pageSkeletonToAI(space.schema, page, space.style)),
|
|
80
91
|
label,
|
|
81
92
|
slug,
|
|
82
93
|
matches
|
|
83
94
|
});
|
|
84
95
|
}
|
|
85
|
-
const offset = input.offset ?? 0;
|
|
86
|
-
const limit = input.limit ?? 50;
|
|
87
|
-
const total = results.length;
|
|
88
|
-
const nextOffset = offset + limit < total ? offset + limit : void 0;
|
|
89
96
|
return {
|
|
90
|
-
results
|
|
97
|
+
results,
|
|
91
98
|
total,
|
|
92
99
|
offset,
|
|
93
100
|
limit,
|
|
@@ -99,7 +106,7 @@ var search = (input, space, env) => {
|
|
|
99
106
|
var searchTool = defineTool({
|
|
100
107
|
name: "plitzi_search",
|
|
101
108
|
title: "Search",
|
|
102
|
-
description: "
|
|
109
|
+
description: "FIND elements when you know what you want but not its ref/uri (e.g. \"the hero button\"). Matches label, type or attribute value across all pages. Each hit returns the element uri, its stateVersion (edit with optimistic concurrency, no read needed) and its tree path. Pass include: \"detail\" to inline the full props/style of each hit plus resolvedStyle (the CSS of its classes). Also returns any style definitions matching the query (with full CSS) under `definitions`, and matching pages under `pages`. Element hits are paginated: it returns at most `limit` (default 50) starting at `offset`, plus `total` and — while more remain — `nextOffset` to fetch the next page.",
|
|
103
110
|
inputShape: searchShape,
|
|
104
111
|
access: "read",
|
|
105
112
|
run: (input, ctx) => search(input, ctx.space, ctx.env)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { elementRefOf, findElementByRef } from "../../../helpers/space.js";
|
|
2
|
+
import { definitionToAI, globalStyleToAI, idStyleToAI } from "../../operations/style/translator.js";
|
|
3
|
+
import { checkBindingSourceScope, checkBindingTarget, checkBindingTransformers } from "./bindings.js";
|
|
4
|
+
import { checkSlotCss } from "./css.js";
|
|
5
|
+
import { checkVariantApplication } from "./elements.js";
|
|
6
|
+
import { checkInteractionNode } from "./interactions.js";
|
|
7
|
+
import { buildValidationCtx } from "./index.js";
|
|
8
|
+
//#region src/modules/mcp/tools/shared/validator/audit.ts
|
|
9
|
+
var harvest = (ctx, into, label, run) => {
|
|
10
|
+
const sub = {
|
|
11
|
+
...ctx,
|
|
12
|
+
errors: [],
|
|
13
|
+
warnings: [],
|
|
14
|
+
warned: /* @__PURE__ */ new Set()
|
|
15
|
+
};
|
|
16
|
+
run(sub);
|
|
17
|
+
for (const e of sub.errors) into.errors.push({
|
|
18
|
+
path: e.path,
|
|
19
|
+
message: `Pre-existing malformation in ${label}: ${e.message}`,
|
|
20
|
+
hint: `${e.hint ? `${e.hint} ` : ""}This issue already exists in the space (NOT caused by your change), but the save is blocked until you fix it too, in this same batch.`,
|
|
21
|
+
...e.validValues ? { validValues: e.validValues } : {}
|
|
22
|
+
});
|
|
23
|
+
for (const w of sub.warnings) {
|
|
24
|
+
const message = `Pre-existing issue in ${label} (not caused by your change, but worth fixing too): ${w}`;
|
|
25
|
+
if (!into.warnings.includes(message)) into.warnings.push(message);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var toNode = (id, node) => ({
|
|
29
|
+
id,
|
|
30
|
+
title: node.title,
|
|
31
|
+
nodeType: node.type,
|
|
32
|
+
action: node.action,
|
|
33
|
+
params: node.params,
|
|
34
|
+
enabled: node.enabled,
|
|
35
|
+
when: node.when,
|
|
36
|
+
elementId: node.elementId ?? void 0,
|
|
37
|
+
preview: node.preview
|
|
38
|
+
});
|
|
39
|
+
var auditElement = (space, sub, el) => {
|
|
40
|
+
const hostRef = elementRefOf(el);
|
|
41
|
+
const base = `element "${hostRef}"`;
|
|
42
|
+
for (const [category, list] of Object.entries(el.definition.bindings ?? {})) for (const binding of list) {
|
|
43
|
+
const path = `${base}.bindings.${category}[to=${binding.to}]`;
|
|
44
|
+
checkBindingTransformers(binding.transformers, `${path}.transformers`, sub);
|
|
45
|
+
checkBindingSourceScope(space, sub, hostRef, binding.source, `${path}.source`);
|
|
46
|
+
checkBindingTarget(hostRef, category, binding.to, path, sub);
|
|
47
|
+
}
|
|
48
|
+
for (const [id, node] of Object.entries(el.definition.interactions ?? {})) checkInteractionNode(toNode(id, node), `${base}.interactions.${id}`, sub, hostRef);
|
|
49
|
+
checkVariantApplication(el.definition.initialState, `${base}.initialState`, sub);
|
|
50
|
+
};
|
|
51
|
+
var auditDefinitionCss = (sub, label, def) => {
|
|
52
|
+
const { ref: _ref, slots, ...slot } = def;
|
|
53
|
+
checkSlotCss(slot, label, sub);
|
|
54
|
+
for (const [name, slotDef] of Object.entries(slots ?? {})) checkSlotCss(slotDef, `${label}.slots.${name}`, sub);
|
|
55
|
+
};
|
|
56
|
+
var collectTouched = (ops) => {
|
|
57
|
+
const touched = {
|
|
58
|
+
elementRefs: /* @__PURE__ */ new Set(),
|
|
59
|
+
definitions: /* @__PURE__ */ new Set(),
|
|
60
|
+
globalStyles: /* @__PURE__ */ new Set(),
|
|
61
|
+
idStyles: /* @__PURE__ */ new Set()
|
|
62
|
+
};
|
|
63
|
+
for (const op of ops) switch (op.type) {
|
|
64
|
+
case "upsertElement":
|
|
65
|
+
touched.elementRefs.add(op.element.ref);
|
|
66
|
+
break;
|
|
67
|
+
case "patchElement":
|
|
68
|
+
case "moveElement":
|
|
69
|
+
case "upsertBinding":
|
|
70
|
+
case "patchBinding":
|
|
71
|
+
case "deleteBinding":
|
|
72
|
+
case "upsertInteractionFlow":
|
|
73
|
+
case "patchInteractionNode":
|
|
74
|
+
case "deleteInteraction":
|
|
75
|
+
touched.elementRefs.add(op.ref);
|
|
76
|
+
break;
|
|
77
|
+
case "upsertDefinition":
|
|
78
|
+
case "patchDefinition":
|
|
79
|
+
touched.definitions.add(op.ref);
|
|
80
|
+
break;
|
|
81
|
+
case "upsertGlobalStyle":
|
|
82
|
+
case "patchGlobalStyle":
|
|
83
|
+
touched.globalStyles.add(op.componentType);
|
|
84
|
+
break;
|
|
85
|
+
case "upsertIdStyle":
|
|
86
|
+
case "patchIdStyle":
|
|
87
|
+
touched.idStyles.add(op.targetId);
|
|
88
|
+
break;
|
|
89
|
+
default: break;
|
|
90
|
+
}
|
|
91
|
+
return touched;
|
|
92
|
+
};
|
|
93
|
+
var auditResources = (space, ops) => {
|
|
94
|
+
const ctx = buildValidationCtx(space, ops);
|
|
95
|
+
const result = {
|
|
96
|
+
valid: true,
|
|
97
|
+
errors: [],
|
|
98
|
+
warnings: []
|
|
99
|
+
};
|
|
100
|
+
const touched = collectTouched(ops);
|
|
101
|
+
const seenElements = /* @__PURE__ */ new Set();
|
|
102
|
+
for (const ref of touched.elementRefs) {
|
|
103
|
+
const el = findElementByRef(space.schema, ref);
|
|
104
|
+
if (!el || seenElements.has(el.id)) continue;
|
|
105
|
+
seenElements.add(el.id);
|
|
106
|
+
harvest(ctx, result, `element "${elementRefOf(el)}"`, (sub) => auditElement(space, sub, el));
|
|
107
|
+
}
|
|
108
|
+
for (const ref of touched.definitions) {
|
|
109
|
+
const def = definitionToAI(space.style, ref);
|
|
110
|
+
if (def) harvest(ctx, result, `definition "${ref}"`, (sub) => auditDefinitionCss(sub, `definition "${ref}"`, def));
|
|
111
|
+
}
|
|
112
|
+
for (const componentType of touched.globalStyles) {
|
|
113
|
+
const def = globalStyleToAI(space.style, componentType);
|
|
114
|
+
if (def) harvest(ctx, result, `global style "${componentType}"`, (sub) => auditDefinitionCss(sub, `global style "${componentType}"`, def));
|
|
115
|
+
}
|
|
116
|
+
for (const targetId of touched.idStyles) {
|
|
117
|
+
const def = idStyleToAI(space.style, targetId);
|
|
118
|
+
if (def) harvest(ctx, result, `id style "#${targetId}"`, (sub) => auditDefinitionCss(sub, `id style "#${targetId}"`, def));
|
|
119
|
+
}
|
|
120
|
+
result.valid = result.errors.length === 0;
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
export { auditResources };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { slugRouteParams } from "../../../helpers/space.js";
|
|
2
|
+
//#region src/modules/mcp/tools/shared/validator/batch.ts
|
|
3
|
+
var batchDeclaredVars = (ops) => {
|
|
4
|
+
const names = [];
|
|
5
|
+
for (const op of ops) if (op.type === "upsertVariable") names.push(op.name);
|
|
6
|
+
else if (op.type === "upsertPage" && typeof op.slug === "string") names.push(...slugRouteParams(op.slug));
|
|
7
|
+
return names;
|
|
8
|
+
};
|
|
9
|
+
var batchDeclaredPages = (ops) => {
|
|
10
|
+
const refs = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const op of ops) if (op.type === "upsertPage") refs.add(op.ref);
|
|
12
|
+
return refs;
|
|
13
|
+
};
|
|
14
|
+
var batchDeclaredFolders = (ops) => {
|
|
15
|
+
const refs = /* @__PURE__ */ new Set();
|
|
16
|
+
for (const op of ops) if (op.type === "upsertFolder") refs.add(op.ref);
|
|
17
|
+
return refs;
|
|
18
|
+
};
|
|
19
|
+
var batchDeclaredVariants = (ops) => {
|
|
20
|
+
const map = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const op of ops) {
|
|
22
|
+
if (op.type !== "upsertDefinition" && op.type !== "patchDefinition") continue;
|
|
23
|
+
const names = new Set(Object.keys(op.variants ?? {}));
|
|
24
|
+
for (const slot of Object.values(op.slots ?? {})) for (const name of Object.keys(slot.variants ?? {})) names.add(name);
|
|
25
|
+
if (names.size > 0) map.set(op.ref, /* @__PURE__ */ new Set([...map.get(op.ref) ?? [], ...names]));
|
|
26
|
+
}
|
|
27
|
+
return map;
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { batchDeclaredFolders, batchDeclaredPages, batchDeclaredVariants, batchDeclaredVars };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getTransformer, suggestTransformer } from "../../../catalogs/builtinTransformers.js";
|
|
2
|
+
import { descendantIds, elementRefOf, findElementByRef } from "../../../helpers/space.js";
|
|
3
|
+
import { warnOnce } from "./context.js";
|
|
4
|
+
import getSourceName from "@plitzi/sdk-shared/dataSource/helpers/getSourceName";
|
|
5
|
+
//#region src/modules/mcp/tools/shared/validator/bindings.ts
|
|
6
|
+
var providerOfSource = (space, source) => {
|
|
7
|
+
const head = source.split(".")[0];
|
|
8
|
+
const sep = head.indexOf("_");
|
|
9
|
+
if (sep < 0) return;
|
|
10
|
+
const idRef = head.slice(sep + 1);
|
|
11
|
+
const el = findElementByRef(space.schema, idRef);
|
|
12
|
+
if (!el || getSourceName(el.definition.type, el) !== head) return;
|
|
13
|
+
return {
|
|
14
|
+
ref: elementRefOf(el),
|
|
15
|
+
id: el.id
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
var checkBindingTarget = (ref, category, to, path, ctx) => {
|
|
19
|
+
if (category !== "attributes" && category !== "initialState") return;
|
|
20
|
+
const type = ctx.elementType(ref);
|
|
21
|
+
const targets = type ? ctx.typeMeta.get(type)?.bindingTargets?.[category] : void 0;
|
|
22
|
+
if (!targets || targets.size === 0 || targets.has(to)) return;
|
|
23
|
+
warnOnce(ctx, `Binding target "${to}" at ${path} is not among the "${category}" targets the type "${type}" declares (${[...targets].sort().join(", ")}). Verify against plitzi://data-sources; it may still be valid.`);
|
|
24
|
+
};
|
|
25
|
+
var checkBindingSourceScope = (space, ctx, elementRef, source, path) => {
|
|
26
|
+
const provider = providerOfSource(space, source);
|
|
27
|
+
if (!provider) return;
|
|
28
|
+
const bound = findElementByRef(space.schema, elementRef);
|
|
29
|
+
if (!bound) return;
|
|
30
|
+
if (bound.id !== provider.id && descendantIds(space.schema, provider.id).includes(bound.id)) return;
|
|
31
|
+
ctx.errors.push({
|
|
32
|
+
path,
|
|
33
|
+
message: `Binding source "${source}" is provided by element "${provider.ref}", but "${elementRef}" is not inside its subtree`,
|
|
34
|
+
hint: `An element source is scoped to its DESCENDANTS only, so this binding resolves to nothing at runtime (the source is not available outside "${provider.ref}"). Move "${elementRef}" under "${provider.ref}", or bind to a source that is in scope (e.g. a global module source like state/space/navigation).`
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
var checkBindingTransformers = (transformers, path, ctx) => {
|
|
38
|
+
transformers?.forEach((transformer, i) => {
|
|
39
|
+
if (transformer.enabled === false) return;
|
|
40
|
+
const base = `${path}[${i}]`;
|
|
41
|
+
const spec = getTransformer(transformer.action);
|
|
42
|
+
if (!spec) {
|
|
43
|
+
const suggestion = suggestTransformer(transformer.action);
|
|
44
|
+
ctx.errors.push({
|
|
45
|
+
path: `${base}.action`,
|
|
46
|
+
message: `Unknown transformer action "${transformer.action}"`,
|
|
47
|
+
hint: `The runtime skips an unknown transformer and passes the value through unchanged.${suggestion ? ` Did you mean "${suggestion}"?` : ""} See the transformers list in plitzi://data-sources.`
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const params = transformer.params;
|
|
52
|
+
const unknown = Object.keys(params).filter((key) => !(key in spec.params));
|
|
53
|
+
if (spec.strictParams && unknown.length > 0) warnOnce(ctx, `Transformer "${transformer.action}" at ${base} got unknown param(s) ${unknown.map((k) => `"${k}"`).join(", ")} — the runtime ignores them. Valid params: ${Object.keys(spec.params).join(", ") || "(none)"}.`);
|
|
54
|
+
for (const [key, param] of Object.entries(spec.params)) {
|
|
55
|
+
if (param.required && !(key in params)) ctx.errors.push({
|
|
56
|
+
path: `${base}.params.${key}`,
|
|
57
|
+
message: `Transformer "${transformer.action}" is missing required param "${key}"`,
|
|
58
|
+
hint: param.description
|
|
59
|
+
});
|
|
60
|
+
if (param.type === "select" && param.options && key in params && !param.options.includes(params[key])) ctx.errors.push({
|
|
61
|
+
path: `${base}.params.${key}`,
|
|
62
|
+
message: `Transformer "${transformer.action}" param "${key}" is "${params[key]}", not one of its options`,
|
|
63
|
+
hint: `Use one of: ${param.options.join(", ")}.`,
|
|
64
|
+
validValues: param.options
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { checkBindingSourceScope, checkBindingTarget, checkBindingTransformers };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/modules/mcp/tools/shared/validator/context.ts
|
|
2
|
+
var VAR_REF = /\{\{\s*([A-Za-z_][\w.-]*)\s*\}\}/g;
|
|
3
|
+
var CSS_VAR = /var\(\s*--([A-Za-z_][\w-]*)\s*\)/g;
|
|
4
|
+
var RAW_CODE_TYPES = /* @__PURE__ */ new Set([
|
|
5
|
+
"blockJsx",
|
|
6
|
+
"blockHtml",
|
|
7
|
+
"custom"
|
|
8
|
+
]);
|
|
9
|
+
var warnOnce = (ctx, message) => {
|
|
10
|
+
if (!ctx.warned.has(message)) {
|
|
11
|
+
ctx.warned.add(message);
|
|
12
|
+
ctx.warnings.push(message);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var checkVarRefs = (text, path, ctx) => {
|
|
16
|
+
for (const match of text.matchAll(VAR_REF)) {
|
|
17
|
+
const name = match[1];
|
|
18
|
+
if (!ctx.schemaVars.has(name)) warnOnce(ctx, `Unknown variable {{${name}}} at ${path}: not a space schema variable or a page route param. Read plitzi://schema-variables, or use a route param from the page skeleton (routeParams).`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var checkStyleVarRefs = (text, path, ctx) => {
|
|
22
|
+
for (const match of text.matchAll(CSS_VAR)) {
|
|
23
|
+
const name = match[1];
|
|
24
|
+
if (!ctx.styleVars.has(name)) {
|
|
25
|
+
const tokens = [...ctx.styleVars];
|
|
26
|
+
warnOnce(ctx, `Unknown style variable var(--${name}) at ${path}: not a design token in this space. ${tokens.length > 0 ? `Available tokens: ${tokens.slice(0, 30).join(", ")}${tokens.length > 30 ? ", …" : ""}.` : "Read plitzi://style-variables for the valid token names."}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var checkObservedName = (value, observed, kind, resource, path, ctx) => {
|
|
31
|
+
if (!value || observed.size === 0 || observed.has(value)) return;
|
|
32
|
+
warnOnce(ctx, `${kind} "${value}" at ${path} was not seen in this space. Verify against ${resource}; it may still be valid.`);
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { RAW_CODE_TYPES, checkObservedName, checkStyleVarRefs, checkVarRefs, warnOnce };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { compoundLonghands, expandShorthand, isCssProperty, suggestCssProperty } from "../../../catalogs/cssCatalog.js";
|
|
2
|
+
import { checkStyleVarRefs, checkVarRefs, warnOnce } from "./context.js";
|
|
3
|
+
//#region src/modules/mcp/tools/shared/validator/css.ts
|
|
4
|
+
var checkCss = (css, path, ctx) => {
|
|
5
|
+
if (!css) return;
|
|
6
|
+
const declared = {};
|
|
7
|
+
for (const [key, value] of Object.entries(css)) if (value !== null) declared[key] = value;
|
|
8
|
+
for (const [key, value] of Object.entries(expandShorthand(declared))) {
|
|
9
|
+
const longhands = compoundLonghands(key);
|
|
10
|
+
if (longhands) if (!isCssProperty(key)) ctx.errors.push({
|
|
11
|
+
path: `${path}.${key}`,
|
|
12
|
+
message: `Compound CSS shorthand "${key}" is not supported — write its atomic longhand properties`,
|
|
13
|
+
hint: `Use: ${longhands.join(", ")}. (Note: flex layout is display + flex-direction + flex-grow/shrink/basis, not "flex".)`,
|
|
14
|
+
validValues: longhands
|
|
15
|
+
});
|
|
16
|
+
else warnOnce(ctx, `CSS shorthand "${key}" at ${path}.${key} is accepted but stored as one compound value. Plitzi styling is atomic — prefer the longhands (${longhands.join(", ")}) so a breakpoint/state/variant can override each property independently.`);
|
|
17
|
+
else if (!isCssProperty(key)) {
|
|
18
|
+
const suggestion = suggestCssProperty(key);
|
|
19
|
+
ctx.errors.push({
|
|
20
|
+
path: `${path}.${key}`,
|
|
21
|
+
message: `Unknown CSS property "${key}"`,
|
|
22
|
+
hint: suggestion ? `Use the kebab-case key "${suggestion}"` : "Read plitzi://css-properties for the valid property keys"
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
checkStyleVarRefs(value, `${path}.${key}`, ctx);
|
|
27
|
+
checkVarRefs(value, `${path}.${key}`, ctx);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var checkSlotCss = (slot, path, ctx) => {
|
|
32
|
+
checkCss(slot.desktop, `${path}.desktop`, ctx);
|
|
33
|
+
checkCss(slot.tablet, `${path}.tablet`, ctx);
|
|
34
|
+
checkCss(slot.mobile, `${path}.mobile`, ctx);
|
|
35
|
+
for (const [state, dm] of Object.entries(slot.states ?? {})) {
|
|
36
|
+
checkCss(dm.desktop, `${path}.states.${state}.desktop`, ctx);
|
|
37
|
+
checkCss(dm.tablet, `${path}.states.${state}.tablet`, ctx);
|
|
38
|
+
checkCss(dm.mobile, `${path}.states.${state}.mobile`, ctx);
|
|
39
|
+
}
|
|
40
|
+
for (const [name, dm] of Object.entries(slot.variants ?? {})) {
|
|
41
|
+
checkCss(dm.desktop, `${path}.variants.${name}.desktop`, ctx);
|
|
42
|
+
checkCss(dm.tablet, `${path}.variants.${name}.tablet`, ctx);
|
|
43
|
+
checkCss(dm.mobile, `${path}.variants.${name}.mobile`, ctx);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { checkCss, checkSlotCss };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { definitionVariantNames } from "../../operations/style/translator.js";
|
|
2
|
+
import { RAW_CODE_TYPES, checkVarRefs, warnOnce } from "./context.js";
|
|
3
|
+
import { checkIdRef } from "./refs.js";
|
|
4
|
+
//#region src/modules/mcp/tools/shared/validator/elements.ts
|
|
5
|
+
var checkTypeProps = (type, props, path, ctx) => {
|
|
6
|
+
if (!props || RAW_CODE_TYPES.has(type)) return;
|
|
7
|
+
const meta = ctx.typeMeta.get(type);
|
|
8
|
+
const known = meta && meta.attributes.size > 0 ? meta.attributes : ctx.typeProps.get(type);
|
|
9
|
+
if (!known || known.size === 0) return;
|
|
10
|
+
const strict = meta?.custom === false;
|
|
11
|
+
for (const key of Object.keys(props)) {
|
|
12
|
+
if (key === "subType" || known.has(key)) continue;
|
|
13
|
+
if (strict) ctx.errors.push({
|
|
14
|
+
path,
|
|
15
|
+
message: `Type "${type}" has no attribute "${key}"`,
|
|
16
|
+
hint: `Valid attributes: ${[...known].sort().join(", ")}`,
|
|
17
|
+
validValues: [...known].sort()
|
|
18
|
+
});
|
|
19
|
+
else warnOnce(ctx, `Type "${type}" has no observed prop "${key}" at ${path} (known: ${[...known].sort().join(", ")}). It may still be valid — verify against plitzi://types.`);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var checkVariantApplication = (initialState, path, ctx) => {
|
|
23
|
+
for (const [cls, selectors] of Object.entries(initialState?.styleVariant ?? {})) {
|
|
24
|
+
const declared = definitionVariantNames(ctx.style, cls);
|
|
25
|
+
const batch = ctx.batchVariants.get(cls);
|
|
26
|
+
for (const [selector, variant] of Object.entries(selectors)) {
|
|
27
|
+
const names = Array.isArray(variant) ? variant : [variant];
|
|
28
|
+
for (const name of names) if (!((declared?.[selector]?.includes(name) ?? false) || (batch?.has(name) ?? false))) warnOnce(ctx, `Element applies variant "${name}" on class "${cls}" (${selector}) at ${path}, but that class defines no such variant${declared ? ` (declares: ${Object.entries(declared).map(([s, v]) => `${s}:${v.join("/")}`).join(", ")})` : ""}. Create it via upsertDefinition/patchDefinition "variants", or fix the name.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var checkElementProps = (element, path, ctx) => {
|
|
33
|
+
if (!element.props || RAW_CODE_TYPES.has(element.type)) return;
|
|
34
|
+
for (const [key, value] of Object.entries(element.props)) if (typeof value === "string") checkVarRefs(value, `${path}.props.${key}`, ctx);
|
|
35
|
+
checkTypeProps(element.type, element.props, path, ctx);
|
|
36
|
+
};
|
|
37
|
+
var checkElementInput = (element, path, ctx, seen) => {
|
|
38
|
+
checkIdRef(element.ref, `${path}.ref`, ctx);
|
|
39
|
+
if (seen.has(element.ref)) ctx.errors.push({
|
|
40
|
+
path: `${path}.ref`,
|
|
41
|
+
message: `Duplicate ref "${element.ref}" in this batch`,
|
|
42
|
+
hint: "Use a unique ref"
|
|
43
|
+
});
|
|
44
|
+
seen.add(element.ref);
|
|
45
|
+
if (!element.type) ctx.errors.push({
|
|
46
|
+
path: `${path}.type`,
|
|
47
|
+
message: "Element type is required",
|
|
48
|
+
hint: "Read plitzi://types for known types"
|
|
49
|
+
});
|
|
50
|
+
else if (!ctx.knownTypes.has(element.type)) ctx.warnings.push(`Type "${element.type}" was not seen in this space; ensure a plugin provides it (${path}.type).`);
|
|
51
|
+
checkElementProps(element, path, ctx);
|
|
52
|
+
element.children?.forEach((child, i) => checkElementInput(child, `${path}.children[${i}]`, ctx, seen));
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { checkElementInput, checkTypeProps, checkVariantApplication };
|