@datarails-ai/dr-appspace-cli 0.12.27 → 0.12.29
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/cli.js +191 -60
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
|
|
|
13
13
|
// package.json
|
|
14
14
|
var package_default = {
|
|
15
15
|
name: "@datarails-ai/dr-appspace-cli",
|
|
16
|
-
version: "0.12.
|
|
16
|
+
version: "0.12.29",
|
|
17
17
|
description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
|
|
18
18
|
type: "module",
|
|
19
19
|
engines: {
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
// src/buildInfo.ts
|
|
60
|
-
var BUILD_TIME = "2026-10-25T11:
|
|
60
|
+
var BUILD_TIME = "2026-10-25T11:42:55.355Z";
|
|
61
61
|
function formatBuildTime(iso) {
|
|
62
62
|
if (iso === "") return "";
|
|
63
63
|
const d = new Date(iso);
|
|
@@ -3803,7 +3803,7 @@ function parseHtml(html) {
|
|
|
3803
3803
|
elements.push({ tag, attrs, line: line2 });
|
|
3804
3804
|
if (tag === "script" && !("src" in attrs)) {
|
|
3805
3805
|
const bodyStart = match.index + whole.length;
|
|
3806
|
-
const end = html
|
|
3806
|
+
const end = rawTextEnd(html, "script", bodyStart);
|
|
3807
3807
|
const body = html.slice(bodyStart, end === -1 ? void 0 : end);
|
|
3808
3808
|
scripts.push({ text: body, line: lineAt(html, bodyStart) });
|
|
3809
3809
|
if (end !== -1) TAG.lastIndex = end;
|
|
@@ -3811,6 +3811,25 @@ function parseHtml(html) {
|
|
|
3811
3811
|
}
|
|
3812
3812
|
return { elements, scripts };
|
|
3813
3813
|
}
|
|
3814
|
+
function rawTextEnd(html, tag, from) {
|
|
3815
|
+
const end = new RegExp(`</${tag}(?=[\\t\\n\\f\\r />])`, "gi");
|
|
3816
|
+
end.lastIndex = from;
|
|
3817
|
+
const found = end.exec(html);
|
|
3818
|
+
return found === null ? -1 : found.index;
|
|
3819
|
+
}
|
|
3820
|
+
var CONTRACT_ID = "dr-contract";
|
|
3821
|
+
var JSON_TYPE = "application/json";
|
|
3822
|
+
function contractBlockOf(elements) {
|
|
3823
|
+
const first = elements.find((el) => el.attrs.id === CONTRACT_ID);
|
|
3824
|
+
if (first === void 0 || first.tag !== "script" || first.attrs.src !== void 0) return null;
|
|
3825
|
+
return (first.attrs.type ?? "").trim().toLowerCase() === JSON_TYPE ? first : null;
|
|
3826
|
+
}
|
|
3827
|
+
function contractBlockText(html) {
|
|
3828
|
+
const { elements, scripts } = parseHtml(html);
|
|
3829
|
+
const block = contractBlockOf(elements);
|
|
3830
|
+
if (block === null) return null;
|
|
3831
|
+
return scripts[elements.filter((el) => el.tag === "script" && !("src" in el.attrs)).indexOf(block)]?.text ?? null;
|
|
3832
|
+
}
|
|
3814
3833
|
function parseTree(html) {
|
|
3815
3834
|
const nodes = [];
|
|
3816
3835
|
const roots = [];
|
|
@@ -3849,7 +3868,7 @@ function parseTree(html) {
|
|
|
3849
3868
|
else nodes[parent].children.push(node.index);
|
|
3850
3869
|
if (tag === "script" || tag === "style") {
|
|
3851
3870
|
if (selfClosed) continue;
|
|
3852
|
-
const end = html
|
|
3871
|
+
const end = rawTextEnd(html, tag, match.index + whole.length);
|
|
3853
3872
|
if (end === -1) {
|
|
3854
3873
|
wellFormed = false;
|
|
3855
3874
|
continue;
|
|
@@ -6080,7 +6099,6 @@ function readPage(app, page, spec, elements, problems) {
|
|
|
6080
6099
|
pins: pinsOf(page, tree)
|
|
6081
6100
|
};
|
|
6082
6101
|
}
|
|
6083
|
-
var EMBEDDED_CONTRACT = /<script\b[^>]*\bid\s*=\s*["']dr-contract["'][^>]*>([\s\S]*?)<\/script>/i;
|
|
6084
6102
|
function paramsOf(page) {
|
|
6085
6103
|
const entry = embeddedPageOf(page);
|
|
6086
6104
|
return Array.isArray(entry?.params) ? { params: entry.params } : {};
|
|
@@ -6096,10 +6114,10 @@ function mountOf(page) {
|
|
|
6096
6114
|
};
|
|
6097
6115
|
}
|
|
6098
6116
|
function embeddedContractOf(page) {
|
|
6099
|
-
const
|
|
6100
|
-
if (
|
|
6117
|
+
const text3 = contractBlockText(page?.text ?? "");
|
|
6118
|
+
if (text3 === null) return null;
|
|
6101
6119
|
try {
|
|
6102
|
-
const embedded = JSON.parse(
|
|
6120
|
+
const embedded = JSON.parse(text3.replace(/<\\\//g, "</"));
|
|
6103
6121
|
return isPlainObject(embedded) ? embedded : null;
|
|
6104
6122
|
} catch {
|
|
6105
6123
|
return null;
|
|
@@ -6441,7 +6459,7 @@ function pageScripts(app, page, tree) {
|
|
|
6441
6459
|
for (const node of tree.nodes) {
|
|
6442
6460
|
if (node.tag !== "script") continue;
|
|
6443
6461
|
if (!node.attrs.src) {
|
|
6444
|
-
const end = page.text
|
|
6462
|
+
const end = rawTextEnd(page.text, "script", node.end);
|
|
6445
6463
|
inline.push({ path: page.path, text: page.text.slice(node.end, end === -1 ? void 0 : end) });
|
|
6446
6464
|
continue;
|
|
6447
6465
|
}
|
|
@@ -8604,7 +8622,7 @@ function payloadProducers(contract, { moduleSource = () => void 0, pageSource =
|
|
|
8604
8622
|
}
|
|
8605
8623
|
var SCRIPT_TAG = /<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi;
|
|
8606
8624
|
var SRC_ATTR = /\bsrc\s*=\s*["']([^"']+)["']/i;
|
|
8607
|
-
var
|
|
8625
|
+
var JSON_TYPE2 = /\btype\s*=\s*["']application\/json["']/i;
|
|
8608
8626
|
var MOUNT_ONLY = /^\s*drApp\.mount\(\s*\{[^}]*\}\s*\)\s*;?\s*$/;
|
|
8609
8627
|
function pageCode(html, path3, modules, pageSource) {
|
|
8610
8628
|
const out = [];
|
|
@@ -8612,7 +8630,7 @@ function pageCode(html, path3, modules, pageSource) {
|
|
|
8612
8630
|
const attrs = match[1] ?? "";
|
|
8613
8631
|
const src = SRC_ATTR.exec(attrs)?.[1];
|
|
8614
8632
|
if (src === void 0) {
|
|
8615
|
-
if (
|
|
8633
|
+
if (JSON_TYPE2.test(attrs) || MOUNT_ONLY.test(match[2] ?? "") || (match[2] ?? "").trim() === "") continue;
|
|
8616
8634
|
out.push(match[2]);
|
|
8617
8635
|
continue;
|
|
8618
8636
|
}
|
|
@@ -11098,13 +11116,25 @@ function restateDashboard(composed, pages, handlerName, handler, { refuse, note,
|
|
|
11098
11116
|
slots: {},
|
|
11099
11117
|
binding: null
|
|
11100
11118
|
});
|
|
11101
|
-
const
|
|
11102
|
-
const
|
|
11119
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
11120
|
+
const onlyOne = (uids, what) => {
|
|
11121
|
+
for (const uid of uids.slice(1)) {
|
|
11122
|
+
duplicates.add(uid);
|
|
11123
|
+
refuse(
|
|
11124
|
+
"chrome_duplicate",
|
|
11125
|
+
`/elements/${escapePointer3(uid)}`,
|
|
11126
|
+
`"${uid}" is a second ${what} on ${path3}, after "${uids[0]}"; a dashboard page has one of each piece of chrome \u2014 remove it, or merge it into "${uids[0]}"`
|
|
11127
|
+
);
|
|
11128
|
+
}
|
|
11129
|
+
return uids[0];
|
|
11130
|
+
};
|
|
11131
|
+
const header = onlyOne(regions("header"), "header region") ?? fresh();
|
|
11132
|
+
const chrome = HEADER_CHROME.map((role) => onlyOne(regions(role), `${role} region`) ?? fresh());
|
|
11103
11133
|
elements[header] = region(header, "header", "header", chrome);
|
|
11104
11134
|
chrome.forEach((uid, index) => {
|
|
11105
11135
|
elements[uid] = region(uid, HEADER_CHROME[index], "section", [], header);
|
|
11106
11136
|
});
|
|
11107
|
-
let nav = own2.
|
|
11137
|
+
let nav = onlyOne(own2.filter((uid) => typed[uid].type === "nav"), "nav");
|
|
11108
11138
|
const declaredTabs = own2.filter((uid) => typed[uid].type === "tab").sort((a, b) => orderOf(typed[a]) - orderOf(typed[b]) || natural3(a, b));
|
|
11109
11139
|
let tabs = [];
|
|
11110
11140
|
if (declaredTabs.length > 0) {
|
|
@@ -11159,7 +11189,7 @@ function restateDashboard(composed, pages, handlerName, handler, { refuse, note,
|
|
|
11159
11189
|
};
|
|
11160
11190
|
});
|
|
11161
11191
|
}
|
|
11162
|
-
const filters = regions("filters")
|
|
11192
|
+
const filters = onlyOne(regions("filters"), "filters region") ?? fresh();
|
|
11163
11193
|
elements[filters] = region(filters, "filters", "section", []);
|
|
11164
11194
|
const params = (Array.isArray(page.params) ? page.params : []).filter(isPlainObject7).map(canonical);
|
|
11165
11195
|
const parts = [];
|
|
@@ -11195,7 +11225,7 @@ function restateDashboard(composed, pages, handlerName, handler, { refuse, note,
|
|
|
11195
11225
|
if (conflicts.has(uid) && (parent !== null || kept.includes(typed[uid].parent))) refuse(conflicts.get(uid).code, conflicts.get(uid).pointer, conflicts.get(uid).message);
|
|
11196
11226
|
elements[uid] = cardOf(typed[uid], uid, path3, handlerName, sections, refuse, parent);
|
|
11197
11227
|
}
|
|
11198
|
-
const otherRegions = own2.filter((uid) => typed[uid].type === "region" && !handled.has(uid) && !dropped.has(uid));
|
|
11228
|
+
const otherRegions = own2.filter((uid) => typed[uid].type === "region" && !handled.has(uid) && !dropped.has(uid) && !duplicates.has(uid));
|
|
11199
11229
|
for (const uid of otherRegions) elements[uid] = region(uid, typed[uid].role ?? "header", "section", []);
|
|
11200
11230
|
const indexOfSection = (uid) => sections.findIndex((entry) => entry.id === elements[uid]?.section);
|
|
11201
11231
|
const ownRoots = [...parts, ...kept.filter((uid) => elements[uid].parent === null), ...otherRegions].sort((a, b) => rank(a) - rank(b) || natural3(a, b));
|
|
@@ -11607,7 +11637,7 @@ var WIDGETS = "dr-app-widgets@1.4.0";
|
|
|
11607
11637
|
var COMPONENTS = "dr-components@1.5.0";
|
|
11608
11638
|
var CONTROLS = "dr-components-controls@1.2.0";
|
|
11609
11639
|
var DASHBOARD_RUNTIME = "dr-app-runtime@1.13.1";
|
|
11610
|
-
var DASHBOARD_WIDGETS = "dr-app-widgets@1.5.
|
|
11640
|
+
var DASHBOARD_WIDGETS = "dr-app-widgets@1.5.1";
|
|
11611
11641
|
var DASHBOARD_BAR = "dr-app-dashboard@1.0.0";
|
|
11612
11642
|
var ASSISTANT = "dr-insights@1.4.0";
|
|
11613
11643
|
var MARKDOWN = "dr-md@1.0.0";
|
|
@@ -21730,14 +21760,57 @@ function endOfQuote(source, start, quote) {
|
|
|
21730
21760
|
}
|
|
21731
21761
|
return source.length;
|
|
21732
21762
|
}
|
|
21763
|
+
function withoutRegexLiterals(code) {
|
|
21764
|
+
const out = code.split("");
|
|
21765
|
+
let opens3 = true;
|
|
21766
|
+
let i = 0;
|
|
21767
|
+
while (i < code.length) {
|
|
21768
|
+
const ch = code[i];
|
|
21769
|
+
if (/\s/.test(ch)) {
|
|
21770
|
+
i += 1;
|
|
21771
|
+
continue;
|
|
21772
|
+
}
|
|
21773
|
+
if (WORD.test(ch)) {
|
|
21774
|
+
let j = i;
|
|
21775
|
+
while (j < code.length && WORD.test(code[j])) j += 1;
|
|
21776
|
+
opens3 = BEFORE_LITERAL_WORDS.has(code.slice(i, j));
|
|
21777
|
+
i = j;
|
|
21778
|
+
continue;
|
|
21779
|
+
}
|
|
21780
|
+
const end = ch === "/" && opens3 ? literalEnd(code, i) : -1;
|
|
21781
|
+
if (end !== -1) {
|
|
21782
|
+
blank2(out, i + 1, end);
|
|
21783
|
+
i = end + 1;
|
|
21784
|
+
while (i < code.length && WORD.test(code[i])) i += 1;
|
|
21785
|
+
opens3 = false;
|
|
21786
|
+
continue;
|
|
21787
|
+
}
|
|
21788
|
+
opens3 = ch === "/" || BEFORE_LITERAL.includes(ch);
|
|
21789
|
+
i += 1;
|
|
21790
|
+
}
|
|
21791
|
+
return out.join("");
|
|
21792
|
+
}
|
|
21793
|
+
var WORD = /[\w$]/;
|
|
21794
|
+
var BEFORE_LITERAL = "(,=:[!&|?{};+-*%<>~^}";
|
|
21795
|
+
var BEFORE_LITERAL_WORDS = /* @__PURE__ */ new Set(["return", "typeof", "instanceof", "in", "of", "new", "delete", "void", "throw", "case", "do", "else", "yield", "await"]);
|
|
21796
|
+
function literalEnd(code, start) {
|
|
21797
|
+
let inClass = false;
|
|
21798
|
+
for (let i = start + 1; i < code.length; i++) {
|
|
21799
|
+
const ch = code[i];
|
|
21800
|
+
if (ch === "\n") return -1;
|
|
21801
|
+
if (ch === "\\") i += 1;
|
|
21802
|
+
else if (ch === "[") inClass = true;
|
|
21803
|
+
else if (ch === "]") inClass = false;
|
|
21804
|
+
else if (ch === "/" && !inClass) return i;
|
|
21805
|
+
}
|
|
21806
|
+
return -1;
|
|
21807
|
+
}
|
|
21733
21808
|
|
|
21734
21809
|
// ../flows/insights-builder/kit/checks/rules/runtime.mjs
|
|
21735
21810
|
var RUNTIME_RENDERER3 = "runtime";
|
|
21736
21811
|
var CARD_COMPONENT = "widget";
|
|
21737
21812
|
var SPEC_CARD = "data-dr-spec-card";
|
|
21738
21813
|
var COMPONENT_ATTR2 = "data-dr-component";
|
|
21739
|
-
var CONTRACT_ID = "dr-contract";
|
|
21740
|
-
var JSON_TYPE2 = "application/json";
|
|
21741
21814
|
var MOUNT_CALL = /\bdrApp\s*\.\s*mount\s*\(/;
|
|
21742
21815
|
var RUNTIME_LIBRARIES = [
|
|
21743
21816
|
{
|
|
@@ -21772,19 +21845,15 @@ function compareVersions(a, b) {
|
|
|
21772
21845
|
return 0;
|
|
21773
21846
|
}
|
|
21774
21847
|
function contractBlock(elements) {
|
|
21775
|
-
|
|
21776
|
-
if (first === void 0 || first.attrs.src !== void 0) return null;
|
|
21777
|
-
return (first.attrs.type ?? "").trim().toLowerCase() === JSON_TYPE2 ? first : null;
|
|
21848
|
+
return contractBlockOf(elements);
|
|
21778
21849
|
}
|
|
21779
21850
|
function isEmbeddedContract(el, elements) {
|
|
21780
21851
|
return el === contractBlock(elements);
|
|
21781
21852
|
}
|
|
21782
21853
|
function runtimeContractOf(app, page) {
|
|
21783
21854
|
if (app.manifest?.kind !== "dashboard") return null;
|
|
21784
|
-
const
|
|
21785
|
-
|
|
21786
|
-
if (block === null) return null;
|
|
21787
|
-
const body = scripts[elements.filter((el) => el.tag === "script" && !("src" in el.attrs)).indexOf(block)]?.text ?? "";
|
|
21855
|
+
const body = contractBlockText(page.text ?? "");
|
|
21856
|
+
if (body === null) return null;
|
|
21788
21857
|
let embedded;
|
|
21789
21858
|
try {
|
|
21790
21859
|
embedded = JSON.parse(body.replace(/<\\\//g, "</"));
|
|
@@ -21798,7 +21867,7 @@ function contractCards(embedded, path3) {
|
|
|
21798
21867
|
const props = isPlainObject11(element.props) ? element.props : {};
|
|
21799
21868
|
const id = named6(props.id) ? props.id.trim() : "";
|
|
21800
21869
|
const card = named6(props.card) ? props.card.trim() : null;
|
|
21801
|
-
return { key: id || card || "", id, card, source: named6(props.source) ? props.source
|
|
21870
|
+
return { key: id || card || "", id, card, source: named6(props.source) ? props.source : "" };
|
|
21802
21871
|
});
|
|
21803
21872
|
}
|
|
21804
21873
|
function contractParams(embedded, path3) {
|
|
@@ -21826,8 +21895,7 @@ function libraryOrderProblems(page) {
|
|
|
21826
21895
|
const { elements, scripts } = parseHtml(page.text);
|
|
21827
21896
|
const indexOf = (module) => elements.findIndex((el) => el.tag === "script" && el.attrs.src !== void 0 && RUNTIME_LIBRARIES.find((one) => one.module === module).pattern.test(resolveFromPlatformRoot(page.path, el.attrs.src) ?? ""));
|
|
21828
21897
|
const inline = elements.filter((el) => el.tag === "script" && !("src" in el.attrs));
|
|
21829
|
-
const
|
|
21830
|
-
const mountScript = inline.find((el, index) => el !== block && MOUNT_CALL.test(executableText(scripts[index]?.text ?? "")));
|
|
21898
|
+
const mountScript = inline.find((el, index) => runsInPlace(el) && MOUNT_CALL.test(withoutRegexLiterals(executableText(scripts[index]?.text ?? ""))));
|
|
21831
21899
|
const mount = mountScript === void 0 ? -1 : elements.indexOf(mountScript);
|
|
21832
21900
|
const runtime = indexOf("dr-app-runtime");
|
|
21833
21901
|
const problems = [];
|
|
@@ -21851,6 +21919,28 @@ function libraryOrderProblems(page) {
|
|
|
21851
21919
|
}
|
|
21852
21920
|
return problems;
|
|
21853
21921
|
}
|
|
21922
|
+
function runsInPlace(el) {
|
|
21923
|
+
const type = (el.attrs.type ?? "").trim().toLowerCase();
|
|
21924
|
+
return type === "" || JAVASCRIPT_TYPES.has(type);
|
|
21925
|
+
}
|
|
21926
|
+
var JAVASCRIPT_TYPES = /* @__PURE__ */ new Set([
|
|
21927
|
+
"application/ecmascript",
|
|
21928
|
+
"application/javascript",
|
|
21929
|
+
"application/x-ecmascript",
|
|
21930
|
+
"application/x-javascript",
|
|
21931
|
+
"text/ecmascript",
|
|
21932
|
+
"text/javascript",
|
|
21933
|
+
"text/javascript1.0",
|
|
21934
|
+
"text/javascript1.1",
|
|
21935
|
+
"text/javascript1.2",
|
|
21936
|
+
"text/javascript1.3",
|
|
21937
|
+
"text/javascript1.4",
|
|
21938
|
+
"text/javascript1.5",
|
|
21939
|
+
"text/jscript",
|
|
21940
|
+
"text/livescript",
|
|
21941
|
+
"text/x-ecmascript",
|
|
21942
|
+
"text/x-javascript"
|
|
21943
|
+
]);
|
|
21854
21944
|
function deferralOf(el) {
|
|
21855
21945
|
if ("async" in el.attrs) return "async";
|
|
21856
21946
|
if ("defer" in el.attrs) return "defer";
|
|
@@ -22085,9 +22175,13 @@ function checkMount(page, embedded, declared) {
|
|
|
22085
22175
|
return [{ rule: "R2.2", where: page.path, message: `${page.path}'s mount names handler "${handler}", which this package does not declare; the filter bar's catalog and saved filters would reach no handler` }];
|
|
22086
22176
|
}
|
|
22087
22177
|
function runtimeSpecKeys(app) {
|
|
22088
|
-
const
|
|
22089
|
-
|
|
22090
|
-
|
|
22178
|
+
const keys2 = /* @__PURE__ */ new Map();
|
|
22179
|
+
for (const handler of app.handlers) {
|
|
22180
|
+
const spec = readSpec([handler]);
|
|
22181
|
+
if (!spec.found || spec.unresolved.length > 0) continue;
|
|
22182
|
+
keys2.set(handler.name, new Set(Object.keys(spec.table).filter((key) => !key.startsWith("_") && !key.startsWith("$"))));
|
|
22183
|
+
}
|
|
22184
|
+
return keys2.size === 0 ? null : keys2;
|
|
22091
22185
|
}
|
|
22092
22186
|
function checkScripts(scripts) {
|
|
22093
22187
|
const violations = [];
|
|
@@ -22265,7 +22359,8 @@ function checkRuntimeCards(app, page, elements, runtime, violations) {
|
|
|
22265
22359
|
continue;
|
|
22266
22360
|
}
|
|
22267
22361
|
if (drawn2 !== own2) {
|
|
22268
|
-
const
|
|
22362
|
+
const keys2 = runtime.specKeys?.get(twin.source);
|
|
22363
|
+
const unknown = keys2 !== void 0 && !keys2.has(drawn2) ? `, and "${drawn2}" is no row of the handler's SPEC` : "";
|
|
22269
22364
|
violations.push({ rule: "R2.5", where: where2(el.line), message: `the card${id === "" ? "" : ` with data-dr-id "${id}"`} draws "${own2}" in the skeleton and "${drawn2}" in #dr-contract, which the runtime mounts from${unknown}; the two name one SPEC card, or the page shows one card and a round trip writes back another` });
|
|
22270
22365
|
claim(id, own2, drawn2);
|
|
22271
22366
|
continue;
|
|
@@ -22288,12 +22383,22 @@ function checkRuntimeCards(app, page, elements, runtime, violations) {
|
|
|
22288
22383
|
if (!(el.attrs[SPAN_MARK] ?? "").trim()) {
|
|
22289
22384
|
violations.push({ rule: "R2.7", where: where2(el.line), message: `widget "${own2}" declares no ${SPAN_MARK}; every card on the kit's 12-column grid says how many columns it takes` });
|
|
22290
22385
|
}
|
|
22291
|
-
const handler = twin.source
|
|
22292
|
-
|
|
22386
|
+
const handler = twin.source;
|
|
22387
|
+
const written = (el.attrs["data-dr-source"] ?? "").trim();
|
|
22388
|
+
for (const name of new Set([handler, written].filter((one) => one !== ""))) {
|
|
22293
22389
|
if (!runtime.declared.has(name)) {
|
|
22294
22390
|
violations.push({ rule: "R2.2", where: where2(el.line), message: `widget "${own2}" is posted to handler "${name}", which this package does not declare; the runtime's request for it would reach no handler` });
|
|
22391
|
+
claim(own2);
|
|
22295
22392
|
}
|
|
22296
22393
|
}
|
|
22394
|
+
if (handler === "") {
|
|
22395
|
+
violations.push({
|
|
22396
|
+
rule: "R2.2",
|
|
22397
|
+
where: where2(el.line),
|
|
22398
|
+
message: `widget "${own2}" is posted to no handler: its props.source in #dr-contract, which the runtime mounts from, names none${written === "" ? "" : ` (the skeleton's data-dr-source "${written}" is not what the runtime reads)`}, so the runtime never loads it`
|
|
22399
|
+
});
|
|
22400
|
+
claim(own2);
|
|
22401
|
+
}
|
|
22297
22402
|
const source = specSource(runtime.data, own2);
|
|
22298
22403
|
widgets.push({
|
|
22299
22404
|
id: own2,
|
|
@@ -22505,20 +22610,26 @@ function checkAgainstSpec(app, pages, contract, specKeys = null) {
|
|
|
22505
22610
|
);
|
|
22506
22611
|
}
|
|
22507
22612
|
if (!runtime || specKeys === null) return orphans;
|
|
22508
|
-
const
|
|
22509
|
-
|
|
22510
|
-
)
|
|
22511
|
-
const drawn2 = new Set(pages.flatMap((page) => [...page.widgets.map((widget) => widget.id), ...page.claimed ?? []]));
|
|
22512
|
-
return [...orphans, ...runtimeOrphans, ...orphanSpecRows(app, [...specKeys].filter((key) => !drawn2.has(key)).sort())];
|
|
22513
|
-
}
|
|
22514
|
-
function orphanSpecRows(app, keys2) {
|
|
22515
|
-
const handler = app.handlers.find((one) => SPEC_TABLE.test(one.source)) ?? app.handlers[0];
|
|
22516
|
-
const file = handler?.file || app.handlersSource;
|
|
22517
|
-
return keys2.map((key) => ({
|
|
22613
|
+
const cards = pages.filter((page) => runtimePages.has(page.path)).flatMap((page) => page.widgets.map((widget) => ({ page, widget })));
|
|
22614
|
+
const unanswered = cards.filter(({ widget }) => specKeys.has(widget.handler) && !specKeys.get(widget.handler).has(widget.id));
|
|
22615
|
+
const runtimeOrphans = unanswered.map(({ page, widget }) => ({
|
|
22518
22616
|
rule: "R2.5",
|
|
22519
|
-
where: `${
|
|
22520
|
-
message: `
|
|
22617
|
+
where: `${page.path}:${widget.line}`,
|
|
22618
|
+
message: `widget "${widget.id}" is not a key in the handler's SPEC; the page would ask for a widget the handler cannot answer for`
|
|
22521
22619
|
}));
|
|
22620
|
+
const drawn2 = new Set(cards.filter(({ widget }) => specKeys.has(widget.handler)).map(({ widget }) => `${widget.handler}\0${widget.id}`));
|
|
22621
|
+
const claimed = /* @__PURE__ */ new Set([...pages.flatMap((page) => page.claimed ?? []), ...unanswered.map(({ widget }) => widget.id)]);
|
|
22622
|
+
return [...orphans, ...runtimeOrphans, ...orphanSpecRows(app, specKeys, drawn2, claimed)];
|
|
22623
|
+
}
|
|
22624
|
+
function orphanSpecRows(app, specKeys, drawn2, claimed) {
|
|
22625
|
+
return app.handlers.filter((handler) => specKeys.has(handler.name)).flatMap((handler) => {
|
|
22626
|
+
const file = handler.file || app.handlersSource;
|
|
22627
|
+
return [...specKeys.get(handler.name)].filter((key) => !drawn2.has(`${handler.name}\0${key}`) && !claimed.has(key)).sort().map((key) => ({
|
|
22628
|
+
rule: "R2.5",
|
|
22629
|
+
where: `${file}#SPEC.${key}`,
|
|
22630
|
+
message: `the SPEC declares "${key}", and no card on any page draws it (no [data-dr-component="widget"] names it, in ${SPEC_CARD} or in #dr-contract); the handler answers for a figure the dashboard never shows`
|
|
22631
|
+
}));
|
|
22632
|
+
});
|
|
22522
22633
|
}
|
|
22523
22634
|
|
|
22524
22635
|
// ../flows/insights-builder/kit/checks/rules/handlers.mjs
|
|
@@ -23101,7 +23212,7 @@ function parseHtml2(html) {
|
|
|
23101
23212
|
elements.push({ tag, attrs, line: line2 });
|
|
23102
23213
|
if (tag === "script" && !("src" in attrs)) {
|
|
23103
23214
|
const bodyStart = match.index + whole.length;
|
|
23104
|
-
const end = html
|
|
23215
|
+
const end = rawTextEnd2(html, "script", bodyStart);
|
|
23105
23216
|
const body = html.slice(bodyStart, end === -1 ? void 0 : end);
|
|
23106
23217
|
scripts.push({ text: body, line: lineAt2(html, bodyStart) });
|
|
23107
23218
|
if (end !== -1) TAG2.lastIndex = end;
|
|
@@ -23109,6 +23220,25 @@ function parseHtml2(html) {
|
|
|
23109
23220
|
}
|
|
23110
23221
|
return { elements, scripts };
|
|
23111
23222
|
}
|
|
23223
|
+
function rawTextEnd2(html, tag, from) {
|
|
23224
|
+
const end = new RegExp(`</${tag}(?=[\\t\\n\\f\\r />])`, "gi");
|
|
23225
|
+
end.lastIndex = from;
|
|
23226
|
+
const found = end.exec(html);
|
|
23227
|
+
return found === null ? -1 : found.index;
|
|
23228
|
+
}
|
|
23229
|
+
var CONTRACT_ID2 = "dr-contract";
|
|
23230
|
+
var JSON_TYPE3 = "application/json";
|
|
23231
|
+
function contractBlockOf2(elements) {
|
|
23232
|
+
const first = elements.find((el) => el.attrs.id === CONTRACT_ID2);
|
|
23233
|
+
if (first === void 0 || first.tag !== "script" || first.attrs.src !== void 0) return null;
|
|
23234
|
+
return (first.attrs.type ?? "").trim().toLowerCase() === JSON_TYPE3 ? first : null;
|
|
23235
|
+
}
|
|
23236
|
+
function contractBlockText2(html) {
|
|
23237
|
+
const { elements, scripts } = parseHtml2(html);
|
|
23238
|
+
const block = contractBlockOf2(elements);
|
|
23239
|
+
if (block === null) return null;
|
|
23240
|
+
return scripts[elements.filter((el) => el.tag === "script" && !("src" in el.attrs)).indexOf(block)]?.text ?? null;
|
|
23241
|
+
}
|
|
23112
23242
|
function parseTree2(html) {
|
|
23113
23243
|
const nodes = [];
|
|
23114
23244
|
const roots = [];
|
|
@@ -23147,7 +23277,7 @@ function parseTree2(html) {
|
|
|
23147
23277
|
else nodes[parent].children.push(node.index);
|
|
23148
23278
|
if (tag === "script" || tag === "style") {
|
|
23149
23279
|
if (selfClosed) continue;
|
|
23150
|
-
const end = html
|
|
23280
|
+
const end = rawTextEnd2(html, tag, match.index + whole.length);
|
|
23151
23281
|
if (end === -1) {
|
|
23152
23282
|
wellFormed = false;
|
|
23153
23283
|
continue;
|
|
@@ -24439,7 +24569,6 @@ function readPage2(app, page, spec, elements, problems) {
|
|
|
24439
24569
|
pins: pinsOf2(page, tree)
|
|
24440
24570
|
};
|
|
24441
24571
|
}
|
|
24442
|
-
var EMBEDDED_CONTRACT2 = /<script\b[^>]*\bid\s*=\s*["']dr-contract["'][^>]*>([\s\S]*?)<\/script>/i;
|
|
24443
24572
|
function paramsOf2(page) {
|
|
24444
24573
|
const entry = embeddedPageOf2(page);
|
|
24445
24574
|
return Array.isArray(entry?.params) ? { params: entry.params } : {};
|
|
@@ -24455,10 +24584,10 @@ function mountOf2(page) {
|
|
|
24455
24584
|
};
|
|
24456
24585
|
}
|
|
24457
24586
|
function embeddedContractOf2(page) {
|
|
24458
|
-
const
|
|
24459
|
-
if (
|
|
24587
|
+
const text3 = contractBlockText2(page?.text ?? "");
|
|
24588
|
+
if (text3 === null) return null;
|
|
24460
24589
|
try {
|
|
24461
|
-
const embedded = JSON.parse(
|
|
24590
|
+
const embedded = JSON.parse(text3.replace(/<\\\//g, "</"));
|
|
24462
24591
|
return isPlainObject12(embedded) ? embedded : null;
|
|
24463
24592
|
} catch {
|
|
24464
24593
|
return null;
|
|
@@ -24797,7 +24926,7 @@ function pageScripts2(app, page, tree) {
|
|
|
24797
24926
|
for (const node of tree.nodes) {
|
|
24798
24927
|
if (node.tag !== "script") continue;
|
|
24799
24928
|
if (!node.attrs.src) {
|
|
24800
|
-
const end = page.text
|
|
24929
|
+
const end = rawTextEnd2(page.text, "script", node.end);
|
|
24801
24930
|
inline.push({ path: page.path, text: page.text.slice(node.end, end === -1 ? void 0 : end) });
|
|
24802
24931
|
continue;
|
|
24803
24932
|
}
|
|
@@ -26110,7 +26239,7 @@ function payloadProducers2(contract, { moduleSource = () => void 0, pageSource =
|
|
|
26110
26239
|
}
|
|
26111
26240
|
var SCRIPT_TAG2 = /<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi;
|
|
26112
26241
|
var SRC_ATTR2 = /\bsrc\s*=\s*["']([^"']+)["']/i;
|
|
26113
|
-
var
|
|
26242
|
+
var JSON_TYPE4 = /\btype\s*=\s*["']application\/json["']/i;
|
|
26114
26243
|
var MOUNT_ONLY2 = /^\s*drApp\.mount\(\s*\{[^}]*\}\s*\)\s*;?\s*$/;
|
|
26115
26244
|
function pageCode2(html, path3, modules, pageSource) {
|
|
26116
26245
|
const out = [];
|
|
@@ -26118,7 +26247,7 @@ function pageCode2(html, path3, modules, pageSource) {
|
|
|
26118
26247
|
const attrs = match[1] ?? "";
|
|
26119
26248
|
const src = SRC_ATTR2.exec(attrs)?.[1];
|
|
26120
26249
|
if (src === void 0) {
|
|
26121
|
-
if (
|
|
26250
|
+
if (JSON_TYPE4.test(attrs) || MOUNT_ONLY2.test(match[2] ?? "") || (match[2] ?? "").trim() === "") continue;
|
|
26122
26251
|
out.push(match[2]);
|
|
26123
26252
|
continue;
|
|
26124
26253
|
}
|
|
@@ -28624,11 +28753,13 @@ var REFUSALS = /* @__PURE__ */ new Set([
|
|
|
28624
28753
|
"card_not_for_apps",
|
|
28625
28754
|
// a runtime dashboard (`dashboardPage.mjs`): a card bound to no SPEC row,
|
|
28626
28755
|
// a control no part draws, a control whose param is declared otherwise,
|
|
28627
|
-
//
|
|
28756
|
+
// a page route app.routes does not serve, and a second piece of chrome
|
|
28757
|
+
// (a header, asof, refresh, theme or filters region, or a nav) on a page
|
|
28628
28758
|
"card_unnamed",
|
|
28629
28759
|
"control_unsupported",
|
|
28630
28760
|
"control_conflict",
|
|
28631
|
-
"route_mismatch"
|
|
28761
|
+
"route_mismatch",
|
|
28762
|
+
"chrome_duplicate"
|
|
28632
28763
|
]);
|
|
28633
28764
|
var APP_REFUSALS = {
|
|
28634
28765
|
app_id_shape: 'app.id of an app with a data model is not lowercase letters, digits and "-" (e.g. "arr_test_9"); the push would take it and the first table read would fail with "invalid app_id" \u2014 rename it (e.g. "arr-test-9")',
|
|
@@ -30014,7 +30145,7 @@ async function ejectHandler(dir, contract, name) {
|
|
|
30014
30145
|
function customRole(body) {
|
|
30015
30146
|
const start = body.search(/^HANDLER = \{/m);
|
|
30016
30147
|
if (start < 0) return null;
|
|
30017
|
-
const end =
|
|
30148
|
+
const end = literalEnd2(body, body.indexOf("{", start));
|
|
30018
30149
|
if (end < 0) return null;
|
|
30019
30150
|
const literal = body.slice(start, end);
|
|
30020
30151
|
const rewritten = literal.replace(/"role": "[^"]*"/, '"role": "custom"');
|
|
@@ -30025,7 +30156,7 @@ var EJECTED_DOCSTRING = 'Ejected with app-space eject: this file is yours now, a
|
|
|
30025
30156
|
function authorsDocstring(body) {
|
|
30026
30157
|
return body.replace(/Generated by [^\n]*compile[\s\S]*?not this file\./, EJECTED_DOCSTRING);
|
|
30027
30158
|
}
|
|
30028
|
-
function
|
|
30159
|
+
function literalEnd2(text3, open2) {
|
|
30029
30160
|
let depth = 0;
|
|
30030
30161
|
let quote = null;
|
|
30031
30162
|
for (let i = open2; i < text3.length; i++) {
|