@setzkasten-cms/astro-admin 1.4.6 → 1.5.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/dist/api-routes/_auth-guard.d.ts +27 -3
- package/dist/api-routes/_auth-guard.js +5 -2
- package/dist/api-routes/_dev-session-secret.d.ts +8 -0
- package/dist/api-routes/_dev-session-secret.js +8 -0
- package/dist/api-routes/_github-token.js +1 -1
- package/dist/api-routes/_role-resolver.js +6 -3
- package/dist/api-routes/_session-secret.d.ts +19 -0
- package/dist/api-routes/_session-secret.js +7 -0
- package/dist/api-routes/_session-signing.d.ts +45 -0
- package/dist/api-routes/_session-signing.js +8 -0
- package/dist/api-routes/_webhook-dispatcher.js +4 -4
- package/dist/api-routes/asset-proxy.js +1 -1
- package/dist/api-routes/auth-callback.js +12 -5
- package/dist/api-routes/auth-logout.d.ts +4 -4
- package/dist/api-routes/auth-logout.js +8 -2
- package/dist/api-routes/auth-session.d.ts +6 -0
- package/dist/api-routes/auth-session.js +19 -19
- package/dist/api-routes/auth-setzkasten-login.js +14 -7
- package/dist/api-routes/catalog-add.js +59 -17
- package/dist/api-routes/catalog-export.js +14 -4
- package/dist/api-routes/config.d.ts +10 -3
- package/dist/api-routes/config.js +26 -4
- package/dist/api-routes/deploy-hook.js +8 -8
- package/dist/api-routes/editors.d.ts +1 -1
- package/dist/api-routes/editors.js +5 -2
- package/dist/api-routes/github-proxy.js +30 -8
- package/dist/api-routes/global-config.js +6 -3
- package/dist/api-routes/history-rollback.js +31 -14
- package/dist/api-routes/history-version.js +8 -6
- package/dist/api-routes/history.js +5 -2
- package/dist/api-routes/icons-local.js +1 -1
- package/dist/api-routes/init-add-section.js +113 -47
- package/dist/api-routes/init-apply.js +56 -42
- package/dist/api-routes/init-migrate.js +43 -36
- package/dist/api-routes/init-scan-page.d.ts +1 -1
- package/dist/api-routes/init-scan-page.js +59 -13
- package/dist/api-routes/init-scan.js +22 -7
- package/dist/api-routes/migrate-to-multi.js +5 -2
- package/dist/api-routes/pages.js +15 -4
- package/dist/api-routes/section-add.js +68 -16
- package/dist/api-routes/section-commit-pending.js +70 -22
- package/dist/api-routes/section-delete.js +49 -14
- package/dist/api-routes/section-duplicate.js +65 -16
- package/dist/api-routes/section-prepare-copy.js +15 -2
- package/dist/api-routes/section-prepare.js +25 -4
- package/dist/api-routes/setup-github-app-bounce.js +15 -1
- package/dist/api-routes/setup-github-app-branches.js +9 -6
- package/dist/api-routes/setup-github-app-callback.js +24 -1
- package/dist/api-routes/setup-github-app-credentials.d.ts +27 -0
- package/dist/api-routes/setup-github-app-credentials.js +43 -0
- package/dist/api-routes/setup-github-app-installed.js +22 -1
- package/dist/api-routes/setup-github-app-repos.js +5 -2
- package/dist/api-routes/setup-github-app.d.ts +4 -0
- package/dist/api-routes/setup-github-app.js +19 -2
- package/dist/api-routes/updater-register.js +7 -1
- package/dist/api-routes/webhooks-status.js +5 -2
- package/dist/api-routes/webhooks-test.js +9 -8
- package/dist/api-routes/webhooks.js +12 -14
- package/dist/api-routes/websites-add.js +5 -2
- package/dist/api-routes/websites-remove.js +5 -2
- package/dist/{chunk-ZQDGGWJP.js → chunk-5KMGSFCZ.js} +2 -2
- package/dist/{chunk-Q3N336KR.js → chunk-CDXCYYQR.js} +29 -24
- package/dist/{chunk-NKDATSPA.js → chunk-DP6RTINQ.js} +1 -1
- package/dist/chunk-KENFINT4.js +76 -0
- package/dist/chunk-ONP6BRZO.js +47 -0
- package/dist/{chunk-INIWFKQ3.js → chunk-Q5HV47DW.js} +33 -19
- package/dist/chunk-QVCW6EF3.js +26 -0
- package/dist/{chunk-TD76R3A6.js → chunk-UHI6323G.js} +293 -174
- package/dist/{chunk-AM4DZXXM.js → chunk-UJAFZEX2.js} +76 -9
- package/package.json +12 -6
- package/src/api-routes/__tests__/_session-signing.test.ts +114 -0
- package/src/api-routes/__tests__/_session-test-helper.ts +27 -0
- package/src/api-routes/__tests__/add-section-helpers.test.ts +59 -25
- package/src/api-routes/__tests__/auth-guard.test.ts +46 -7
- package/src/api-routes/__tests__/catalog-api.test.ts +14 -6
- package/src/api-routes/__tests__/commit-trailers.test.ts +5 -5
- package/src/api-routes/__tests__/deferred-operations.test.ts +9 -12
- package/src/api-routes/__tests__/deploy-hook.test.ts +3 -8
- package/src/api-routes/__tests__/feature-gate.test.ts +1 -1
- package/src/api-routes/__tests__/github-cache.test.ts +1 -1
- package/src/api-routes/__tests__/github-token.test.ts +1 -1
- package/src/api-routes/__tests__/global-config-theme.test.ts +4 -4
- package/src/api-routes/__tests__/history-rollback.test.ts +6 -3
- package/src/api-routes/__tests__/history.test.ts +9 -6
- package/src/api-routes/__tests__/init-scan-page-resolve-config.test.ts +11 -3
- package/src/api-routes/__tests__/migrate-to-multi.test.ts +5 -1
- package/src/api-routes/__tests__/pages-meta-store.test.ts +10 -5
- package/src/api-routes/__tests__/pages.test.ts +7 -2
- package/src/api-routes/__tests__/patch-page-file.test.ts +71 -19
- package/src/api-routes/__tests__/route-registry.test.ts +11 -18
- package/src/api-routes/__tests__/scan-page-helpers.test.ts +13 -10
- package/src/api-routes/__tests__/section-management.test.ts +28 -28
- package/src/api-routes/__tests__/setup-github-app-callback.test.ts +58 -16
- package/src/api-routes/__tests__/setup-github-app-repos.test.ts +4 -5
- package/src/api-routes/__tests__/setup-github-app.test.ts +27 -7
- package/src/api-routes/__tests__/storage-config-for-request.test.ts +83 -0
- package/src/api-routes/__tests__/updater-register.test.ts +230 -0
- package/src/api-routes/__tests__/webhook-signing.test.ts +1 -1
- package/src/api-routes/__tests__/webhooks.test.ts +19 -7
- package/src/api-routes/__tests__/websites-add.test.ts +2 -1
- package/src/api-routes/__tests__/websites-remove.test.ts +2 -1
- package/src/api-routes/_auth-guard.ts +47 -15
- package/src/api-routes/_commit-trailers.ts +3 -2
- package/src/api-routes/_dev-session-secret.ts +79 -0
- package/src/api-routes/_github-token.ts +1 -1
- package/src/api-routes/_pages-meta-store.ts +2 -2
- package/src/api-routes/_role-resolver.ts +7 -5
- package/src/api-routes/_session-secret.ts +46 -0
- package/src/api-routes/_session-signing.ts +135 -0
- package/src/api-routes/_vercel-origin.ts +2 -6
- package/src/api-routes/_webhook-dispatcher.ts +12 -16
- package/src/api-routes/_website-resolver.ts +3 -10
- package/src/api-routes/auth-callback.ts +9 -5
- package/src/api-routes/auth-login.ts +5 -3
- package/src/api-routes/auth-logout.ts +18 -1
- package/src/api-routes/auth-session.ts +13 -21
- package/src/api-routes/auth-setzkasten-login.ts +12 -9
- package/src/api-routes/catalog-add.ts +89 -31
- package/src/api-routes/catalog-export.ts +30 -10
- package/src/api-routes/config.ts +39 -6
- package/src/api-routes/deploy-hook.ts +13 -11
- package/src/api-routes/editors.ts +33 -22
- package/src/api-routes/github-proxy.ts +25 -11
- package/src/api-routes/global-config.ts +103 -18
- package/src/api-routes/history-rollback.ts +41 -14
- package/src/api-routes/history-version.ts +5 -6
- package/src/api-routes/history.ts +3 -3
- package/src/api-routes/icons-local.ts +2 -2
- package/src/api-routes/init-add-section.ts +174 -79
- package/src/api-routes/init-apply.ts +71 -56
- package/src/api-routes/init-migrate.ts +54 -48
- package/src/api-routes/init-scan-page.ts +77 -30
- package/src/api-routes/init-scan.ts +19 -11
- package/src/api-routes/pages.ts +16 -11
- package/src/api-routes/section-add.ts +98 -27
- package/src/api-routes/section-commit-pending.ts +87 -34
- package/src/api-routes/section-delete.ts +76 -27
- package/src/api-routes/section-duplicate.ts +95 -28
- package/src/api-routes/section-management.ts +3 -7
- package/src/api-routes/section-prepare-copy.ts +29 -8
- package/src/api-routes/section-prepare.ts +38 -10
- package/src/api-routes/setup-github-app-bounce.ts +7 -1
- package/src/api-routes/setup-github-app-branches.ts +6 -7
- package/src/api-routes/setup-github-app-callback.ts +18 -1
- package/src/api-routes/setup-github-app-credentials.ts +55 -0
- package/src/api-routes/setup-github-app-installed.ts +12 -1
- package/src/api-routes/setup-github-app-repos.ts +2 -3
- package/src/api-routes/setup-github-app.ts +14 -5
- package/src/api-routes/updater-check.ts +6 -4
- package/src/api-routes/updater-register.ts +34 -20
- package/src/api-routes/updater-transfer.ts +8 -6
- package/src/api-routes/updater-unbind.ts +14 -10
- package/src/api-routes/webhooks-test.ts +9 -11
- package/src/api-routes/webhooks.ts +15 -19
- package/src/init/__tests__/page-level.test.ts +279 -105
- package/src/init/__tests__/page-list-coverage.test.ts +70 -70
- package/src/init/__tests__/patcher-child-component.test.ts +12 -3
- package/src/init/__tests__/patcher-edge-cases.test.ts +47 -23
- package/src/init/__tests__/patcher-mixed-content-wrapper.test.ts +16 -6
- package/src/init/__tests__/patcher-page-mode.test.ts +30 -20
- package/src/init/__tests__/section-pipeline.test.ts +53 -19
- package/src/init/astro-config-patcher.ts +4 -18
- package/src/init/astro-detector.ts +2 -7
- package/src/init/astro-section-analyzer-v2.ts +475 -193
- package/src/init/field-label-enricher.ts +6 -6
- package/src/init/template-patcher-v2.ts +218 -97
|
@@ -69,10 +69,7 @@ function deriveSectionKey(componentName) {
|
|
|
69
69
|
function resolveImportPath(importPath, fromFile, allFiles, projectRoot) {
|
|
70
70
|
if (importPath.startsWith("@/") || importPath.startsWith("~/")) {
|
|
71
71
|
const aliasPath = importPath.replace(/^[@~]\//, "");
|
|
72
|
-
const candidates = [
|
|
73
|
-
`${projectRoot}/src/${aliasPath}`,
|
|
74
|
-
`${projectRoot}/src/${aliasPath}.astro`
|
|
75
|
-
];
|
|
72
|
+
const candidates = [`${projectRoot}/src/${aliasPath}`, `${projectRoot}/src/${aliasPath}.astro`];
|
|
76
73
|
for (const candidate of candidates) {
|
|
77
74
|
if (allFiles.some((f) => f.path === candidate)) return candidate;
|
|
78
75
|
}
|
|
@@ -170,7 +167,10 @@ async function analyzeAstroSection(source, sectionKey, componentName, componentP
|
|
|
170
167
|
field.defaultValue = extractFrontmatterValue(frontmatter, field.key);
|
|
171
168
|
}
|
|
172
169
|
}
|
|
173
|
-
const { fields: templateFields, repeatedGroups } = await extractTemplateFields(
|
|
170
|
+
const { fields: templateFields, repeatedGroups } = await extractTemplateFields(
|
|
171
|
+
template,
|
|
172
|
+
frontmatter
|
|
173
|
+
);
|
|
174
174
|
const posAdjust = templateOffset;
|
|
175
175
|
for (const group of repeatedGroups) {
|
|
176
176
|
for (const inst of group.instances) {
|
|
@@ -206,15 +206,14 @@ async function analyzeAstroSection(source, sectionKey, componentName, componentP
|
|
|
206
206
|
field._pos = usageMatch.index;
|
|
207
207
|
} else {
|
|
208
208
|
const mapUsage = template.indexOf(`${field.key}.map(`);
|
|
209
|
-
field._pos = mapUsage !== -1 ? mapUsage :
|
|
209
|
+
field._pos = mapUsage !== -1 ? mapUsage : Number.POSITIVE_INFINITY;
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
const existingKeys = new Set(variableFields.map((f) => f.key));
|
|
213
|
-
const allFields = [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
allFields.sort((a, b) => (a._pos ?? Infinity) - (b._pos ?? Infinity));
|
|
213
|
+
const allFields = [...variableFields, ...templateFields.filter((f) => !existingKeys.has(f.key))];
|
|
214
|
+
allFields.sort(
|
|
215
|
+
(a, b) => (a._pos ?? Number.POSITIVE_INFINITY) - (b._pos ?? Number.POSITIVE_INFINITY)
|
|
216
|
+
);
|
|
218
217
|
const fields = allFields.map(({ ...field }) => {
|
|
219
218
|
delete field._pos;
|
|
220
219
|
return field;
|
|
@@ -399,10 +398,10 @@ function convertAstPositions(node, b2c) {
|
|
|
399
398
|
}
|
|
400
399
|
var WRAPPER_OFFSET = 8;
|
|
401
400
|
function nodeOffset(node) {
|
|
402
|
-
return (node.position?.start?.offset ??
|
|
401
|
+
return (node.position?.start?.offset ?? Number.POSITIVE_INFINITY) - WRAPPER_OFFSET;
|
|
403
402
|
}
|
|
404
403
|
function nodeEnd(node) {
|
|
405
|
-
return (node.position?.end?.offset ??
|
|
404
|
+
return (node.position?.end?.offset ?? Number.POSITIVE_INFINITY) - WRAPPER_OFFSET;
|
|
406
405
|
}
|
|
407
406
|
function getClassValue(node) {
|
|
408
407
|
if (!node.attributes) return "";
|
|
@@ -547,8 +546,10 @@ function inferInnerFieldType(name) {
|
|
|
547
546
|
if (/icon/.test(n)) return "icon";
|
|
548
547
|
if (/image|img|photo|avatar|logo|thumbnail|src/.test(n)) return "image";
|
|
549
548
|
if (/color|colour/.test(n)) return "color";
|
|
550
|
-
if (/count|amount|number|quantity|total|rating|score|percent|order|index|size|width|height/.test(n))
|
|
551
|
-
|
|
549
|
+
if (/count|amount|number|quantity|total|rating|score|percent|order|index|size|width|height/.test(n))
|
|
550
|
+
return "number";
|
|
551
|
+
if (/^is[A-Z]/.test(name) || /^has[A-Z]/.test(name) || /enabled|disabled|visible|hidden|active|checked|selected|highlight|accent|featured/.test(n))
|
|
552
|
+
return "boolean";
|
|
552
553
|
return "text";
|
|
553
554
|
}
|
|
554
555
|
function extractInlineArrayValues(arrayContent, isObjectArray, isStringArray) {
|
|
@@ -682,7 +683,7 @@ ${template}`;
|
|
|
682
683
|
const keyMatch = keyRegex.exec(template);
|
|
683
684
|
if (keyMatch) finalPos = keyMatch.index;
|
|
684
685
|
}
|
|
685
|
-
fields.push({ ...field, _pos: finalPos === -1 ?
|
|
686
|
+
fields.push({ ...field, _pos: finalPos === -1 ? Number.POSITIVE_INFINITY : finalPos });
|
|
686
687
|
}
|
|
687
688
|
}
|
|
688
689
|
function numberedKey(base, count) {
|
|
@@ -772,26 +773,34 @@ ${template}`;
|
|
|
772
773
|
items.push(m[1] ?? m[2] ?? m[3] ?? "");
|
|
773
774
|
}
|
|
774
775
|
const hasFormatting = items.some((s) => /<[a-z]/.test(s));
|
|
775
|
-
addField(
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
776
|
+
addField(
|
|
777
|
+
{
|
|
778
|
+
key: fieldKey,
|
|
779
|
+
type: "array",
|
|
780
|
+
label: camelToLabel(fieldKey),
|
|
781
|
+
confidence: "high",
|
|
782
|
+
defaultValue: items.length > 0 ? items : void 0,
|
|
783
|
+
options: {
|
|
784
|
+
arrayItem: { type: "text", ...hasFormatting ? { formatting: true } : {} }
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
nodeOffset(node)
|
|
788
|
+
);
|
|
783
789
|
} else {
|
|
784
790
|
const strFallback = exprCode.match(/\?\?\s*(?:`([\s\S]*?)`|'([^']*)'|"([^"]*)")/);
|
|
785
791
|
const defaultValue = strFallback ? (strFallback[1] ?? strFallback[2] ?? strFallback[3] ?? "").trim() : void 0;
|
|
786
792
|
const hasHtml = defaultValue ? /<[a-z]/.test(defaultValue) : false;
|
|
787
|
-
addField(
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
793
|
+
addField(
|
|
794
|
+
{
|
|
795
|
+
key: fieldKey,
|
|
796
|
+
type: "text",
|
|
797
|
+
label: camelToLabel(fieldKey),
|
|
798
|
+
confidence: "high",
|
|
799
|
+
...defaultValue ? { defaultValue } : {},
|
|
800
|
+
...hasHtml ? { options: { formatting: true } } : {}
|
|
801
|
+
},
|
|
802
|
+
nodeOffset(node)
|
|
803
|
+
);
|
|
795
804
|
}
|
|
796
805
|
cmsBoundOffsets.add(nodeOffset(node));
|
|
797
806
|
}
|
|
@@ -800,7 +809,9 @@ ${template}`;
|
|
|
800
809
|
if (node.type !== "element" && node.type !== "component") return;
|
|
801
810
|
for (const attr of node.attributes ?? []) {
|
|
802
811
|
if (attr.kind !== "expression") continue;
|
|
803
|
-
const cmsAttrMatch = attr.value.match(
|
|
812
|
+
const cmsAttrMatch = attr.value.match(
|
|
813
|
+
/^\s*\w+\?\.\s*(\w+)\s*\?\?\s*(?:`([\s\S]*?)`|'([^']*)'|"([^"]*)")/
|
|
814
|
+
);
|
|
804
815
|
if (cmsAttrMatch) {
|
|
805
816
|
const fieldKey = cmsAttrMatch[1];
|
|
806
817
|
const fallback = (cmsAttrMatch[2] ?? cmsAttrMatch[3] ?? cmsAttrMatch[4] ?? "").trim();
|
|
@@ -808,14 +819,17 @@ ${template}`;
|
|
|
808
819
|
const isSetHtml = attr.name === "set:html";
|
|
809
820
|
const fallbackHasHtml = fallback ? /<[a-z]/.test(fallback) : false;
|
|
810
821
|
const hasHtml = fallbackHasHtml || isSetHtml && !fallback;
|
|
811
|
-
addField(
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
822
|
+
addField(
|
|
823
|
+
{
|
|
824
|
+
key: fieldKey,
|
|
825
|
+
type: "text",
|
|
826
|
+
label: camelToLabel(fieldKey),
|
|
827
|
+
confidence: "high",
|
|
828
|
+
...fallback ? { defaultValue: fallback } : {},
|
|
829
|
+
...hasHtml ? { options: { formatting: true } } : {}
|
|
830
|
+
},
|
|
831
|
+
pos
|
|
832
|
+
);
|
|
819
833
|
cmsBoundOffsets.add(nodeOffset(node));
|
|
820
834
|
}
|
|
821
835
|
}
|
|
@@ -835,10 +849,21 @@ ${template}`;
|
|
|
835
849
|
if (!/uppercase|tracking-widest/.test(classVal)) return;
|
|
836
850
|
const text = extractTextContent(node, true).trim();
|
|
837
851
|
if (text.length >= 2 && text.length <= 80) {
|
|
838
|
-
addField(
|
|
852
|
+
addField(
|
|
853
|
+
{
|
|
854
|
+
key: "overline",
|
|
855
|
+
type: "text",
|
|
856
|
+
label: "Overline",
|
|
857
|
+
confidence: "medium",
|
|
858
|
+
defaultValue: text
|
|
859
|
+
},
|
|
860
|
+
nodeOffset(node)
|
|
861
|
+
);
|
|
839
862
|
}
|
|
840
863
|
});
|
|
841
|
-
let headingCount = Array.from(usedKeys).filter(
|
|
864
|
+
let headingCount = Array.from(usedKeys).filter(
|
|
865
|
+
(k) => k === "heading" || /^heading\d+$/.test(k)
|
|
866
|
+
).length;
|
|
842
867
|
walkAst(ast, (node) => {
|
|
843
868
|
if (node.type !== "element") return;
|
|
844
869
|
if (!/^h[1-6]$/.test(node.name ?? "")) return;
|
|
@@ -848,17 +873,22 @@ ${template}`;
|
|
|
848
873
|
headingCount++;
|
|
849
874
|
const headingOpts = { required: true };
|
|
850
875
|
if (hasInlineFormatting(node)) headingOpts.formatting = true;
|
|
851
|
-
addField(
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
876
|
+
addField(
|
|
877
|
+
{
|
|
878
|
+
key: numberedKey("heading", headingCount),
|
|
879
|
+
type: "text",
|
|
880
|
+
label: numberedLabel("Heading", headingCount),
|
|
881
|
+
confidence: "high",
|
|
882
|
+
defaultValue: text,
|
|
883
|
+
options: headingOpts
|
|
884
|
+
},
|
|
885
|
+
nodeOffset(node)
|
|
886
|
+
);
|
|
859
887
|
}
|
|
860
888
|
});
|
|
861
|
-
let descCount = Array.from(usedKeys).filter(
|
|
889
|
+
let descCount = Array.from(usedKeys).filter(
|
|
890
|
+
(k) => k === "description" || /^description\d+$/.test(k)
|
|
891
|
+
).length;
|
|
862
892
|
walkAst(ast, (node) => {
|
|
863
893
|
if (node.type !== "element") return;
|
|
864
894
|
if (node.name !== "p" && node.name !== "div") return;
|
|
@@ -866,16 +896,20 @@ ${template}`;
|
|
|
866
896
|
const classVal = getClassValue(node);
|
|
867
897
|
const serialized = serializeNode(node);
|
|
868
898
|
if (/uppercase|tracking-widest/.test(classVal) && serialized.length < 250) return;
|
|
869
|
-
if (/text-2xl|text-3xl|text-\[11px\]|text-\[10px\]|text-\[9px\]|text-\[8px\]/.test(classVal))
|
|
899
|
+
if (/text-2xl|text-3xl|text-\[11px\]|text-\[10px\]|text-\[9px\]|text-\[8px\]/.test(classVal))
|
|
900
|
+
return;
|
|
870
901
|
if (node.name === "div" && (containsElement(node, "a") || containsElement(node, "button"))) {
|
|
871
902
|
const hasMixedText = (node.children ?? []).some(
|
|
872
903
|
(c) => c.type === "text" && (c.value ?? "").trim().length > 0
|
|
873
904
|
);
|
|
874
905
|
if (!hasMixedText) return;
|
|
875
906
|
}
|
|
876
|
-
if (node.name === "div" && ["h1", "h2", "h3", "h4", "h5", "h6"].some((h) => containsElement(node, h)))
|
|
907
|
+
if (node.name === "div" && ["h1", "h2", "h3", "h4", "h5", "h6"].some((h) => containsElement(node, h)))
|
|
908
|
+
return;
|
|
877
909
|
if (node.name === "div") {
|
|
878
|
-
const contentChildren = (node.children ?? []).filter(
|
|
910
|
+
const contentChildren = (node.children ?? []).filter(
|
|
911
|
+
(c) => c.type !== "text" || (c.value ?? "").trim().length > 0
|
|
912
|
+
);
|
|
879
913
|
const hasOnlyElementChildren = contentChildren.length > 0 && contentChildren.every((c) => c.type === "element" || c.type === "component");
|
|
880
914
|
if (hasOnlyElementChildren) return;
|
|
881
915
|
}
|
|
@@ -884,14 +918,17 @@ ${template}`;
|
|
|
884
918
|
descCount++;
|
|
885
919
|
const descOpts = { multiline: true };
|
|
886
920
|
if (hasInlineFormatting(node)) descOpts.formatting = true;
|
|
887
|
-
addField(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
921
|
+
addField(
|
|
922
|
+
{
|
|
923
|
+
key: numberedKey("description", descCount),
|
|
924
|
+
type: "text",
|
|
925
|
+
label: numberedLabel("Beschreibung", descCount),
|
|
926
|
+
confidence: "medium",
|
|
927
|
+
defaultValue: text,
|
|
928
|
+
options: descOpts
|
|
929
|
+
},
|
|
930
|
+
nodeOffset(node)
|
|
931
|
+
);
|
|
895
932
|
});
|
|
896
933
|
let richCount = 0;
|
|
897
934
|
walkAst(ast, (node) => {
|
|
@@ -905,14 +942,17 @@ ${template}`;
|
|
|
905
942
|
const strMatch = expr.match(/['"]([^'"]+)['"]/);
|
|
906
943
|
const fallbackMatch = expr.match(/\?\?\s*['"]([^'"]+)['"]/);
|
|
907
944
|
const value = fallbackMatch?.[1] ?? strMatch?.[1] ?? "";
|
|
908
|
-
addField(
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
945
|
+
addField(
|
|
946
|
+
{
|
|
947
|
+
key: numberedKey("richText", richCount),
|
|
948
|
+
type: "text",
|
|
949
|
+
label: numberedLabel("Rich Text", richCount),
|
|
950
|
+
confidence: "high",
|
|
951
|
+
defaultValue: value,
|
|
952
|
+
options: { multiline: true, formatting: true }
|
|
953
|
+
},
|
|
954
|
+
nodeOffset(node)
|
|
955
|
+
);
|
|
916
956
|
}
|
|
917
957
|
});
|
|
918
958
|
let ctaCount = 0;
|
|
@@ -925,13 +965,16 @@ ${template}`;
|
|
|
925
965
|
const text = extractTextContent(node, true).replace(/\s+/g, " ").trim();
|
|
926
966
|
if (text.length >= 2 && text.length <= 60) {
|
|
927
967
|
ctaCount++;
|
|
928
|
-
addField(
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
968
|
+
addField(
|
|
969
|
+
{
|
|
970
|
+
key: numberedKey("ctaText", ctaCount),
|
|
971
|
+
type: "text",
|
|
972
|
+
label: numberedLabel("Button Text", ctaCount),
|
|
973
|
+
confidence: "medium",
|
|
974
|
+
defaultValue: text
|
|
975
|
+
},
|
|
976
|
+
nodeOffset(node)
|
|
977
|
+
);
|
|
935
978
|
}
|
|
936
979
|
});
|
|
937
980
|
let linkCount = 0;
|
|
@@ -953,13 +996,16 @@ ${template}`;
|
|
|
953
996
|
if (!href) return;
|
|
954
997
|
if (href.startsWith("#") || href.startsWith("javascript:")) return;
|
|
955
998
|
linkCount++;
|
|
956
|
-
addField(
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
999
|
+
addField(
|
|
1000
|
+
{
|
|
1001
|
+
key: numberedKey("ctaLink", linkCount),
|
|
1002
|
+
type: "text",
|
|
1003
|
+
label: numberedLabel("Button Link", linkCount),
|
|
1004
|
+
confidence: "medium",
|
|
1005
|
+
defaultValue: href
|
|
1006
|
+
},
|
|
1007
|
+
nodeOffset(node)
|
|
1008
|
+
);
|
|
963
1009
|
});
|
|
964
1010
|
let imgCount = 0;
|
|
965
1011
|
let altCount = 0;
|
|
@@ -978,26 +1024,32 @@ ${template}`;
|
|
|
978
1024
|
}
|
|
979
1025
|
if (src) {
|
|
980
1026
|
imgCount++;
|
|
981
|
-
addField(
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1027
|
+
addField(
|
|
1028
|
+
{
|
|
1029
|
+
key: numberedKey("image", imgCount),
|
|
1030
|
+
type: "image",
|
|
1031
|
+
label: numberedLabel("Bild", imgCount),
|
|
1032
|
+
confidence: "high",
|
|
1033
|
+
defaultValue: { path: src.trim(), alt: "" }
|
|
1034
|
+
},
|
|
1035
|
+
nodeOffset(node)
|
|
1036
|
+
);
|
|
988
1037
|
}
|
|
989
1038
|
}
|
|
990
1039
|
if (tagName === "img" || tagName === "Image") {
|
|
991
1040
|
const altAttr = getAttr(node, "alt");
|
|
992
1041
|
if (altAttr && altAttr.kind === "quoted" && altAttr.value.trim().length >= 2) {
|
|
993
1042
|
altCount++;
|
|
994
|
-
addField(
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1043
|
+
addField(
|
|
1044
|
+
{
|
|
1045
|
+
key: numberedKey("imageAlt", altCount),
|
|
1046
|
+
type: "text",
|
|
1047
|
+
label: numberedLabel("Bild Alt-Text", altCount),
|
|
1048
|
+
confidence: "medium",
|
|
1049
|
+
defaultValue: altAttr.value.trim()
|
|
1050
|
+
},
|
|
1051
|
+
nodeOffset(node)
|
|
1052
|
+
);
|
|
1001
1053
|
}
|
|
1002
1054
|
}
|
|
1003
1055
|
});
|
|
@@ -1009,12 +1061,15 @@ ${template}`;
|
|
|
1009
1061
|
if (svgSource.length < 100) return;
|
|
1010
1062
|
if (parentNode && (parentNode.name === "a" || parentNode.name === "button")) return;
|
|
1011
1063
|
iconCount++;
|
|
1012
|
-
addField(
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1064
|
+
addField(
|
|
1065
|
+
{
|
|
1066
|
+
key: numberedKey("icon", iconCount),
|
|
1067
|
+
type: "icon",
|
|
1068
|
+
label: numberedLabel("Icon", iconCount),
|
|
1069
|
+
confidence: "low"
|
|
1070
|
+
},
|
|
1071
|
+
nodeOffset(node)
|
|
1072
|
+
);
|
|
1018
1073
|
});
|
|
1019
1074
|
let foundIconProp = false;
|
|
1020
1075
|
walkAst(ast, (node) => {
|
|
@@ -1031,7 +1086,9 @@ ${template}`;
|
|
|
1031
1086
|
walkAst(ast, (node) => {
|
|
1032
1087
|
if (node.type !== "expression") return;
|
|
1033
1088
|
const exprCode = (node.children ?? []).map((c) => c.value ?? "").join("");
|
|
1034
|
-
const inlineArrayMatch = exprCode.match(
|
|
1089
|
+
const inlineArrayMatch = exprCode.match(
|
|
1090
|
+
/^\s*\[([\s\S]*?)\]\s*\.map\s*\(\s*\(?\s*(\{[^}]*\}|\w+)/
|
|
1091
|
+
);
|
|
1035
1092
|
if (!inlineArrayMatch) return;
|
|
1036
1093
|
arrayCount++;
|
|
1037
1094
|
const arrayContent = inlineArrayMatch[1];
|
|
@@ -1064,23 +1121,29 @@ ${template}`;
|
|
|
1064
1121
|
label: camelToLabel(prop),
|
|
1065
1122
|
confidence: "medium"
|
|
1066
1123
|
}));
|
|
1067
|
-
addField(
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1124
|
+
addField(
|
|
1125
|
+
{
|
|
1126
|
+
key: numberedKey("items", arrayCount),
|
|
1127
|
+
type: "array",
|
|
1128
|
+
label: numberedLabel("Liste", arrayCount),
|
|
1129
|
+
confidence: "high",
|
|
1130
|
+
defaultValue: arrayDefaultValue,
|
|
1131
|
+
options: { arrayItem: { type: "object", fields: innerFields } }
|
|
1132
|
+
},
|
|
1133
|
+
nodeOffset(node)
|
|
1134
|
+
);
|
|
1075
1135
|
} else {
|
|
1076
|
-
addField(
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1136
|
+
addField(
|
|
1137
|
+
{
|
|
1138
|
+
key: numberedKey("items", arrayCount),
|
|
1139
|
+
type: "array",
|
|
1140
|
+
label: numberedLabel("Liste", arrayCount),
|
|
1141
|
+
confidence: "high",
|
|
1142
|
+
defaultValue: arrayDefaultValue,
|
|
1143
|
+
options: { arrayItem: { type: "text" } }
|
|
1144
|
+
},
|
|
1145
|
+
nodeOffset(node)
|
|
1146
|
+
);
|
|
1084
1147
|
}
|
|
1085
1148
|
});
|
|
1086
1149
|
let staticListCount = 0;
|
|
@@ -1144,14 +1207,19 @@ ${template}`;
|
|
|
1144
1207
|
}
|
|
1145
1208
|
if (listItems.length < 1) return;
|
|
1146
1209
|
staticListCount++;
|
|
1147
|
-
addField(
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1210
|
+
addField(
|
|
1211
|
+
{
|
|
1212
|
+
key: numberedKey("items", arrayCount + staticListCount),
|
|
1213
|
+
type: "array",
|
|
1214
|
+
label: numberedLabel("Liste", arrayCount + staticListCount),
|
|
1215
|
+
confidence: "high",
|
|
1216
|
+
defaultValue: listItems,
|
|
1217
|
+
options: {
|
|
1218
|
+
arrayItem: { type: "text", ...listHasFormatting ? { formatting: true } : {} }
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
nodeOffset(node)
|
|
1222
|
+
);
|
|
1155
1223
|
});
|
|
1156
1224
|
const componentCounts = /* @__PURE__ */ new Map();
|
|
1157
1225
|
walkAst(ast, (node) => {
|
|
@@ -1166,32 +1234,47 @@ ${template}`;
|
|
|
1166
1234
|
if (attr.kind === "quoted") {
|
|
1167
1235
|
const propName = attr.name;
|
|
1168
1236
|
const propValue = attr.value;
|
|
1169
|
-
if (/^(class|className|id|style|type|role|width|height|viewBox|fill|stroke|xmlns|d|cx|cy|r|rx|ry|x|y|x1|y1|x2|y2)$/.test(
|
|
1170
|
-
|
|
1237
|
+
if (/^(class|className|id|style|type|role|width|height|viewBox|fill|stroke|xmlns|d|cx|cy|r|rx|ry|x|y|x1|y1|x2|y2)$/.test(
|
|
1238
|
+
propName
|
|
1239
|
+
))
|
|
1240
|
+
continue;
|
|
1241
|
+
if (/^(lang|language|filename|file|format|variant|size|loading|decoding|transition|client:.*)$/.test(
|
|
1242
|
+
propName
|
|
1243
|
+
))
|
|
1244
|
+
continue;
|
|
1171
1245
|
if (/^(aria-|data-)/.test(propName)) continue;
|
|
1172
1246
|
if (propValue.length < 2) continue;
|
|
1173
1247
|
if (propValue === "true" || propValue === "false" || /^\d+$/.test(propValue)) continue;
|
|
1174
1248
|
if (propValue.includes("/") && !propValue.includes(" ")) continue;
|
|
1175
|
-
addField(
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1249
|
+
addField(
|
|
1250
|
+
{
|
|
1251
|
+
key: propName,
|
|
1252
|
+
type: propName === "icon" ? "icon" : propName === "src" ? "image" : "text",
|
|
1253
|
+
label: camelToLabel(propName),
|
|
1254
|
+
confidence: "medium",
|
|
1255
|
+
defaultValue: propValue
|
|
1256
|
+
},
|
|
1257
|
+
nodeOffset(node)
|
|
1258
|
+
);
|
|
1182
1259
|
} else if (attr.kind === "expression") {
|
|
1183
1260
|
const propName = attr.name;
|
|
1184
|
-
if (/^(class|className|id|style|type|role|lang|language|filename|file|format|variant|size|loading|decoding)$/.test(
|
|
1261
|
+
if (/^(class|className|id|style|type|role|lang|language|filename|file|format|variant|size|loading|decoding)$/.test(
|
|
1262
|
+
propName
|
|
1263
|
+
))
|
|
1264
|
+
continue;
|
|
1185
1265
|
if (/^\s*\w+\s*$/.test(attr.value)) continue;
|
|
1186
1266
|
const fallbackMatch = attr.value.match(/\?\?\s*['"]([^'"]+)['"]/);
|
|
1187
1267
|
if (fallbackMatch) {
|
|
1188
|
-
addField(
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1268
|
+
addField(
|
|
1269
|
+
{
|
|
1270
|
+
key: propName,
|
|
1271
|
+
type: propName === "icon" ? "icon" : propName === "src" ? "image" : "text",
|
|
1272
|
+
label: camelToLabel(propName),
|
|
1273
|
+
confidence: "medium",
|
|
1274
|
+
defaultValue: fallbackMatch[1]
|
|
1275
|
+
},
|
|
1276
|
+
nodeOffset(node)
|
|
1277
|
+
);
|
|
1195
1278
|
}
|
|
1196
1279
|
}
|
|
1197
1280
|
}
|
|
@@ -1232,23 +1315,43 @@ ${template}`;
|
|
|
1232
1315
|
if (Object.keys(item).length > 0) instanceValues.push(item);
|
|
1233
1316
|
}
|
|
1234
1317
|
if (allProps.size > 0) {
|
|
1235
|
-
const cardKey = compName.replace(
|
|
1318
|
+
const cardKey = compName.replace(
|
|
1319
|
+
/([A-Z])/g,
|
|
1320
|
+
(_m, c, i) => i === 0 ? c.toLowerCase() : "_" + c.toLowerCase()
|
|
1321
|
+
).replace(/_/g, "") + "s";
|
|
1236
1322
|
if (!usedKeys.has(cardKey)) {
|
|
1237
1323
|
const innerFields = [...allProps].map((p) => {
|
|
1238
1324
|
const isArray = instanceValues.some((iv) => Array.isArray(iv[p]));
|
|
1239
1325
|
if (isArray) {
|
|
1240
|
-
return {
|
|
1326
|
+
return {
|
|
1327
|
+
key: p,
|
|
1328
|
+
type: "array",
|
|
1329
|
+
label: camelToLabel(p),
|
|
1330
|
+
confidence: "medium",
|
|
1331
|
+
options: { arrayItem: { type: "text" } }
|
|
1332
|
+
};
|
|
1241
1333
|
}
|
|
1242
|
-
return {
|
|
1334
|
+
return {
|
|
1335
|
+
key: p,
|
|
1336
|
+
type: inferInnerFieldType(p),
|
|
1337
|
+
label: camelToLabel(p),
|
|
1338
|
+
confidence: "medium"
|
|
1339
|
+
};
|
|
1243
1340
|
});
|
|
1244
|
-
addField(
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1341
|
+
addField(
|
|
1342
|
+
{
|
|
1343
|
+
key: cardKey,
|
|
1344
|
+
type: "array",
|
|
1345
|
+
label: `${compName} Liste`,
|
|
1346
|
+
confidence: "medium",
|
|
1347
|
+
defaultValue: instanceValues.length > 0 ? instanceValues : void 0,
|
|
1348
|
+
options: {
|
|
1349
|
+
arrayItem: { type: "object", fields: innerFields },
|
|
1350
|
+
sourceComponent: compName
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1353
|
+
nodeOffset(instances[0])
|
|
1354
|
+
);
|
|
1252
1355
|
}
|
|
1253
1356
|
}
|
|
1254
1357
|
}
|
|
@@ -1371,8 +1474,8 @@ ${template}`;
|
|
|
1371
1474
|
const tag = item.tag;
|
|
1372
1475
|
const isArray = tag === "__array__";
|
|
1373
1476
|
const isLink = tag === "a";
|
|
1374
|
-
|
|
1375
|
-
|
|
1477
|
+
const fieldType = isArray ? "array" : isLink ? "link" : "text";
|
|
1478
|
+
const keyBase = /^h[1-6]$/.test(tag) ? "heading" : isLink ? "link" : isArray ? "list" : "text";
|
|
1376
1479
|
typeCounts[keyBase] = (typeCounts[keyBase] ?? 0) + 1;
|
|
1377
1480
|
const key = typeCounts[keyBase] === 1 ? keyBase : `${keyBase}${typeCounts[keyBase]}`;
|
|
1378
1481
|
const positions = new Array(instanceCount).fill(null);
|
|
@@ -1395,7 +1498,14 @@ ${template}`;
|
|
|
1395
1498
|
const ltDefaults = new Array(instanceCount).fill(null);
|
|
1396
1499
|
ltPositions[ii] = positions[ii] ?? null;
|
|
1397
1500
|
ltDefaults[ii] = item.text || null;
|
|
1398
|
-
innerFields.push({
|
|
1501
|
+
innerFields.push({
|
|
1502
|
+
key: ltKey,
|
|
1503
|
+
type: "text",
|
|
1504
|
+
tag: "a",
|
|
1505
|
+
required: false,
|
|
1506
|
+
positions: ltPositions,
|
|
1507
|
+
defaultValues: ltDefaults
|
|
1508
|
+
});
|
|
1399
1509
|
}
|
|
1400
1510
|
}
|
|
1401
1511
|
}
|
|
@@ -1434,18 +1544,21 @@ ${template}`;
|
|
|
1434
1544
|
};
|
|
1435
1545
|
});
|
|
1436
1546
|
const groupLabel = group.tag === "tr" ? "Tabellen-Zeilen" : `${group.tag.charAt(0).toUpperCase() + group.tag.slice(1)} Liste`;
|
|
1437
|
-
addField(
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1547
|
+
addField(
|
|
1548
|
+
{
|
|
1549
|
+
key: fieldKey,
|
|
1550
|
+
type: "array",
|
|
1551
|
+
label: groupLabel,
|
|
1552
|
+
confidence: "high",
|
|
1553
|
+
defaultValue,
|
|
1554
|
+
options: {
|
|
1555
|
+
arrayItem: { type: "object", fields: innerFieldDefs },
|
|
1556
|
+
_repeatedTag: group.tag,
|
|
1557
|
+
_instanceCount: instanceCount
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
instanceBounds[0].start
|
|
1561
|
+
);
|
|
1449
1562
|
const classAttrs = group.instances.map((inst) => collectClassAttrs(inst, "", template));
|
|
1450
1563
|
repeatedGroups.push({
|
|
1451
1564
|
tag: group.tag,
|
|
@@ -1535,7 +1648,13 @@ function walkContentNodes(root, depth, items, frontmatter) {
|
|
|
1535
1648
|
}
|
|
1536
1649
|
}
|
|
1537
1650
|
function findMatchingItem(targetFp, canonicalItem, canonicalIndex, allCanonical, consumed) {
|
|
1538
|
-
const result = findMatchingItemCore(
|
|
1651
|
+
const result = findMatchingItemCore(
|
|
1652
|
+
targetFp,
|
|
1653
|
+
canonicalItem,
|
|
1654
|
+
canonicalIndex,
|
|
1655
|
+
allCanonical,
|
|
1656
|
+
consumed
|
|
1657
|
+
);
|
|
1539
1658
|
if (result) consumed.add(result.idx);
|
|
1540
1659
|
return result?.item ?? null;
|
|
1541
1660
|
}
|