@saastro/studio 0.5.1 → 0.7.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/{chunk-C2QUBB5U.js → chunk-DKDGF6IQ.js} +84 -210
- package/dist/chunk-DKDGF6IQ.js.map +1 -0
- package/dist/{chunk-VH3YYJEZ.js → chunk-MN3J6PBW.js} +2 -2
- package/dist/chunk-PKDMKMD6.js +212 -0
- package/dist/chunk-PKDMKMD6.js.map +1 -0
- package/dist/{chunk-F4AD4HVW.js → chunk-ZHCSQE2N.js} +2 -2
- package/dist/doctor.d.ts +216 -0
- package/dist/doctor.js +495 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/integration/index.js +4 -3
- package/dist/middleware/index.js +1 -1
- package/dist/vite/index.js +3 -2
- package/package.json +16 -13
- package/dist/chunk-C2QUBB5U.js.map +0 -1
- /package/dist/{chunk-VH3YYJEZ.js.map → chunk-MN3J6PBW.js.map} +0 -0
- /package/dist/{chunk-F4AD4HVW.js.map → chunk-ZHCSQE2N.js.map} +0 -0
|
@@ -3,7 +3,13 @@ import {
|
|
|
3
3
|
injectVersionMetaTag,
|
|
4
4
|
injectVisibilityStyle,
|
|
5
5
|
readVisibilityConfigSync
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-MN3J6PBW.js";
|
|
7
|
+
import {
|
|
8
|
+
hasFrontmatterFieldPrefix,
|
|
9
|
+
resolvePageKey,
|
|
10
|
+
transformAstroPage,
|
|
11
|
+
transformAstroSource
|
|
12
|
+
} from "./chunk-PKDMKMD6.js";
|
|
7
13
|
|
|
8
14
|
// src/vite/index.ts
|
|
9
15
|
import { promises as fs } from "node:fs";
|
|
@@ -507,192 +513,6 @@ function parseLiteral(rhs) {
|
|
|
507
513
|
return trimmed;
|
|
508
514
|
}
|
|
509
515
|
|
|
510
|
-
// ../studio-core/dist/auto-wrap-core.js
|
|
511
|
-
var FRONTMATTER_RE2 = /^\s*---\s*\n([\s\S]*?)\n---\s*\n/;
|
|
512
|
-
var SAASTRO_ATTR_RE = /data-saastro/;
|
|
513
|
-
var FIELD_PREFIX_REFERENCE_RE = /\bfieldPrefix\b/;
|
|
514
|
-
function stripCommentsAndStrings(s) {
|
|
515
|
-
return s.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/`(?:[^`\\]|\\.)*`/g, "``").replace(/'(?:[^'\\]|\\.)*'/g, "''").replace(/"(?:[^"\\]|\\.)*"/g, '""').replace(/\/\/[^\n]*/g, " ");
|
|
516
|
-
}
|
|
517
|
-
function frontmatterDeclaresFieldPrefix(fmBody) {
|
|
518
|
-
return FIELD_PREFIX_REFERENCE_RE.test(stripCommentsAndStrings(fmBody));
|
|
519
|
-
}
|
|
520
|
-
function hasFrontmatterFieldPrefix(source) {
|
|
521
|
-
const fm = FRONTMATTER_RE2.exec(source);
|
|
522
|
-
return fm ? frontmatterDeclaresFieldPrefix(fm[1]) : false;
|
|
523
|
-
}
|
|
524
|
-
var OPEN_TAG_NAME_RE = /^<([a-zA-Z][a-zA-Z0-9]*)/;
|
|
525
|
-
var INJECTION = ' {...(fieldPrefix ? { "data-saastro": `sec:${fieldPrefix}`, draggable: "true" } : {})}';
|
|
526
|
-
function findTagEnd(s, start) {
|
|
527
|
-
let i = start + 1;
|
|
528
|
-
let quote = "";
|
|
529
|
-
let brace = 0;
|
|
530
|
-
while (i < s.length) {
|
|
531
|
-
const c = s[i];
|
|
532
|
-
if (quote) {
|
|
533
|
-
if (c === quote) quote = "";
|
|
534
|
-
} else if (c === '"' || c === "'" || c === "`") {
|
|
535
|
-
quote = c;
|
|
536
|
-
} else if (c === "{") {
|
|
537
|
-
brace++;
|
|
538
|
-
} else if (c === "}") {
|
|
539
|
-
if (brace > 0) brace--;
|
|
540
|
-
} else if (c === ">" && brace === 0) {
|
|
541
|
-
return i;
|
|
542
|
-
}
|
|
543
|
-
i++;
|
|
544
|
-
}
|
|
545
|
-
return -1;
|
|
546
|
-
}
|
|
547
|
-
function injectIntoTag(template, tagStart, tagName, tagEnd, injection) {
|
|
548
|
-
const between = template.slice(tagStart + 1 + tagName.length, tagEnd);
|
|
549
|
-
const selfCloseMatch = /\s*\/\s*$/.exec(between);
|
|
550
|
-
let attrs = between;
|
|
551
|
-
let selfClose = false;
|
|
552
|
-
if (selfCloseMatch) {
|
|
553
|
-
selfClose = true;
|
|
554
|
-
attrs = between.slice(0, selfCloseMatch.index);
|
|
555
|
-
}
|
|
556
|
-
attrs = attrs.replace(/\s+$/, "");
|
|
557
|
-
const rebuilt = `<${tagName}${attrs}${injection}${selfClose ? " />" : ">"}`;
|
|
558
|
-
return template.slice(0, tagStart) + rebuilt + template.slice(tagEnd + 1);
|
|
559
|
-
}
|
|
560
|
-
function firstTagStart(template) {
|
|
561
|
-
return template.search(/<[a-zA-Z]/);
|
|
562
|
-
}
|
|
563
|
-
function transformAstroSource(source) {
|
|
564
|
-
const fm = FRONTMATTER_RE2.exec(source);
|
|
565
|
-
if (!fm) return source;
|
|
566
|
-
if (!frontmatterDeclaresFieldPrefix(fm[1])) return source;
|
|
567
|
-
const fmLen = fm[0].length;
|
|
568
|
-
const template = source.slice(fmLen);
|
|
569
|
-
const start = firstTagStart(template);
|
|
570
|
-
if (start === -1) return source;
|
|
571
|
-
const nameMatch = OPEN_TAG_NAME_RE.exec(template.slice(start));
|
|
572
|
-
if (!nameMatch) return source;
|
|
573
|
-
const tagName = nameMatch[1];
|
|
574
|
-
if (tagName[0] !== tagName[0].toLowerCase()) return source;
|
|
575
|
-
const tagEnd = findTagEnd(template, start);
|
|
576
|
-
if (tagEnd === -1) return source;
|
|
577
|
-
const between = template.slice(start + 1 + tagName.length, tagEnd);
|
|
578
|
-
if (SAASTRO_ATTR_RE.test(between)) return source;
|
|
579
|
-
return source.slice(0, fmLen) + injectIntoTag(template, start, tagName, tagEnd, INJECTION);
|
|
580
|
-
}
|
|
581
|
-
var SKIP_BODY_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "template", "title"]);
|
|
582
|
-
var SKIP_STRUCTURAL_TAGS = /* @__PURE__ */ new Set(["html", "head", "body", "link", "meta", "base", "slot"]);
|
|
583
|
-
var PAGE_MARKER_RE = /data-saastro\s*=|["']data-saastro["']\s*:/;
|
|
584
|
-
var T_USAGE_RE = /(?:Astro\.locals\.)?\bt\.([A-Za-z_$][\w$]*)/g;
|
|
585
|
-
function indexAfterCloseTag(s, lower, from) {
|
|
586
|
-
const re = new RegExp(`</\\s*${lower}\\s*>`, "i");
|
|
587
|
-
const m = re.exec(s.slice(from));
|
|
588
|
-
return m ? from + m.index + m[0].length : -1;
|
|
589
|
-
}
|
|
590
|
-
function findFirstContentTag(template) {
|
|
591
|
-
const n = template.length;
|
|
592
|
-
let i = 0;
|
|
593
|
-
let brace = 0;
|
|
594
|
-
while (i < n) {
|
|
595
|
-
const c = template[i];
|
|
596
|
-
if (c === "{") {
|
|
597
|
-
brace++;
|
|
598
|
-
i++;
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
if (c === "}") {
|
|
602
|
-
if (brace > 0) brace--;
|
|
603
|
-
i++;
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
if (c !== "<") {
|
|
607
|
-
i++;
|
|
608
|
-
continue;
|
|
609
|
-
}
|
|
610
|
-
if (template.startsWith("<!--", i)) {
|
|
611
|
-
const end = template.indexOf("-->", i + 4);
|
|
612
|
-
i = end === -1 ? n : end + 3;
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
const nameMatch = OPEN_TAG_NAME_RE.exec(template.slice(i));
|
|
616
|
-
if (!nameMatch) {
|
|
617
|
-
i++;
|
|
618
|
-
continue;
|
|
619
|
-
}
|
|
620
|
-
const tagName = nameMatch[1];
|
|
621
|
-
const tagEnd = findTagEnd(template, i);
|
|
622
|
-
if (tagEnd === -1) return null;
|
|
623
|
-
const lower = tagName.toLowerCase();
|
|
624
|
-
if (SKIP_BODY_TAGS.has(lower)) {
|
|
625
|
-
const after = indexAfterCloseTag(template, lower, tagEnd + 1);
|
|
626
|
-
i = after === -1 ? n : after;
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
const isComponent = tagName[0] !== tagName[0].toLowerCase();
|
|
630
|
-
if (isComponent || SKIP_STRUCTURAL_TAGS.has(lower) || brace > 0) {
|
|
631
|
-
i = tagEnd + 1;
|
|
632
|
-
continue;
|
|
633
|
-
}
|
|
634
|
-
return { tagStart: i, tagName, tagEnd };
|
|
635
|
-
}
|
|
636
|
-
return null;
|
|
637
|
-
}
|
|
638
|
-
function normalizeKey(s) {
|
|
639
|
-
return s.toLowerCase().replace(/[-_\s.]/g, "");
|
|
640
|
-
}
|
|
641
|
-
function routeBaseName(path) {
|
|
642
|
-
const m = /(?:^|\/)src\/pages\/(.+\.astro)$/.exec(path);
|
|
643
|
-
if (!m) return null;
|
|
644
|
-
const rel = m[1].replace(/\.astro$/, "");
|
|
645
|
-
const segments = rel.split("/").filter(Boolean);
|
|
646
|
-
const isDynamic = (s) => s.includes("[") || s.includes("]");
|
|
647
|
-
const isLocale = (s) => /^[a-z]{2}(-[a-z]{2})?$/i.test(s);
|
|
648
|
-
let last = segments.pop();
|
|
649
|
-
if (!last || isDynamic(last)) return null;
|
|
650
|
-
if (last === "index") {
|
|
651
|
-
let parent;
|
|
652
|
-
while (segments.length) {
|
|
653
|
-
const s = segments.pop();
|
|
654
|
-
if (!isDynamic(s) && !isLocale(s)) {
|
|
655
|
-
parent = s;
|
|
656
|
-
break;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
last = parent ?? "home";
|
|
660
|
-
}
|
|
661
|
-
return last;
|
|
662
|
-
}
|
|
663
|
-
function scanTUsage(source) {
|
|
664
|
-
const out = /* @__PURE__ */ new Set();
|
|
665
|
-
T_USAGE_RE.lastIndex = 0;
|
|
666
|
-
let m;
|
|
667
|
-
while ((m = T_USAGE_RE.exec(source)) !== null) out.add(m[1]);
|
|
668
|
-
return out;
|
|
669
|
-
}
|
|
670
|
-
function resolvePageKey(source, path) {
|
|
671
|
-
const base = routeBaseName(path);
|
|
672
|
-
if (!base) return null;
|
|
673
|
-
const target = normalizeKey(base);
|
|
674
|
-
for (const ns of scanTUsage(source)) {
|
|
675
|
-
if (normalizeKey(ns) === target) return ns;
|
|
676
|
-
}
|
|
677
|
-
return null;
|
|
678
|
-
}
|
|
679
|
-
function transformAstroPage(source, key) {
|
|
680
|
-
const fm = FRONTMATTER_RE2.exec(source);
|
|
681
|
-
const fmLen = fm ? fm[0].length : 0;
|
|
682
|
-
const template = source.slice(fmLen);
|
|
683
|
-
if (PAGE_MARKER_RE.test(template)) return source;
|
|
684
|
-
const hit = findFirstContentTag(template);
|
|
685
|
-
if (!hit) return source;
|
|
686
|
-
const injected = injectIntoTag(
|
|
687
|
-
template,
|
|
688
|
-
hit.tagStart,
|
|
689
|
-
hit.tagName,
|
|
690
|
-
hit.tagEnd,
|
|
691
|
-
` data-saastro="sec:${key}"`
|
|
692
|
-
);
|
|
693
|
-
return source.slice(0, fmLen) + injected;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
516
|
// src/vite/extract-props-schema.ts
|
|
697
517
|
var CACHE_MAX = 500;
|
|
698
518
|
var cache = /* @__PURE__ */ new Map();
|
|
@@ -723,7 +543,7 @@ function extractPropsSchema(source, options = {}) {
|
|
|
723
543
|
}
|
|
724
544
|
|
|
725
545
|
// src/vite/inject-schema.ts
|
|
726
|
-
var
|
|
546
|
+
var FRONTMATTER_RE2 = /^\s*---\s*\n([\s\S]*?)\n---\s*\n/;
|
|
727
547
|
var SCHEMA_SCRIPT_MARKER = 'type="application/saastro-schema"';
|
|
728
548
|
var FIRST_OPEN_TAG_RE = /<([a-zA-Z][a-zA-Z0-9]*)\b([^<>]*?)\s*(\/?)>/;
|
|
729
549
|
function extractFieldPrefixDefault(frontmatter) {
|
|
@@ -765,7 +585,7 @@ function encodeSchemaBody(schema) {
|
|
|
765
585
|
}
|
|
766
586
|
function injectSchema(source, schema, options = {}) {
|
|
767
587
|
if (source.includes(SCHEMA_SCRIPT_MARKER)) return source;
|
|
768
|
-
const fm =
|
|
588
|
+
const fm = FRONTMATTER_RE2.exec(source);
|
|
769
589
|
if (!fm) return source;
|
|
770
590
|
const frontmatter = fm[1] ?? "";
|
|
771
591
|
const templateStart = fm[0].length;
|
|
@@ -787,11 +607,11 @@ function injectSchema(source, schema, options = {}) {
|
|
|
787
607
|
}
|
|
788
608
|
|
|
789
609
|
// src/vite/instrument-fields.ts
|
|
790
|
-
var
|
|
610
|
+
var FRONTMATTER_RE3 = /^\s*---\s*\n[\s\S]*?\n---\s*\n/;
|
|
791
611
|
function instrumentFields(source, schema, options = {}) {
|
|
792
612
|
if (!schema.fields.length) return source;
|
|
793
613
|
if (!source.includes("data-saastro=")) return source;
|
|
794
|
-
const fmMatch =
|
|
614
|
+
const fmMatch = FRONTMATTER_RE3.exec(source);
|
|
795
615
|
if (!fmMatch) return source;
|
|
796
616
|
const templateStart = fmMatch[0].length;
|
|
797
617
|
const template = source.slice(templateStart);
|
|
@@ -824,7 +644,7 @@ function transformTemplate(template, fields, componentPath, source = template) {
|
|
|
824
644
|
let out = template;
|
|
825
645
|
for (const field of fields) {
|
|
826
646
|
if (field.kind !== "array") continue;
|
|
827
|
-
const res = transformArrayField(out, field);
|
|
647
|
+
const res = transformArrayField(out, field, componentPath);
|
|
828
648
|
out = res.out;
|
|
829
649
|
if (!res.matched && hasMapReference(source, field.name) && !hasHandWrittenFieldMarker(template, field.name)) {
|
|
830
650
|
warnUninstrumentedArray(componentPath, field.name);
|
|
@@ -842,22 +662,61 @@ function hasHandWrittenFieldMarker(template, name) {
|
|
|
842
662
|
"data-saastro(?:-field)?\\s*=\\s*\\{\\s*`[^`]*\\b" + n + "[[.]"
|
|
843
663
|
).test(template);
|
|
844
664
|
}
|
|
845
|
-
function warnUninstrumentedArray(componentPath, name) {
|
|
665
|
+
function warnUninstrumentedArray(componentPath, name, mapExpr = name) {
|
|
846
666
|
const where = componentPath ? ` in ${componentPath}` : "";
|
|
847
667
|
console.warn(
|
|
848
|
-
`[saastro/studio] array prop "${name}"${where} was not auto-instrumented: no \`${
|
|
668
|
+
`[saastro/studio] array prop "${name}"${where} was not auto-instrumented: no \`${mapExpr}.map(...)\` found in the template (it may be iterated via a derived variable, a chained method, or a destructured param). Its items won't be editable in the Studio until you hand-write data-saastro-field markers \u2014 e.g. <img src={item.image} data-saastro-field={\`${name}[\${i}].image\`} />.`
|
|
849
669
|
);
|
|
850
670
|
}
|
|
851
671
|
function hasMapReference(source, name) {
|
|
852
672
|
return new RegExp("\\b" + escapeReg(name) + "\\s*\\.\\s*map\\s*\\(").test(source);
|
|
853
673
|
}
|
|
854
|
-
function transformArrayField(template, field) {
|
|
674
|
+
function transformArrayField(template, field, componentPath) {
|
|
855
675
|
const name = field.name;
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
676
|
+
const re = mapCallAnchor(escapeReg(name));
|
|
677
|
+
return rewriteMapCalls(
|
|
678
|
+
template,
|
|
679
|
+
re,
|
|
680
|
+
"__i",
|
|
681
|
+
(paramName) => `${name}.map((${paramName}, __i) => `,
|
|
682
|
+
(innerJsx, paramName) => stampArrayItem(
|
|
683
|
+
innerJsx,
|
|
684
|
+
`${name}[\${__i}]`,
|
|
685
|
+
paramName,
|
|
686
|
+
field.items,
|
|
687
|
+
1,
|
|
688
|
+
componentPath
|
|
689
|
+
)
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
function transformNestedArrayField(template, parentParam, field, parentPathPrefix, depth, componentPath) {
|
|
693
|
+
const indexVar = `__i${depth + 1}`;
|
|
694
|
+
const callee = `${parentParam}.${field.name}`;
|
|
695
|
+
const re = mapCallAnchor(
|
|
696
|
+
`${escapeReg(parentParam)}\\s*\\.\\s*${escapeReg(field.name)}`
|
|
697
|
+
);
|
|
698
|
+
return rewriteMapCalls(
|
|
699
|
+
template,
|
|
700
|
+
re,
|
|
701
|
+
indexVar,
|
|
702
|
+
(paramName) => `${callee}.map((${paramName}, ${indexVar}) => `,
|
|
703
|
+
(innerJsx, paramName) => stampArrayItem(
|
|
704
|
+
innerJsx,
|
|
705
|
+
`${parentPathPrefix}.${field.name}[\${${indexVar}}]`,
|
|
706
|
+
paramName,
|
|
707
|
+
field.items,
|
|
708
|
+
depth + 1,
|
|
709
|
+
componentPath
|
|
710
|
+
)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
function mapCallAnchor(calleePattern) {
|
|
714
|
+
return new RegExp(
|
|
715
|
+
`\\b${calleePattern}\\s*\\.\\s*map\\s*\\(\\s*\\(\\s*([A-Za-z_$][\\w$]*)\\s*(?:,\\s*([A-Za-z_$][\\w$]*)\\s*)?\\)\\s*=>\\s*`,
|
|
859
716
|
"g"
|
|
860
717
|
);
|
|
718
|
+
}
|
|
719
|
+
function rewriteMapCalls(template, re, indexVar, makeHeader, transformBody) {
|
|
861
720
|
let result = "";
|
|
862
721
|
let cursor = 0;
|
|
863
722
|
let matchCount = 0;
|
|
@@ -871,13 +730,12 @@ function transformArrayField(template, field) {
|
|
|
871
730
|
const body = readArrowBody(template, arrowEnd);
|
|
872
731
|
if (!body) continue;
|
|
873
732
|
let innerJsx = body.bodyText;
|
|
874
|
-
if (existingIdx && existingIdx !==
|
|
733
|
+
if (existingIdx && existingIdx !== indexVar) {
|
|
875
734
|
const renameRe = new RegExp(`\\b${escapeReg(existingIdx)}\\b`, "g");
|
|
876
|
-
innerJsx = innerJsx.replace(renameRe,
|
|
735
|
+
innerJsx = innerJsx.replace(renameRe, indexVar);
|
|
877
736
|
}
|
|
878
|
-
const transformedJsx =
|
|
879
|
-
|
|
880
|
-
result += template.slice(cursor, headerStart) + headerNew;
|
|
737
|
+
const transformedJsx = transformBody(innerJsx, paramName);
|
|
738
|
+
result += template.slice(cursor, headerStart) + makeHeader(paramName);
|
|
881
739
|
if (body.parens) {
|
|
882
740
|
result += "(" + transformedJsx + ")";
|
|
883
741
|
} else {
|
|
@@ -1088,13 +946,29 @@ function readJsxElement(s, start) {
|
|
|
1088
946
|
}
|
|
1089
947
|
return null;
|
|
1090
948
|
}
|
|
1091
|
-
function stampArrayItem(jsx,
|
|
1092
|
-
let out = stampOuterElement(
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
949
|
+
function stampArrayItem(jsx, pathPrefix, paramName, itemField, depth, componentPath) {
|
|
950
|
+
let out = stampOuterElement(jsx, `{\`${pathPrefix}\`}`);
|
|
951
|
+
const subFields = itemField?.fields ?? [];
|
|
952
|
+
for (const sub of subFields) {
|
|
953
|
+
if (sub.kind !== "array") continue;
|
|
954
|
+
const res = transformNestedArrayField(
|
|
955
|
+
out,
|
|
956
|
+
paramName,
|
|
957
|
+
sub,
|
|
958
|
+
pathPrefix,
|
|
959
|
+
depth,
|
|
960
|
+
componentPath
|
|
961
|
+
);
|
|
962
|
+
out = res.out;
|
|
963
|
+
const mapExpr = `${paramName}.${sub.name}`;
|
|
964
|
+
if (!res.matched && hasMapReference(out, mapExpr) && !hasHandWrittenFieldMarker(out, sub.name)) {
|
|
965
|
+
const displayPath = `${pathPrefix.replace(/\[\$\{__i\d*\}\]/g, "[]")}.${sub.name}`;
|
|
966
|
+
warnUninstrumentedArray(componentPath, displayPath, mapExpr);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
1096
969
|
for (const sub of subFields) {
|
|
1097
|
-
|
|
970
|
+
if (sub.kind === "array") continue;
|
|
971
|
+
const propPath = `{\`${pathPrefix}.${sub.name}\`}`;
|
|
1098
972
|
out = transformDottedReference(out, paramName, sub.name, propPath);
|
|
1099
973
|
}
|
|
1100
974
|
return out;
|
|
@@ -1471,4 +1345,4 @@ async function loadTsx(path) {
|
|
|
1471
1345
|
export {
|
|
1472
1346
|
studioAutoWrap
|
|
1473
1347
|
};
|
|
1474
|
-
//# sourceMappingURL=chunk-
|
|
1348
|
+
//# sourceMappingURL=chunk-DKDGF6IQ.js.map
|