@pipelex/mthds-form 0.23.2 → 0.25.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.
@@ -49,6 +49,57 @@ function readHtmlContent(value) {
49
49
  var NATIVE_HTML_CONCEPT_REF = "native.Html";
50
50
  var NATIVE_DATE_CONCEPT_REF = "native.Date";
51
51
  var NATIVE_COMPOSITE_CONCEPT_REF = "native.Composite";
52
+ var NATIVE_PAGE_CONCEPT_REF = "native.Page";
53
+ var NATIVE_YES_NO_CONCEPT_REF = "native.YesNo";
54
+ var NATIVE_RATING_CONCEPT_REF = "native.Rating";
55
+ var NATIVE_CHOICE_CONCEPT_REF = "native.Choice";
56
+ function readPageContent(value) {
57
+ if (!isRecord(value)) return void 0;
58
+ const textAndImages = ownProp(value, "text_and_images");
59
+ const holder = isRecord(textAndImages) ? textAndImages : void 0;
60
+ const textContent = holder ? ownProp(holder, "text") : void 0;
61
+ const text = typeof textContent === "string" ? textContent : isRecord(textContent) ? readText(textContent, "text") : void 0;
62
+ const images = holder ? ownProp(holder, "images") : void 0;
63
+ const rawHtml = holder ? readText(holder, "raw_html") : void 0;
64
+ const pageView = ownProp(value, "page_view");
65
+ return {
66
+ ...text !== void 0 && text.trim() !== "" ? { text } : {},
67
+ images: Array.isArray(images) ? images : [],
68
+ ...rawHtml !== void 0 && rawHtml.trim() !== "" ? { rawHtml } : {},
69
+ ...isRecord(pageView) ? { pageView } : {}
70
+ };
71
+ }
72
+ function readUnitInterval(record, key) {
73
+ const value = readNumber(record, key);
74
+ return value !== void 0 && value >= 0 && value <= 1 ? value : void 0;
75
+ }
76
+ function readYesNoContent(value) {
77
+ if (typeof value === "boolean") return { yesNo: value };
78
+ if (!isRecord(value)) return void 0;
79
+ const yesNo = ownProp(value, "yes_no");
80
+ if (typeof yesNo !== "boolean") return void 0;
81
+ const probability = readUnitInterval(value, "probability");
82
+ return { yesNo, ...probability !== void 0 ? { probability } : {} };
83
+ }
84
+ function readRatingContent(value) {
85
+ if (!isRecord(value)) return void 0;
86
+ const level = readNumber(value, "level");
87
+ if (level === void 0 || !Number.isInteger(level) || level < 0) return void 0;
88
+ const label = readText(value, "label");
89
+ const confidence = readUnitInterval(value, "confidence");
90
+ return {
91
+ level,
92
+ ...label !== void 0 ? { label } : {},
93
+ ...confidence !== void 0 ? { confidence } : {}
94
+ };
95
+ }
96
+ function readChoiceContent(value) {
97
+ if (!isRecord(value)) return void 0;
98
+ const choice = readText(value, "choice");
99
+ if (choice === void 0) return void 0;
100
+ const confidence = readUnitInterval(value, "confidence");
101
+ return { choice, ...confidence !== void 0 ? { confidence } : {} };
102
+ }
52
103
  function readCompositeContent(value) {
53
104
  if (!isRecord(value)) return void 0;
54
105
  return Object.entries(value).map(([name, member]) => ({ name, value: member }));
@@ -62,6 +113,15 @@ function isNativeDateNode(node) {
62
113
  function isNativeCompositeNode(node) {
63
114
  return refinesNative(node, NATIVE_COMPOSITE_CONCEPT_REF);
64
115
  }
116
+ function isNativePageNode(node) {
117
+ return refinesNative(node, NATIVE_PAGE_CONCEPT_REF);
118
+ }
119
+ function nativeVerdictOf(node) {
120
+ if (refinesNative(node, NATIVE_YES_NO_CONCEPT_REF)) return "yes_no";
121
+ if (refinesNative(node, NATIVE_RATING_CONCEPT_REF)) return "rating";
122
+ if (refinesNative(node, NATIVE_CHOICE_CONCEPT_REF)) return "choice";
123
+ return void 0;
124
+ }
65
125
  function isNativeValueNode(node) {
66
126
  return isNativeDateNode(node) || isNativeHtmlNode(node) || isNativeCompositeNode(node);
67
127
  }
@@ -196,6 +256,6 @@ function hasTypedScalarMarkers(value) {
196
256
  return isRecord(value) && TYPED_SCALAR_MARKERS.every((marker) => hasOwnProp(value, marker));
197
257
  }
198
258
 
199
- export { NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, TYPED_SCALAR_MARKERS, dataUrlExtensions, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isNativeValueNode, isViewableUrl, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, viewableUrl };
200
- //# sourceMappingURL=chunk-CM4KVG53.js.map
201
- //# sourceMappingURL=chunk-CM4KVG53.js.map
259
+ export { NATIVE_CHOICE_CONCEPT_REF, NATIVE_COMPOSITE_CONCEPT_REF, NATIVE_DATE_CONCEPT_REF, NATIVE_HTML_CONCEPT_REF, NATIVE_PAGE_CONCEPT_REF, NATIVE_RATING_CONCEPT_REF, NATIVE_YES_NO_CONCEPT_REF, TYPED_SCALAR_MARKERS, dataUrlExtensions, formatDateContent, hasTypedScalarMarkers, isNativeCompositeNode, isNativeDateNode, isNativeHtmlNode, isNativePageNode, isNativeValueNode, isViewableUrl, nativeVerdictOf, readChoiceContent, readCompositeContent, readDataUrl, readDateContent, readDocumentContent, readHtmlContent, readImageContent, readPageContent, readRatingContent, readYesNoContent, viewableUrl };
260
+ //# sourceMappingURL=chunk-JSPF4BQP.js.map
261
+ //# sourceMappingURL=chunk-JSPF4BQP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/native-content.ts"],"names":["parsed"],"mappings":";;;AA4CA,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAGA,SAAS,QAAA,CAAS,QAAiC,GAAA,EAAiC;AAClF,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA;AACjC,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,GAAQ,MAAA;AACjE;AAEA,SAAS,UAAA,CAAW,QAAiC,GAAA,EAAiC;AACpF,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA;AACjC,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,QAAA,CAAS,KAAK,IAAI,KAAA,GAAQ,MAAA;AACvE;AA2CO,SAAS,oBAAoB,KAAA,EAAiD;AACnF,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,EAAO,KAAK,CAAA;AACjC,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,MAAA;AAC9B,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,SAAA,EAAW,QAAA,CAAS,KAAA,EAAO,YAAY,CAAA;AAAA,IACvC,QAAA,EAAU,QAAA,CAAS,KAAA,EAAO,WAAW,CAAA;AAAA,IACrC,QAAA,EAAU,QAAA,CAAS,KAAA,EAAO,UAAU,CAAA;AAAA,IACpC,KAAA,EAAO,QAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9B,OAAA,EAAS,QAAA,CAAS,KAAA,EAAO,SAAS;AAAA,GACpC;AACF;AAGO,SAAS,iBAAiB,KAAA,EAA8C;AAC7E,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,EAAO,KAAK,CAAA;AACjC,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,MAAA;AAC9B,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,SAAA,EAAW,QAAA,CAAS,KAAA,EAAO,YAAY,CAAA;AAAA,IACvC,OAAA,EAAS,QAAA,CAAS,KAAA,EAAO,SAAS,CAAA;AAAA,IAClC,QAAA,EAAU,QAAA,CAAS,KAAA,EAAO,WAAW,CAAA;AAAA,IACrC,QAAA,EAAU,QAAA,CAAS,KAAA,EAAO,UAAU,CAAA;AAAA,IACpC,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA;AAAA,IAChC,MAAA,EAAQ,UAAA,CAAW,KAAA,EAAO,QAAQ,CAAA;AAAA,IAClC,YAAA,EAAc,QAAA,CAAS,KAAA,EAAO,eAAe;AAAA,GAC/C;AACF;AA0BO,SAAS,gBAAgB,KAAA,EAA6C;AAC3E,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,KAAA,EAAO,YAAY,CAAA;AAC9C,EAAA,IAAI,SAAA,KAAc,QAAW,OAAO,MAAA;AACpC,EAAA,OAAO,EAAE,SAAA,EAAW,QAAA,EAAU,QAAA,CAAS,KAAA,EAAO,WAAW,CAAA,EAAE;AAC7D;AAGO,IAAM,uBAAA,GAA0B;AAChC,IAAM,uBAAA,GAA0B;AAChC,IAAM,4BAAA,GAA+B;AACrC,IAAM,uBAAA,GAA0B;AAChC,IAAM,yBAAA,GAA4B;AAClC,IAAM,yBAAA,GAA4B;AAClC,IAAM,yBAAA,GAA4B;AAgClC,SAAS,gBAAgB,KAAA,EAA6C;AAC3E,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,KAAA,EAAO,iBAAiB,CAAA;AACtD,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAa,CAAA,GAAI,aAAA,GAAgB,MAAA;AACzD,EAAA,MAAM,WAAA,GAAc,MAAA,GAAS,OAAA,CAAQ,MAAA,EAAQ,MAAM,CAAA,GAAI,MAAA;AAGvD,EAAA,MAAM,IAAA,GACJ,OAAO,WAAA,KAAgB,QAAA,GACnB,WAAA,GACA,QAAA,CAAS,WAAW,CAAA,GAClB,QAAA,CAAS,WAAA,EAAa,MAAM,CAAA,GAC5B,MAAA;AACR,EAAA,MAAM,MAAA,GAAS,MAAA,GAAS,OAAA,CAAQ,MAAA,EAAQ,QAAQ,CAAA,GAAI,MAAA;AACpD,EAAA,MAAM,OAAA,GAAU,MAAA,GAAS,QAAA,CAAS,MAAA,EAAQ,UAAU,CAAA,GAAI,MAAA;AACxD,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA;AAC3C,EAAA,OAAO;AAAA,IACL,GAAI,IAAA,KAAS,MAAA,IAAa,IAAA,CAAK,IAAA,OAAW,EAAA,GAAK,EAAE,IAAA,EAAK,GAAI,EAAC;AAAA,IAC3D,QAAQ,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,GAAI,SAAS,EAAC;AAAA,IAC1C,GAAI,OAAA,KAAY,MAAA,IAAa,OAAA,CAAQ,IAAA,OAAW,EAAA,GAAK,EAAE,OAAA,EAAQ,GAAI,EAAC;AAAA,IACpE,GAAI,QAAA,CAAS,QAAQ,IAAI,EAAE,QAAA,KAAa;AAAC,GAC3C;AACF;AAQA,SAAS,gBAAA,CAAiB,QAAiC,GAAA,EAAiC;AAC1F,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,MAAA,EAAQ,GAAG,CAAA;AACpC,EAAA,OAAO,UAAU,MAAA,IAAa,KAAA,IAAS,CAAA,IAAK,KAAA,IAAS,IAAI,KAAA,GAAQ,MAAA;AACnE;AAeO,SAAS,iBAAiB,KAAA,EAA8C;AAC7E,EAAA,IAAI,OAAO,KAAA,KAAU,SAAA,EAAW,OAAO,EAAE,OAAO,KAAA,EAAM;AACtD,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,EAAO,QAAQ,CAAA;AACrC,EAAA,IAAI,OAAO,KAAA,KAAU,SAAA,EAAW,OAAO,MAAA;AACvC,EAAA,MAAM,WAAA,GAAc,gBAAA,CAAiB,KAAA,EAAO,aAAa,CAAA;AACzD,EAAA,OAAO,EAAE,OAAO,GAAI,WAAA,KAAgB,SAAY,EAAE,WAAA,EAAY,GAAI,EAAC,EAAG;AACxE;AAaO,SAAS,kBAAkB,KAAA,EAA+C;AAC/E,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA;AACvC,EAAA,IAAI,KAAA,KAAU,UAAa,CAAC,MAAA,CAAO,UAAU,KAAK,CAAA,IAAK,KAAA,GAAQ,CAAA,EAAG,OAAO,MAAA;AACzE,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AACrC,EAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,KAAA,EAAO,YAAY,CAAA;AACvD,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU,EAAC;AAAA,IACvC,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe;AAAC,GACnD;AACF;AAgBO,SAAS,kBAAkB,KAAA,EAA+C;AAC/E,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,EAAO,QAAQ,CAAA;AACvC,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,EAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,KAAA,EAAO,YAAY,CAAA;AACvD,EAAA,OAAO,EAAE,QAAQ,GAAI,UAAA,KAAe,SAAY,EAAE,UAAA,EAAW,GAAI,EAAC,EAAG;AACvE;AAiBO,SAAS,qBAAqB,KAAA,EAA+C;AAClF,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,IAAA,EAAM,MAAM,CAAA,MAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAO,CAAE,CAAA;AAChF;AAWO,SAAS,iBAAiB,IAAA,EAA2B;AAC1D,EAAA,OAAO,aAAA,CAAc,MAAM,uBAAuB,CAAA;AACpD;AAgBO,SAAS,iBAAiB,IAAA,EAA2B;AAC1D,EAAA,OAAO,aAAA,CAAc,MAAM,uBAAuB,CAAA;AACpD;AAgBO,SAAS,sBAAsB,IAAA,EAA2B;AAC/D,EAAA,OAAO,aAAA,CAAc,MAAM,4BAA4B,CAAA;AACzD;AAaO,SAAS,iBAAiB,IAAA,EAA2B;AAC1D,EAAA,OAAO,aAAA,CAAc,MAAM,uBAAuB,CAAA;AACpD;AAcO,SAAS,gBAAgB,IAAA,EAA8D;AAC5F,EAAA,IAAI,aAAA,CAAc,IAAA,EAAM,yBAAyB,CAAA,EAAG,OAAO,QAAA;AAC3D,EAAA,IAAI,aAAA,CAAc,IAAA,EAAM,yBAAyB,CAAA,EAAG,OAAO,QAAA;AAC3D,EAAA,IAAI,aAAA,CAAc,IAAA,EAAM,yBAAyB,CAAA,EAAG,OAAO,QAAA;AAC3D,EAAA,OAAO,MAAA;AACT;AAaO,SAAS,kBAAkB,IAAA,EAA2B;AAC3D,EAAA,OAAO,iBAAiB,IAAI,CAAA,IAAK,iBAAiB,IAAI,CAAA,IAAK,sBAAsB,IAAI,CAAA;AACvF;AAsBA,SAAS,aAAA,CAAc,MAAkB,GAAA,EAAsB;AAC7D,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAQ,OAAO,KAAA;AACjC,EAAA,IAAI,IAAA,CAAK,UAAA,KAAe,GAAA,EAAK,OAAO,IAAA;AACpC,EAAA,OAAO,IAAA,CAAK,OAAA,EAAS,QAAA,CAAS,GAAG,CAAA,IAAK,KAAA;AACxC;AAWO,SAAS,gBAAgB,KAAA,EAA6C;AAC3E,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,MAAM,MAAA,GAAS,CAAA,GAAI,EAAE,IAAA,EAAM,OAAM,GAAI,MAAA;AAAA,EAC9C;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAE7B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,EAAO,MAAM,CAAA;AACnC,EAAA,MAAM,IAAA,GACJ,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,QAAA,CAAS,KAAK,CAAA,GAAI,QAAA,CAAS,KAAA,EAAO,MAAM,CAAA,GAAI,MAAA;AAClF,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,MAAA;AAC/B,EAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,QAAA,CAAS,KAAA,EAAO,MAAM,CAAA,EAAE;AAC/C;AAGO,SAAS,kBAAkB,OAAA,EAAkC;AAClE,EAAA,OAAO,OAAA,CAAQ,OAAO,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,CAAA,EAAI,OAAA,CAAQ,IAAI,CAAA,CAAA,GAAK,OAAA,CAAQ,IAAA;AACpE;AAsBA,IAAM,yBAAA,uBAAqF,GAAA,CAAI;AAAA,EAC7F,CAAC,WAAA,EAAa,CAAC,KAAK,CAAC,CAAA;AAAA,EACrB,CAAC,YAAA,EAAc,CAAC,KAAA,EAAO,MAAM,CAAC,CAAA;AAAA,EAC9B,CAAC,WAAA,EAAa,CAAC,KAAK,CAAC,CAAA;AAAA,EACrB,CAAC,YAAA,EAAc,CAAC,MAAM,CAAC,CAAA;AAAA,EACvB,CAAC,YAAA,EAAc,CAAC,MAAM,CAAC,CAAA;AAAA,EACvB,CAAC,iBAAA,EAAmB,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAA;AAMM,SAAS,kBAAkB,SAAA,EAAsC;AACtE,EAAA,OAAO,yBAAA,CAA0B,GAAA,CAAI,SAAS,CAAA,IAAK,EAAC;AACtD;AASA,IAAM,wBAAA,GAA2B,0BAAA;AAQjC,IAAM,aAAA,GAAgB,sBAAA;AAYtB,SAAS,mBAAmB,SAAA,EAA2B;AAGrD,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,MAAM,SAAA,CAAU,MAAA;AACpB,EAAA,OAAO,QAAQ,GAAA,IAAO,SAAA,CAAU,WAAW,KAAK,CAAA,IAAK,IAAM,KAAA,IAAS,CAAA;AACpE,EAAA,OAAO,GAAA,GAAM,SAAS,SAAA,CAAU,UAAA,CAAW,MAAM,CAAC,CAAA,IAAK,IAAM,GAAA,IAAO,CAAA;AAOpE,EAAA,KAAA,IAAS,KAAA,GAAQ,KAAA,EAAO,KAAA,GAAQ,GAAA,EAAK,SAAS,CAAA,EAAG;AAC/C,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,UAAA,CAAW,KAAK,CAAA;AAGvC,IAAA,IAAI,IAAA,KAAS,CAAA,IAAQ,IAAA,KAAS,EAAA,IAAQ,SAAS,EAAA,EAAM;AACnD,MAAA,IAAI,QAAA,GAAW,SAAA,CAAU,KAAA,CAAM,KAAA,EAAO,KAAK,CAAA;AAC3C,MAAA,KAAA,IAAS,IAAA,GAAO,KAAA,EAAO,IAAA,GAAO,GAAA,EAAK,QAAQ,CAAA,EAAG;AAC5C,QAAA,MAAM,QAAA,GAAW,SAAA,CAAU,UAAA,CAAW,IAAI,CAAA;AAC1C,QAAA,IAAI,QAAA,KAAa,CAAA,IAAQ,QAAA,KAAa,EAAA,IAAQ,QAAA,KAAa,EAAA;AACzD,UAAA,QAAA,IAAY,UAAU,IAAI,CAAA;AAAA,MAC9B;AACA,MAAA,OAAO,QAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,KAAA,KAAU,KAAK,GAAA,KAAQ,SAAA,CAAU,SAAS,SAAA,GAAY,SAAA,CAAU,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA;AACzF;AAwBO,SAAS,YAAY,SAAA,EAA4C;AACtE,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,IAAI,CAAC,SAAA,CAAU,IAAA,CAAK,GAAG,GAAG,OAAO,MAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,KAAU,IAAI,OAAO,MAAA;AACzB,EAAA,MAAM,CAAC,QAAA,GAAW,EAAA,EAAI,GAAG,UAAU,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAQ,KAAK,CAAA,CAAE,MAAM,GAAG,CAAA;AACjF,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,IAAA,EAAK,CAAE,WAAA,EAAY;AAG5C,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,KAAK,CAAA;AACvC,EAAA,MAAM,OAAA,GAAU,QAAA,KAAa,EAAA,GAAK,GAAA,CAAI,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,QAAQ,CAAA;AACtF,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,IAAA,CAAK,CAAC,SAAA,KAAc,UAAU,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,QAAQ,CAAA;AACzF,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,OAAA,KAAY,EAAA,GAAK,YAAA,GAAe,OAAA;AAAA,IAC3C,OAAO,MAAA,GAAS,WAAA,CAAY,OAAO,CAAA,GAAI,oBAAoB,OAAO;AAAA,GACpE;AACF;AAWA,SAAS,YAAY,OAAA,EAAyB;AAC5C,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAQ,SAAS,CAAA,EAAG;AACtD,IAAA,IAAI,IAAA,GAAO,OAAA,CAAQ,UAAA,CAAW,KAAK,CAAA;AACnC,IAAA,IAAI,SAAS,EAAA,EAAM;AACjB,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAA,EAAG,EAAE,CAAA;AACvE,MAAA,IAAI,CAAC,OAAO,KAAA,CAAM,OAAO,KAAK,KAAA,GAAQ,CAAA,GAAI,QAAQ,MAAA,EAAQ;AACxD,QAAA,IAAA,GAAO,OAAA;AACP,QAAA,KAAA,IAAS,CAAA;AAAA,MACX;AAAA,IACF;AACA,IAAA,IACG,QAAQ,EAAA,IAAQ,IAAA,IAAQ,MACxB,IAAA,IAAQ,EAAA,IAAQ,QAAQ,GAAA,IACxB,IAAA,IAAQ,EAAA,IAAQ,IAAA,IAAQ,MACzB,IAAA,KAAS,EAAA,IACT,SAAS,EAAA,IACT,IAAA,KAAS,MACT,IAAA,KAAS,EAAA;AAET,MAAA,OAAA,IAAW,CAAA;AAAA,EACf;AACA,EAAA,OAAO,IAAA,CAAK,KAAA,CAAO,OAAA,GAAU,CAAA,GAAK,CAAC,CAAA;AACrC;AAGA,SAAS,oBAAoB,OAAA,EAAyB;AACpD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,gBAAgB,GAAG,MAAA,IAAU,CAAA;AAC3D,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,OAAO,OAAO,CAAA,CAAE,SAAS,OAAA,GAAU,CAAA;AAC9D;AAGA,SAAS,iBAAiB,MAAA,EAAqB;AAC7C,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAC,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AACxD,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,IAAA,EAAK,CAAE,WAAA,EAAY;AAC5C,EAAA,OAAO,OAAA,KAAY,KAAK,YAAA,GAAe,OAAA;AACzC;AAuCO,SAAS,YAAY,SAAA,EAAmD;AAC7E,EAAA,IAAI,CAAC,WAAW,OAAO,MAAA;AACvB,EAAA,MAAM,QAAA,GAAW,mBAAmB,SAAS,CAAA;AAC7C,EAAA,IAAI,QAAA,KAAa,IAAI,OAAO,MAAA;AAU5B,EAAA,IAAI,aAAA,CAAc,IAAA,CAAK,QAAQ,CAAA,EAAG;AAChC,IAAA,IAAIA,OAAAA;AACJ,IAAA,IAAI;AACF,MAAAA,OAAAA,GAAS,IAAI,GAAA,CAAI,QAAQ,CAAA;AAAA,IAC3B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,QAAQA,QAAO,QAAA;AAAU,MACvB,KAAK,OAAA;AAAA,MACL,KAAK,QAAA;AAAA,MACL,KAAK,OAAA;AACH,QAAA,OAAOA,OAAAA,CAAO,IAAA;AAAA,MAChB,KAAK,OAAA;AACH,QAAA,OAAO,0BAA0B,GAAA,CAAI,gBAAA,CAAiBA,OAAM,CAAC,CAAA,GAAIA,QAAO,IAAA,GAAO,MAAA;AAAA,MACjF;AACE,QAAA,OAAO,MAAA;AAAA;AACX,EACF;AAIA,EAAA,IAAI,CAAC,QAAA,CAAS,UAAA,CAAW,GAAG,GAAG,OAAO,MAAA;AAItC,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,UAAA,CAAW,CAAC,CAAA;AACxC,EAAA,IAAI,UAAA,KAAe,EAAA,IAAQ,UAAA,KAAe,EAAA,EAAM,OAAO,MAAA;AACvD,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,GAAA,CAAI,QAAA,EAAU,wBAAwB,CAAA;AAAA,EACrD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,KAAW,wBAAA,GAA2B,QAAA,GAAW,MAAA;AACjE;AASO,SAAS,cAAc,GAAA,EAAwC;AACpE,EAAA,OAAO,WAAA,CAAY,GAAG,CAAA,KAAM,MAAA;AAC9B;AASO,IAAM,oBAAA,GAAuB,CAAC,WAAA,EAAa,YAAY;AAGvD,SAAS,sBAAsB,KAAA,EAAyB;AAC7D,EAAA,OAAO,QAAA,CAAS,KAAK,CAAA,IAAK,oBAAA,CAAqB,KAAA,CAAM,CAAC,MAAA,KAAW,UAAA,CAAW,KAAA,EAAO,MAAM,CAAC,CAAA;AAC5F","file":"chunk-JSPF4BQP.js","sourcesContent":["/**\n * How to READ the native content models — the result side's twin of\n * `./file-formats`.\n *\n * A renderer handed a result knows the field's `kind` from the descriptor, and\n * for the kinds whose value is a structured content model rather than a bare\n * scalar (`document`, `image`, `date`) it must then read that model's members.\n * **That is reading the standard, not sniffing at it.** The distinction is the\n * whole reason this module exists as data rather than as heuristics inside a\n * control: a reader keyed by a STATED kind consults a pinned definition, where\n * a reader that works out *which* kind it is holding by counting properties is\n * guessing — and guessing is exactly what [../../docs/derivation-swap.md]\n * records removing from the input side.\n *\n * ## Where each shape comes from\n *\n * `native.Image` and `native.Document` are pinned by the standard, in\n * `docs/spec/native-concepts.md` § \"The Pinned Set (MTHDS 1.0.0)\". Both carry a\n * required `url` — a storage URI, an HTTP(S) URL, or a base64 data URL — and\n * optional presentation members beside it. Nothing here adds a member the spec\n * does not state.\n *\n * `native.Date` is pinned the same way (`{date, time}`), but a `date` FIELD\n * inside a structured concept is not a `native.Date` value: it is a python\n * `datetime.date`, and the serialization layer stamps it with its class. So a\n * date arrives in one of three legal shapes, all three of which a run really\n * produces:\n *\n * \"2026-03-14\" a plain ISO string\n * { date: \"2026-03-14\", __class__: \"date\", … } a typed scalar\n * { date: \"2026-03-14\", time: \"15:40:00\" } native.Date\n *\n * The typed-scalar envelope is the one shape the standard does NOT pin — it is\n * a serialization fact, measured off a real run rather than read off a spec —\n * and it is called out as such here so nobody mistakes it for normative.\n *\n * This module lives in core, not beside the control that renders it, for the\n * reason `file-formats.ts` established: a host that shows a result its own way\n * needs the same answer the control uses, and two copies of an answer is two\n * places for it to drift. Pure data and pure functions — no React.\n */\n\nimport { hasOwnProp, ownProp } from './own-property';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** A member the content models declare as `type = \"text\"`, when it is one. */\nfunction readText(record: Record<string, unknown>, key: string): string | undefined {\n const value = ownProp(record, key);\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction readNumber(record: Record<string, unknown>, key: string): number | undefined {\n const value = ownProp(record, key);\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/**\n * `native.Document`, read.\n *\n * `url` is the only required member; everything else is a producer's courtesy,\n * so a reader that demands any of them describes a value the standard permits\n * as malformed.\n */\nexport interface DocumentContentView {\n url: string;\n publicUrl?: string;\n mimeType?: string;\n filename?: string;\n title?: string;\n snippet?: string;\n}\n\n/** `native.Image`, read. `width`/`height` are optional but PAIRED by the spec. */\nexport interface ImageContentView {\n url: string;\n publicUrl?: string;\n caption?: string;\n mimeType?: string;\n filename?: string;\n width?: number;\n height?: number;\n sourcePrompt?: string;\n}\n\n/** `native.Date` (and the typed-scalar envelope a nested `date` field arrives in). */\nexport interface DateContentView {\n /** ISO 8601 calendar date, `YYYY-MM-DD`. */\n date: string;\n /** ISO 8601 time of day, present only when the source stated one. */\n time?: string;\n}\n\n/**\n * Read a `document`-kind value. `undefined` when the value carries no `url`,\n * which is the one member the standard requires — a caller renders its own\n * absence rather than being handed a half-value to test.\n */\nexport function readDocumentContent(value: unknown): DocumentContentView | undefined {\n if (!isRecord(value)) return undefined;\n const url = readText(value, 'url');\n if (url === undefined) return undefined;\n return {\n url,\n publicUrl: readText(value, 'public_url'),\n mimeType: readText(value, 'mime_type'),\n filename: readText(value, 'filename'),\n title: readText(value, 'title'),\n snippet: readText(value, 'snippet'),\n };\n}\n\n/** Read an `image`-kind value. Same contract as `readDocumentContent`. */\nexport function readImageContent(value: unknown): ImageContentView | undefined {\n if (!isRecord(value)) return undefined;\n const url = readText(value, 'url');\n if (url === undefined) return undefined;\n return {\n url,\n publicUrl: readText(value, 'public_url'),\n caption: readText(value, 'caption'),\n mimeType: readText(value, 'mime_type'),\n filename: readText(value, 'filename'),\n width: readNumber(value, 'width'),\n height: readNumber(value, 'height'),\n sourcePrompt: readText(value, 'source_prompt'),\n };\n}\n\n/**\n * `native.Html`, read.\n *\n * The only content model here that is NOT reached by a field kind, and the\n * reason is a deliberate decision of the standard: the kind vocabulary has no\n * `html` member, so a `native.Html` value is an `object` node over its two\n * declared fields. That is right for the descriptor — the kinds name how a value\n * is ENTERED, and markup is entered as text — and wrong for a result view, which\n * would otherwise print a page's source at a reader.\n *\n * So this one is keyed by CONCEPT rather than by kind, through\n * `isNativeHtmlNode` below. That is a membership test on facts the descriptor\n * states (`concept_ref`, `refines`), which the standard's own page calls out as\n * the supported way to ask \"does this refine `native.X`?\" — the opposite of\n * inspecting a value to guess what it is.\n */\nexport interface HtmlContentView {\n /** The markup itself. The one required member. */\n innerHtml: string;\n /** A class name for a wrapper a consumer may put around it, when stated. */\n cssClass?: string;\n}\n\n/** Read an `native.Html` value. `undefined` when it carries no markup. */\nexport function readHtmlContent(value: unknown): HtmlContentView | undefined {\n if (!isRecord(value)) return undefined;\n const innerHtml = readText(value, 'inner_html');\n if (innerHtml === undefined) return undefined;\n return { innerHtml, cssClass: readText(value, 'css_class') };\n}\n\n/** The concept refs whose content model is multi-property, spelled once each. */\nexport const NATIVE_HTML_CONCEPT_REF = 'native.Html';\nexport const NATIVE_DATE_CONCEPT_REF = 'native.Date';\nexport const NATIVE_COMPOSITE_CONCEPT_REF = 'native.Composite';\nexport const NATIVE_PAGE_CONCEPT_REF = 'native.Page';\nexport const NATIVE_YES_NO_CONCEPT_REF = 'native.YesNo';\nexport const NATIVE_RATING_CONCEPT_REF = 'native.Rating';\nexport const NATIVE_CHOICE_CONCEPT_REF = 'native.Choice';\n\n/**\n * `native.Page`, read: what one page of an extracted document holds.\n *\n * The model is `{text_and_images: {text, images, raw_html}, page_view}`, where\n * `text` is a `TextContent` (`{text}`) and the images and the page view are\n * `ImageContent`s. A reader of a page wants its TEXT first, and the structural\n * renderer never reached it: the descriptor states the page as an `object`\n * over two members, and the text sits two levels down, under a member named\n * `text` inside a member named `text_and_images`. Keyed by the concept, this\n * reads the documented model and nothing else.\n */\nexport interface PageContentView {\n /** The page's extracted text, as the extractor wrote it, when it wrote any. */\n text?: string;\n /** The images extracted from the page, each an `ImageContent`, unread. */\n images: readonly unknown[];\n /**\n * The page's markup as the extractor fetched it, when it kept any. It is the\n * page's content a second time when the page has text, and its only content\n * when it has none, which is when a renderer shows it, framed, never injected.\n */\n rawHtml?: string;\n /** The rendering of the whole page, an `ImageContent`, when one was made. */\n pageView?: unknown;\n}\n\n/**\n * Read a `native.Page` value. `undefined` for anything that is not a record,\n * so the caller renders its own absence.\n */\nexport function readPageContent(value: unknown): PageContentView | undefined {\n if (!isRecord(value)) return undefined;\n const textAndImages = ownProp(value, 'text_and_images');\n const holder = isRecord(textAndImages) ? textAndImages : undefined;\n const textContent = holder ? ownProp(holder, 'text') : undefined;\n // `text` is a `TextContent`. A plain string is read too, since a page whose\n // runner rendered it raw would carry one, and both name the same text.\n const text =\n typeof textContent === 'string'\n ? textContent\n : isRecord(textContent)\n ? readText(textContent, 'text')\n : undefined;\n const images = holder ? ownProp(holder, 'images') : undefined;\n const rawHtml = holder ? readText(holder, 'raw_html') : undefined;\n const pageView = ownProp(value, 'page_view');\n return {\n ...(text !== undefined && text.trim() !== '' ? { text } : {}),\n images: Array.isArray(images) ? images : [],\n ...(rawHtml !== undefined && rawHtml.trim() !== '' ? { rawHtml } : {}),\n ...(isRecord(pageView) ? { pageView } : {}),\n };\n}\n\n/**\n * A verdict's measures, as the judging runtime states them: each is a number\n * from 0 to 1, present only when the producer reported one. A measure outside\n * that range is the payload disagreeing with its own model, and is read as\n * absent rather than shown as a percentage above a hundred.\n */\nfunction readUnitInterval(record: Record<string, unknown>, key: string): number | undefined {\n const value = readNumber(record, key);\n return value !== undefined && value >= 0 && value <= 1 ? value : undefined;\n}\n\n/** `native.YesNo`, read. */\nexport interface YesNoContentView {\n /** The answer: yes is `true`. */\n yesNo: boolean;\n /** The probability that the answer is yes, from 0 to 1, when the producer reported one. */\n probability?: number;\n}\n\n/**\n * Read a `native.YesNo` value: `{yes_no, probability}`, or the bare boolean a\n * single-member YesNo is unwrapped to by its content key. Both are the model\n * the concept states, so reading either is reading the standard.\n */\nexport function readYesNoContent(value: unknown): YesNoContentView | undefined {\n if (typeof value === 'boolean') return { yesNo: value };\n if (!isRecord(value)) return undefined;\n const yesNo = ownProp(value, 'yes_no');\n if (typeof yesNo !== 'boolean') return undefined;\n const probability = readUnitInterval(value, 'probability');\n return { yesNo, ...(probability !== undefined ? { probability } : {}) };\n}\n\n/** `native.Rating`, read. */\nexport interface RatingContentView {\n /** The index of the selected level, 0 being the first level declared. */\n level: number;\n /** The name the scale gives the selected level, when it names its levels. */\n label?: string;\n /** The producer's confidence in the level, from 0 to 1, when it reported one. */\n confidence?: number;\n}\n\n/** Read a `native.Rating` value. `undefined` when it carries no whole `level`. */\nexport function readRatingContent(value: unknown): RatingContentView | undefined {\n if (!isRecord(value)) return undefined;\n const level = readNumber(value, 'level');\n if (level === undefined || !Number.isInteger(level) || level < 0) return undefined;\n const label = readText(value, 'label');\n const confidence = readUnitInterval(value, 'confidence');\n return {\n level,\n ...(label !== undefined ? { label } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n };\n}\n\n/** `native.Choice`, read. */\nexport interface ChoiceContentView {\n /** The key of the selected option, as the method declared it. */\n choice: string;\n /** The producer's confidence in the choice, from 0 to 1, when it reported one. */\n confidence?: number;\n}\n\n/**\n * Read a `native.Choice` value. `undefined` when it carries no `choice`, or an\n * empty one: the content model types `choice` as any text, but a choice\n * question's options are keyed by non-empty strings and its `Choice` names one\n * of them, so an empty key names no option and leaves no answer to draw.\n */\nexport function readChoiceContent(value: unknown): ChoiceContentView | undefined {\n if (!isRecord(value)) return undefined;\n const choice = readText(value, 'choice');\n if (choice === undefined) return undefined;\n const confidence = readUnitInterval(value, 'confidence');\n return { choice, ...(confidence !== undefined ? { confidence } : {}) };\n}\n\n/** One member of a composite: the name it was composed under, and its content. */\nexport interface CompositeMember {\n name: string;\n value: unknown;\n}\n\n/**\n * Read a `native.Composite` — a named composition of contents.\n *\n * The members are returned in the order the payload states them, which is the\n * order the method composed them in and the only order there is: a composite\n * declares no fields, so there is no authored order to prefer over it.\n *\n * `undefined` for anything that is not a record, so the caller falls back.\n */\nexport function readCompositeContent(value: unknown): CompositeMember[] | undefined {\n if (!isRecord(value)) return undefined;\n return Object.entries(value).map(([name, member]) => ({ name, value: member }));\n}\n\n/**\n * Whether a descriptor node carries markup — its concept IS `native.Html`, or\n * refines it.\n *\n * The refinement chain is checked, not just the leaf, because a method may\n * declare `legal.ClauseMarkup` refining `native.Html` and a reader of that result\n * wants the markup rendered just the same. `refines` is on the wire for exactly\n * this question.\n */\nexport function isNativeHtmlNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_HTML_CONCEPT_REF);\n}\n\n/**\n * Whether a node IS a `native.Date` — the other content model the kind\n * vocabulary cannot name.\n *\n * `native.Date` is `{date, time}`, two properties, so nothing unwraps it and its\n * node is an `object`. Correct for the descriptor and wrong for a reader: a date\n * result rendered structurally is a two-field card whose second field says \"not\n * provided\", where the answer is a date. The `date` ARM already reads exactly\n * this model — `readDateContent` takes `{date, time}` — it just never fires,\n * because the kind says `object`.\n *\n * A `date` FIELD inside a structure is a different thing and needs none of this:\n * it carries `kind: \"date\"` already.\n */\nexport function isNativeDateNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_DATE_CONCEPT_REF);\n}\n\n/**\n * Whether a node is a `native.Composite` — a named bag of contents.\n *\n * The third concept the kind vocabulary cannot name, and the one where it is\n * least able to: a composite declares no members at all, so its descriptor is\n * `kind: \"unknown\"` and its payload schema is `{additionalProperties: true}`\n * with no properties. Both are TRUE — the standard's escape hatch, honestly\n * used — and both leave a renderer with nothing to read, so the default\n * fallback prints the whole thing as a JSON blob.\n *\n * That is the worst available answer to a value that is, by definition, a map\n * of ordinary `StuffContent`s. Keyed by concept, a renderer can at least show\n * the members as the named things they are. See `CompositeValue`.\n */\nexport function isNativeCompositeNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_COMPOSITE_CONCEPT_REF);\n}\n\n/**\n * Whether a node is a `native.Page`, or a concept refining it — one page of an\n * extracted document.\n *\n * Its node is an `object` over `{text_and_images, page_view}`, which the\n * structural renderer laid out as a record: in a list, a table whose\n * \"Text and images\" column was named by the first `text` member it found,\n * `raw_html`, which an extractor leaves empty, so a page holding a whole\n * report read as a row of dashes. Keyed by concept, the result view reads the\n * page's text instead. See `readPageContent`.\n */\nexport function isNativePageNode(node: NativeNode): boolean {\n return refinesNative(node, NATIVE_PAGE_CONCEPT_REF);\n}\n\n/**\n * Whether a node is one of the verdicts a judge returns — a yes or no\n * (`native.YesNo`), a rating (`native.Rating`) or a choice (`native.Choice`),\n * or a concept refining one — and which.\n *\n * Their nodes are `object`s over the verdict and its measures (a `YesNo` from\n * an older runtime, whose model had one member, is a `boolean` node unwrapped\n * by its content key), so the structural renderer printed the measures as a\n * record: \"Yes no: Yes / Probability: 1\". The concept is what says the record\n * is a verdict, read off `concept_ref` and `refines` like every other native\n * predicate here, never off which keys the value happens to hold.\n */\nexport function nativeVerdictOf(node: NativeNode): 'yes_no' | 'rating' | 'choice' | undefined {\n if (refinesNative(node, NATIVE_YES_NO_CONCEPT_REF)) return 'yes_no';\n if (refinesNative(node, NATIVE_RATING_CONCEPT_REF)) return 'rating';\n if (refinesNative(node, NATIVE_CHOICE_CONCEPT_REF)) return 'choice';\n return undefined;\n}\n\n/**\n * Whether a node is one of the natives the kind vocabulary cannot name that a\n * list draws one value per line — a date, an HTML page, a composite — which a\n * renderer reads by CONCEPT before it reads the kind. A list of one answers no\n * (the predicates refuse a `list` node), and its item answers yes.\n *\n * One answer, read twice: the result view renders a list whose item answers yes\n * one value per line rather than as a table, and the generative layer delegates\n * that list to the kernel, because no catalog component reads a native value.\n * Not re-exported: a host asks the predicates it needs.\n */\nexport function isNativeValueNode(node: NativeNode): boolean {\n return isNativeDateNode(node) || isNativeHtmlNode(node) || isNativeCompositeNode(node);\n}\n\n/** What the native predicates read off a node: its stated kind and its concept. */\ninterface NativeNode {\n kind?: string;\n conceptRef?: string;\n refines?: readonly string[];\n}\n\n/**\n * The node IS one of the named native, or of a concept refining it.\n *\n * **A list of them is not one of them.** Plurality is not on the concept: a\n * plural node's `concept_ref` is its ELEMENT's, with the multiplicity stripped,\n * so a `native.Date[]` result is a `list` node whose concept reads\n * `native.Date`. Asking the concept alone answered yes for the whole list, and\n * every caller then treated the list as ONE date, one page or one composite: a\n * list of dates rendered as a single absent date, and a list of pages collected\n * no page at all. So a node whose stated kind is `list`\n * answers no, and its `item` answers for itself. The kind is the descriptor's\n * own statement, so this reads a stated fact and inspects no value.\n */\nfunction refinesNative(node: NativeNode, ref: string): boolean {\n if (node.kind === 'list') return false;\n if (node.conceptRef === ref) return true;\n return node.refines?.includes(ref) ?? false;\n}\n\n/**\n * Read a `date`-kind value, in any of the three shapes a run produces.\n *\n * The `date` member is read one level deep, because `native.Date`'s own `date`\n * member is a `datetime.date` and therefore arrives inside the same typed-scalar\n * envelope the whole value may already be wrapped in. One level is enough and\n * the recursion is bounded on purpose: a second envelope would be a\n * serialization bug, and following it forever would turn one into a hang.\n */\nexport function readDateContent(value: unknown): DateContentView | undefined {\n if (typeof value === 'string') {\n return value.length > 0 ? { date: value } : undefined;\n }\n if (!isRecord(value)) return undefined;\n\n const inner = ownProp(value, 'date');\n const date =\n typeof inner === 'string' ? inner : isRecord(inner) ? readText(inner, 'date') : undefined;\n if (date === undefined) return undefined;\n return { date, time: readText(value, 'time') };\n}\n\n/** `{date}` / `{date, time}` as one line, which is how both are read aloud. */\nexport function formatDateContent(content: DateContentView): string {\n return content.time ? `${content.date} ${content.time}` : content.date;\n}\n\n/**\n * The media types a `data:` URL may carry and still be viewable, each with the\n * extensions a saved file of that type may carry, the first being the one given\n * to a name that has none of them.\n *\n * An allow-list rather than a deny-list, because the question a sink asks is\n * \"can this paint without executing\", and only a closed set answers it. The\n * raster types are the ones the preview arms already name; `application/pdf` is\n * here because the input control previews a `data:application/pdf` value a\n * storage-less host wrote back, through an `<object>`, and reads this same\n * predicate to decide.\n *\n * `image/svg+xml` is deliberately absent: an SVG paints as a picture and\n * EXECUTES as a document the moment it is opened in a tab, which is one click\n * away from every image this package paints.\n *\n * The extensions live here, beside each admitted type, rather than in the save\n * planner that reads them: a type admitted without one would save under a name\n * with no extension, and the two lists used to be kept in step by hand.\n */\nconst VIEWABLE_DATA_MEDIA_TYPES: ReadonlyMap<string, readonly [string, ...string[]]> = new Map([\n ['image/png', ['png']],\n ['image/jpeg', ['jpg', 'jpeg']],\n ['image/gif', ['gif']],\n ['image/webp', ['webp']],\n ['image/avif', ['avif']],\n ['application/pdf', ['pdf']],\n]);\n\n/**\n * The extensions a saved `data:` file of this admitted media type may carry,\n * the first being its own. Empty for a type the gate does not admit.\n */\nexport function dataUrlExtensions(mediaType: string): readonly string[] {\n return VIEWABLE_DATA_MEDIA_TYPES.get(mediaType) ?? [];\n}\n\n/**\n * An origin no host can be, to resolve a relative reference against.\n *\n * `.invalid` is reserved by RFC 2606 and resolves nowhere, so nothing can be\n * fetched from it by accident. It exists only so a path can be parsed at all;\n * the answer taken from the parse is whether the reference STAYED on it.\n */\nconst RELATIVE_SENTINEL_ORIGIN = 'https://url-gate.invalid';\n\n/**\n * A scheme, by RFC 3986's grammar: a letter, then letters, digits, `+`, `-`, `.`\n *\n * Read off the string rather than inferred from a parse, because a parse needs a\n * base and the base is what makes the answer wrong — see {@link viewableUrl}.\n */\nconst OWN_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;\n\n/**\n * What the WHATWG URL parser strips before it parses, applied before we judge.\n *\n * Leading and trailing C0 controls and spaces are removed, and every internal\n * tab, line feed and carriage return. This is not tidying: a scheme test run on\n * the raw string and a browser running on the parsed one disagree about\n * `\" https://cdn/x.png\"` — `new URL()` reads it as `https:` and `/^https?:/`\n * does not — and a host that validated a member by parsing while this gate\n * prefix-matched would have judged a different string than the one painted.\n */\nfunction stripUrlWhitespace(candidate: string): string {\n // Written out rather than as a character-class regex: the range IS the control\n // characters, which is exactly what a regex may not spell (`no-control-regex`).\n let start = 0;\n let end = candidate.length;\n while (start < end && candidate.charCodeAt(start) <= 0x20) start += 1;\n while (end > start && candidate.charCodeAt(end - 1) <= 0x20) end -= 1;\n // Scan before rebuilding, and rebuild only from the first character that has\n // to go. Almost every URL has nothing to strip inside it, and the one that\n // does is the one that is huge: an inline `data:` image is judged three or\n // four times per render, and a per-character rebuild of a megabyte-long\n // payload each time is hundreds of milliseconds of frozen main thread for a\n // string that comes back identical.\n for (let index = start; index < end; index += 1) {\n const code = candidate.charCodeAt(index);\n // Tab, line feed, carriage return - removed wherever they appear, not only\n // at the edges, which is what the parser does with them.\n if (code === 0x09 || code === 0x0a || code === 0x0d) {\n let stripped = candidate.slice(start, index);\n for (let rest = index; rest < end; rest += 1) {\n const restCode = candidate.charCodeAt(rest);\n if (restCode !== 0x09 && restCode !== 0x0a && restCode !== 0x0d)\n stripped += candidate[rest];\n }\n return stripped;\n }\n }\n return start === 0 && end === candidate.length ? candidate : candidate.slice(start, end);\n}\n\n/** What a `data:` URL says about the bytes it carries. */\nexport interface DataUrlView {\n /** Lowercased, without its parameters; `text/plain` when the URL declares none. */\n mediaType: string;\n /** The size of the DECODED payload, in bytes. */\n bytes: number;\n}\n\n/**\n * A `data:` URL's media type and decoded size, or `undefined` for any other URL.\n *\n * A host that encodes a picked file in the browser writes the file itself into\n * the value's `url`, so a thirty-kilobyte PDF is a forty-thousand-character\n * string, and printed where a reference would be it tells a person nothing. Its\n * type and its size are what they can read.\n *\n * The size is COUNTED rather than decoded. A base64 payload's size follows from\n * how many symbols it holds, and decoding a megabyte to measure it would be the\n * frozen main thread {@link stripUrlWhitespace} is written to avoid. This is a\n * reading for display, not a gate: whether the URL may be painted is still\n * {@link viewableUrl}'s answer alone.\n */\nexport function readDataUrl(candidate: string): DataUrlView | undefined {\n const url = candidate.trimStart();\n if (!/^data:/i.test(url)) return undefined;\n const comma = url.indexOf(',');\n if (comma === -1) return undefined;\n const [declared = '', ...parameters] = url.slice('data:'.length, comma).split(';');\n const trimmed = declared.trim().toLowerCase();\n // A fragment is not payload. `#page=2` on an inline PDF is the viewer's, and\n // counting it as bytes is counting the URL rather than the file.\n const fragment = url.indexOf('#', comma);\n const payload = fragment === -1 ? url.slice(comma + 1) : url.slice(comma + 1, fragment);\n const base64 = parameters.some((parameter) => parameter.trim().toLowerCase() === 'base64');\n return {\n mediaType: trimmed === '' ? 'text/plain' : trimmed,\n bytes: base64 ? base64Bytes(payload) : percentEncodedBytes(payload),\n };\n}\n\n/**\n * Three bytes for every four symbols, ignoring what is not one: the `=`\n * padding, and the line breaks a MIME encoder wraps its output at. Both\n * alphabets count, the standard one and the URL-safe one.\n *\n * A percent-escape is resolved to the character it stands for before it is\n * judged, because a payload may be escaped anywhere — `YQ%3D%3D` is `YQ==`,\n * one byte, and counting `3` and `D` as symbols made it four.\n */\nfunction base64Bytes(payload: string): number {\n let symbols = 0;\n for (let index = 0; index < payload.length; index += 1) {\n let code = payload.charCodeAt(index);\n if (code === 0x25) {\n const escaped = Number.parseInt(payload.slice(index + 1, index + 3), 16);\n if (!Number.isNaN(escaped) && index + 2 < payload.length) {\n code = escaped;\n index += 2;\n }\n }\n if (\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n (code >= 0x30 && code <= 0x39) ||\n code === 0x2b ||\n code === 0x2f ||\n code === 0x2d ||\n code === 0x5f\n )\n symbols += 1;\n }\n return Math.floor((symbols * 3) / 4);\n}\n\n/** A percent-escape is one byte; any other character is its UTF-8 length. */\nfunction percentEncodedBytes(payload: string): number {\n const escapes = payload.match(/%[0-9a-f]{2}/gi)?.length ?? 0;\n return new TextEncoder().encode(payload).length - escapes * 2;\n}\n\n/** The media type a `data:` URL declares, lowercased; `text/plain` when it declares none. */\nfunction dataUrlMediaType(parsed: URL): string {\n const declared = parsed.pathname.split(/[;,]/, 1)[0] ?? '';\n const trimmed = declared.trim().toLowerCase();\n return trimmed === '' ? 'text/plain' : trimmed;\n}\n\n/**\n * The URL a browser can paint, normalised — or `undefined` when there is none.\n *\n * **The string this returns is the string a sink must use.** That is the whole\n * point of returning one rather than answering yes or no: the gate judges a\n * normalised URL, so handing the caller back the raw member would let the two\n * diverge again on exactly the whitespace the parser strips.\n *\n * The gate parses rather than prefix-matches, and branches on the protocol the\n * parser reports:\n *\n * - `http:` and `https:` are viewable.\n * - `blob:` is viewable. A blob URL is bound to the origin that minted it, so a\n * payload cannot forge one that points anywhere else.\n * - `data:` is viewable only for a media type in {@link VIEWABLE_DATA_MEDIA_TYPES}.\n * `data:text/html` is a document at the EMBEDDING page's own origin, which is\n * what made an unsandboxed frame over a payload URL a real hole.\n * - Everything else is not: `javascript:`, `file:` (a run on a developer's\n * machine writes one, and a browser refuses to load it from an http page) and\n * `pipelex-storage://`, which cannot be resolved client-side at all — that is\n * the upload seam's job (see [../../docs/upload-seam.md]), and a renderer with\n * no resolver must show the reference rather than a broken `<img>`.\n *\n * **A root-relative path counts**, and leaving it out was a real bug rather\n * than an omission. A host's URL resolver naturally hands back a path on its\n * OWN origin — `/api/assets/…`, an authenticated route that streams the object\n * — which is the whole point of resolving rather than exposing storage. This\n * predicate rejected it for having no scheme, so the resolved URL was thrown\n * away and the arms fell back to the payload's `public_url`: a presigned URL\n * that had already expired. The image stayed broken with the fix in place.\n *\n * A path is rejected when it is protocol-relative — `//host/x`, and the two\n * backslash spellings the parser reads the same way (`\\\\host\\x`, `/\\host/x`) —\n * and then checked against the sentinel as well. An accepted path is returned\n * relative, because making it absolute against a sentinel would point it at\n * nowhere.\n */\nexport function viewableUrl(candidate: string | undefined): string | undefined {\n if (!candidate) return undefined;\n const stripped = stripUrlWhitespace(candidate);\n if (stripped === '') return undefined;\n\n // Whether the string carries a scheme is read OFF THE STRING, before any base\n // is applied, because the parser reads a candidate whose scheme equals the\n // base's as relative to that base. Deciding it with a second, base-less parse\n // let the two disagree: `https:cdn.example/x.png` was judged absolute and\n // resolved against the sentinel, so the gate handed a sink\n // `https://url-gate.invalid/cdn.example/x.png` — an internal placeholder, in a\n // real `<img src>`, in place of a URL that had worked. The grammar is RFC\n // 3986's, and it agrees with the parser on every string either accepts.\n if (OWN_SCHEME_RE.test(stripped)) {\n let parsed: URL;\n try {\n parsed = new URL(stripped);\n } catch {\n return undefined;\n }\n switch (parsed.protocol) {\n case 'http:':\n case 'https:':\n case 'blob:':\n return parsed.href;\n case 'data:':\n return VIEWABLE_DATA_MEDIA_TYPES.has(dataUrlMediaType(parsed)) ? parsed.href : undefined;\n default:\n return undefined;\n }\n }\n\n // No scheme of its own: a reference relative to wherever the page is. Only a\n // root-relative path qualifies.\n if (!stripped.startsWith('/')) return undefined;\n // Protocol-relative, rejected on the SPELLING. \"Did it stay on the sentinel\"\n // reads as the same rule and is blind in exactly one place — the sentinel's\n // own host — so `//url-gate.invalid/x` passed the test written to stop it.\n const afterSlash = stripped.charCodeAt(1);\n if (afterSlash === 0x2f || afterSlash === 0x5c) return undefined;\n let parsed: URL;\n try {\n parsed = new URL(stripped, RELATIVE_SENTINEL_ORIGIN);\n } catch {\n return undefined;\n }\n return parsed.origin === RELATIVE_SENTINEL_ORIGIN ? stripped : undefined;\n}\n\n/**\n * Whether a browser can paint this URL as-is — {@link viewableUrl} as a guard.\n *\n * Prefer `viewableUrl` wherever the URL is then USED: this answers the question\n * without handing back the normalised string, so a caller that acts on the raw\n * candidate acts on a string the gate did not judge.\n */\nexport function isViewableUrl(url: string | undefined): url is string {\n return viewableUrl(url) !== undefined;\n}\n\n/**\n * The typed-scalar markers the serialization layer stamps onto a value.\n *\n * Exported so a host can recognise (and strip) them; nothing in the kernel\n * BRANCHES on them, which is the point — a reader keyed by these would be\n * reading the serializer instead of the standard.\n */\nexport const TYPED_SCALAR_MARKERS = ['__class__', '__module__'] as const;\n\n/** Whether a record carries the typed-scalar markers. Informational. */\nexport function hasTypedScalarMarkers(value: unknown): boolean {\n return isRecord(value) && TYPED_SCALAR_MARKERS.every((marker) => hasOwnProp(value, marker));\n}\n"]}