@aglyn/plugins-ai 1.0.0-beta.288 → 1.0.0-beta.290

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.
Files changed (92) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +3 -2
  3. package/src/lib/activity/ai-activity-actions.js +3 -0
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-job-requests.d.ts +2 -0
  6. package/src/lib/components/ai-job-requests.js +2 -0
  7. package/src/lib/components/ai-job-requests.js.map +1 -1
  8. package/src/lib/components/ai-site-build-page.component.js +4 -0
  9. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  10. package/src/lib/components/ai-site-import-job.component.d.ts +6 -1
  11. package/src/lib/components/ai-site-import-job.component.js +124 -17
  12. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  13. package/src/lib/components/ai-site-import-start.component.d.ts +6 -0
  14. package/src/lib/components/ai-site-import-start.component.js +18 -4
  15. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  16. package/src/lib/components/ai-site-start-card.component.js +2 -1
  17. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  18. package/src/lib/jobs/ai-image-reads.d.ts +20 -2
  19. package/src/lib/jobs/ai-image-reads.js +47 -0
  20. package/src/lib/jobs/ai-image-reads.js.map +1 -1
  21. package/src/lib/jobs/ai-job-import-step.d.ts +53 -3
  22. package/src/lib/jobs/ai-job-import-step.js +386 -64
  23. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  24. package/src/lib/jobs/ai-job-layout-language.d.ts +33 -0
  25. package/src/lib/jobs/ai-job-layout-language.js +75 -1
  26. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  27. package/src/lib/jobs/ai-job-layout-step.js +8 -3
  28. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  29. package/src/lib/jobs/ai-job-page-language.d.ts +29 -0
  30. package/src/lib/jobs/ai-job-page-language.js +178 -2
  31. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  32. package/src/lib/jobs/ai-job-page-step.js +3 -0
  33. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  34. package/src/lib/jobs/ai-site-import-document.d.ts +117 -0
  35. package/src/lib/jobs/ai-site-import-document.js +710 -0
  36. package/src/lib/jobs/ai-site-import-document.js.map +1 -0
  37. package/src/lib/jobs/ai-site-import-look.d.ts +112 -0
  38. package/src/lib/jobs/ai-site-import-look.js +402 -0
  39. package/src/lib/jobs/ai-site-import-look.js.map +1 -0
  40. package/src/lib/jobs/ai-site-import-publish.d.ts +41 -0
  41. package/src/lib/jobs/ai-site-import-publish.js +92 -0
  42. package/src/lib/jobs/ai-site-import-publish.js.map +1 -0
  43. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +27 -2
  44. package/src/lib/jobs/ai-theme-brand-inputs.js +37 -8
  45. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
  46. package/src/lib/layout-language/ai-layout-frame.d.ts +17 -0
  47. package/src/lib/layout-language/ai-layout-frame.js +73 -2
  48. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  49. package/src/lib/layout-language/ai-layout-language.d.ts +43 -0
  50. package/src/lib/layout-language/ai-layout-language.js +199 -0
  51. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  52. package/src/lib/model/ai-credit-estimate.d.ts +15 -0
  53. package/src/lib/model/ai-credit-estimate.js +14 -1
  54. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  55. package/src/lib/model/ai-jobs.types.d.ts +13 -1
  56. package/src/lib/model/ai-jobs.types.js.map +1 -1
  57. package/src/lib/model/ai-site-import-view.d.ts +47 -3
  58. package/src/lib/model/ai-site-import-view.js +122 -20
  59. package/src/lib/model/ai-site-import-view.js.map +1 -1
  60. package/src/lib/model/ai-site-import.d.ts +232 -7
  61. package/src/lib/model/ai-site-import.js +365 -35
  62. package/src/lib/model/ai-site-import.js.map +1 -1
  63. package/src/lib/runtime/ai-doctrine-validators.d.ts +18 -0
  64. package/src/lib/runtime/ai-doctrine-validators.js +16 -5
  65. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  66. package/src/lib/runtime/ai-palette.generated.js +31 -0
  67. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  68. package/src/lib/server/ai-image-reads-route.js +24 -1
  69. package/src/lib/server/ai-image-reads-route.js.map +1 -1
  70. package/src/lib/server/ai-jobs-resume.js +7 -1
  71. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  72. package/src/lib/site-import/fixtures/aglyn-com-recordings.d.ts +57 -0
  73. package/src/lib/site-import/fixtures/aglyn-com-recordings.js +172 -0
  74. package/src/lib/site-import/fixtures/aglyn-com-recordings.js.map +1 -0
  75. package/src/lib/site-import/site-import-crawl.d.ts +32 -7
  76. package/src/lib/site-import/site-import-crawl.js +133 -44
  77. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  78. package/src/lib/site-import/site-import-edge-server.d.ts +31 -0
  79. package/src/lib/site-import/site-import-edge-server.js +31 -0
  80. package/src/lib/site-import/site-import-edge-server.js.map +1 -0
  81. package/src/lib/site-import/site-import-edge.d.ts +44 -0
  82. package/src/lib/site-import/site-import-edge.js +108 -0
  83. package/src/lib/site-import/site-import-edge.js.map +1 -0
  84. package/src/lib/site-import/site-import-html.d.ts +73 -3
  85. package/src/lib/site-import/site-import-html.js +332 -45
  86. package/src/lib/site-import/site-import-html.js.map +1 -1
  87. package/src/lib/site-import/site-import-images.d.ts +22 -0
  88. package/src/lib/site-import/site-import-images.js +78 -2
  89. package/src/lib/site-import/site-import-images.js.map +1 -1
  90. package/src/lib/site-import/site-import-page.d.ts +44 -2
  91. package/src/lib/site-import/site-import-page.js +116 -16
  92. package/src/lib/site-import/site-import-page.js.map +1 -1
@@ -0,0 +1,710 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ /*==========================================
18
+ * A PAGE BROUGHT IN WORD FOR WORD (AGL-4084).
19
+ *
20
+ * An imported page is never rewritten. Its words are the source's, as the
21
+ * crawler read them (`AiSiteImportPageRead.blocks`), and this module is the
22
+ * only thing that puts them on the new page:
23
+ *
24
+ * - **Lines.** The page's main region, numbered: every heading, paragraph,
25
+ * list item, quote, link and picture in source order. A link inside a
26
+ * sentence is in its sentence already and is no line of its own.
27
+ * - **Sections.** One for the page's opening (its title and what comes
28
+ * before the first second-level heading), then one for each second-level
29
+ * heading, as the source divides itself. The page's plan has exactly
30
+ * these sections, by these names.
31
+ * - **Copied** (a collection's page, a long page): laid out by code, every
32
+ * line in order, the bands alternating plain and soft, with no model at
33
+ * all.
34
+ * - **Arranged** (a main page): the model's answer says each section's band
35
+ * and columns and which numbered lines go in which kind of block
36
+ * (`AI_LAYOUT_ARRANGE_TOOL`, which has no field for a word of copy). Code
37
+ * substitutes the lines exactly as written. A block naming a line already
38
+ * placed is dropped, a line of another section is not taken, and every
39
+ * line the answer never placed is added at the end of its own section, so
40
+ * each line is on the page exactly once.
41
+ *
42
+ * Both write the palette's own elements with the theme's tokens, the way the
43
+ * layout language compiler does (`ai-layout-compiler.ts`), so the page
44
+ * renders in the site's theme and every word stays editable in the
45
+ * Besigner's fields. Nothing is fitted, cut at a clean boundary or reworded:
46
+ * a paragraph longer than a text element holds is split between sentences,
47
+ * and a page longer than one page may weigh ends at a line, marked `cut`, so
48
+ * the review says how many of its words came through.
49
+ *=========================================*/ import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
50
+ import { bandSx } from "../layout-language/ai-layout-compiler.js";
51
+ import { AI_LAYOUT_ARRANGE_ITEM_KINDS } from "../layout-language/ai-layout-language.js";
52
+ import { AiLayoutTreeBuilder, aiLayoutSpans } from "../layout-language/ai-layout-tree.js";
53
+ import { AI_SITE_IMPORT_LABEL_MAX_CHARS, AI_SITE_IMPORT_MAX_SECTIONS } from "../model/ai-site-import.js";
54
+ import { siteImportLabel } from "../site-import/site-import-page.js";
55
+ import { AI_TEXT_LIMITS } from "../runtime/ai-palette.js";
56
+ /** The unit input carrying a page brought in word for word: its lines, its photos and where its links go. */ export const AI_LAYOUT_IMPORTED_SECTIONS_INPUT = 'importedSections';
57
+ /** The most characters a text element holds (the palette's ceiling for body copy). */ export const AI_SITE_IMPORT_TEXT_MAX_CHARS = AI_TEXT_LIMITS.body;
58
+ /** The most characters a heading style holds; a longer heading is drawn in a subtitle style, still a heading. */ export const AI_SITE_IMPORT_HEADLINE_MAX_CHARS = AI_TEXT_LIMITS.headline;
59
+ /** The most characters a button's label holds; a longer link keeps its words as a line of text. */ export const AI_SITE_IMPORT_LABEL_CHARS = 40;
60
+ /**
61
+ * What one page may weigh, inside the budget of a page of its owner's own
62
+ * words (`AI_OWN_WORDS_PAGE_BUDGET`): a page that would run past it ends at
63
+ * the line before, marked `cut`.
64
+ */ export const AI_SITE_IMPORT_DOC_MAX_NODES = 1400;
65
+ export const AI_SITE_IMPORT_DOC_MAX_CHARS = 200000;
66
+ const SECTION_PADDING = {
67
+ xs: 8,
68
+ md: 12
69
+ };
70
+ const clean = (text)=>String(text != null ? text : '').replace(/\s+/g, ' ').trim();
71
+ /** Whether a block is a line of its own: a link inside a sentence is in its sentence already. */ function isLine(block) {
72
+ if (block.kind === 'image') return !!block.url;
73
+ if (block.kind === 'link') return !block.inline && !!clean(block.text);
74
+ return !!clean(block.text);
75
+ }
76
+ /**
77
+ * The page's lines and sections (AGL-4084): the opening, then one section
78
+ * at each second-level heading, at most `AI_SITE_IMPORT_MAX_SECTIONS` (the
79
+ * last holds whatever follows). A page that opens on a second-level heading
80
+ * opens with it. Section names are the headings' words, neutralized and cut
81
+ * to a label, since they travel outside a fence.
82
+ */ export function aiSiteImportDocLines(blocks, title) {
83
+ const lines = [];
84
+ const sections = [];
85
+ let current = null;
86
+ for (const block of blocks){
87
+ if (!isLine(block)) continue;
88
+ const starts = block.kind === 'heading' && block.level === 2 && sections.length < AI_SITE_IMPORT_MAX_SECTIONS;
89
+ if (!current || starts && current.lines.length > 0) {
90
+ current = {
91
+ name: '',
92
+ lines: []
93
+ };
94
+ sections.push(current);
95
+ }
96
+ const n = lines.length + 1;
97
+ lines.push({
98
+ n,
99
+ block,
100
+ section: sections.length - 1
101
+ });
102
+ current.lines.push(n);
103
+ }
104
+ const named = new Set();
105
+ sections.forEach((section, index)=>{
106
+ const heading = section.lines.map((n)=>lines[n - 1].block).find((block)=>block.kind === 'heading');
107
+ let name = siteImportLabel(heading && heading.kind === 'heading' ? heading.text : index === 0 ? title : '') || (index === 0 ? siteImportLabel(title) : '');
108
+ if (!name) name = `Section ${index + 1}`;
109
+ // Two sections of one name are told apart, so a link to either finds it.
110
+ let unique = name;
111
+ for(let attempt = 2; named.has(unique.toLowerCase()); attempt += 1){
112
+ unique = `${name.slice(0, AI_SITE_IMPORT_LABEL_MAX_CHARS - 4)} (${attempt})`;
113
+ }
114
+ named.add(unique.toLowerCase());
115
+ section.name = unique;
116
+ });
117
+ if (!sections.length) sections.push({
118
+ name: siteImportLabel(title) || 'Introduction',
119
+ lines: []
120
+ });
121
+ return {
122
+ lines,
123
+ sections
124
+ };
125
+ }
126
+ /** The words a line shows: an image's are its description. */ export function aiSiteImportLineText(line) {
127
+ return line.block.kind === 'image' ? clean(line.block.alt) : clean(line.block.text);
128
+ }
129
+ const wordsIn = (text)=>{
130
+ var _text_match;
131
+ return ((_text_match = text.match(RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376-\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E-\\u066F\\u0671-\\u06D3\\u06D5\\u06E5-\\u06E6\\u06EE-\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4-\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F-\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC-\\u09DD\\u09DF-\\u09E1\\u09F0-\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F-\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32-\\u0A33\\u0A35-\\u0A36\\u0A38-\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2-\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0-\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F-\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32-\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C-\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99-\\u0B9A\\u0B9C\\u0B9E-\\u0B9F\\u0BA3-\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C-\\u0C5D\\u0C60-\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0-\\u0CE1\\u0CF1-\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32-\\u0E33\\u0E40-\\u0E46\\u0E81-\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2-\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065-\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE-\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5-\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183-\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2-\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3006\\u3031-\\u3035\\u303B-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A-\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7DC\\uA7F1-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD-\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5-\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40-\\uFB41\\uFB43-\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10000}-\\u{1000B}\\u{1000D}-\\u{10026}\\u{10028}-\\u{1003A}\\u{1003C}-\\u{1003D}\\u{1003F}-\\u{1004D}\\u{10050}-\\u{1005D}\\u{10080}-\\u{100FA}\\u{10280}-\\u{1029C}\\u{102A0}-\\u{102D0}\\u{10300}-\\u{1031F}\\u{1032D}-\\u{10340}\\u{10342}-\\u{10349}\\u{10350}-\\u{10375}\\u{10380}-\\u{1039D}\\u{103A0}-\\u{103C3}\\u{103C8}-\\u{103CF}\\u{10400}-\\u{1049D}\\u{104B0}-\\u{104D3}\\u{104D8}-\\u{104FB}\\u{10500}-\\u{10527}\\u{10530}-\\u{10563}\\u{10570}-\\u{1057A}\\u{1057C}-\\u{1058A}\\u{1058C}-\\u{10592}\\u{10594}-\\u{10595}\\u{10597}-\\u{105A1}\\u{105A3}-\\u{105B1}\\u{105B3}-\\u{105B9}\\u{105BB}-\\u{105BC}\\u{105C0}-\\u{105F3}\\u{10600}-\\u{10736}\\u{10740}-\\u{10755}\\u{10760}-\\u{10767}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10800}-\\u{10805}\\u{10808}\\u{1080A}-\\u{10835}\\u{10837}-\\u{10838}\\u{1083C}\\u{1083F}-\\u{10855}\\u{10860}-\\u{10876}\\u{10880}-\\u{1089E}\\u{108E0}-\\u{108F2}\\u{108F4}-\\u{108F5}\\u{10900}-\\u{10915}\\u{10920}-\\u{10939}\\u{10940}-\\u{10959}\\u{10980}-\\u{109B7}\\u{109BE}-\\u{109BF}\\u{10A00}\\u{10A10}-\\u{10A13}\\u{10A15}-\\u{10A17}\\u{10A19}-\\u{10A35}\\u{10A60}-\\u{10A7C}\\u{10A80}-\\u{10A9C}\\u{10AC0}-\\u{10AC7}\\u{10AC9}-\\u{10AE4}\\u{10B00}-\\u{10B35}\\u{10B40}-\\u{10B55}\\u{10B60}-\\u{10B72}\\u{10B80}-\\u{10B91}\\u{10C00}-\\u{10C48}\\u{10C80}-\\u{10CB2}\\u{10CC0}-\\u{10CF2}\\u{10D00}-\\u{10D23}\\u{10D4A}-\\u{10D65}\\u{10D6F}-\\u{10D85}\\u{10E80}-\\u{10EA9}\\u{10EB0}-\\u{10EB1}\\u{10EC2}-\\u{10EC7}\\u{10F00}-\\u{10F1C}\\u{10F27}\\u{10F30}-\\u{10F45}\\u{10F70}-\\u{10F81}\\u{10FB0}-\\u{10FC4}\\u{10FE0}-\\u{10FF6}\\u{11003}-\\u{11037}\\u{11071}-\\u{11072}\\u{11075}\\u{11083}-\\u{110AF}\\u{110D0}-\\u{110E8}\\u{11103}-\\u{11126}\\u{11144}\\u{11147}\\u{11150}-\\u{11172}\\u{11176}\\u{11183}-\\u{111B2}\\u{111C1}-\\u{111C4}\\u{111DA}\\u{111DC}\\u{11200}-\\u{11211}\\u{11213}-\\u{1122B}\\u{1123F}-\\u{11240}\\u{11280}-\\u{11286}\\u{11288}\\u{1128A}-\\u{1128D}\\u{1128F}-\\u{1129D}\\u{1129F}-\\u{112A8}\\u{112B0}-\\u{112DE}\\u{11305}-\\u{1130C}\\u{1130F}-\\u{11310}\\u{11313}-\\u{11328}\\u{1132A}-\\u{11330}\\u{11332}-\\u{11333}\\u{11335}-\\u{11339}\\u{1133D}\\u{11350}\\u{1135D}-\\u{11361}\\u{11380}-\\u{11389}\\u{1138B}\\u{1138E}\\u{11390}-\\u{113B5}\\u{113B7}\\u{113D1}\\u{113D3}\\u{11400}-\\u{11434}\\u{11447}-\\u{1144A}\\u{1145F}-\\u{11461}\\u{11480}-\\u{114AF}\\u{114C4}-\\u{114C5}\\u{114C7}\\u{11580}-\\u{115AE}\\u{115D8}-\\u{115DB}\\u{11600}-\\u{1162F}\\u{11644}\\u{11680}-\\u{116AA}\\u{116B8}\\u{11700}-\\u{1171A}\\u{11740}-\\u{11746}\\u{11800}-\\u{1182B}\\u{118A0}-\\u{118DF}\\u{118FF}-\\u{11906}\\u{11909}\\u{1190C}-\\u{11913}\\u{11915}-\\u{11916}\\u{11918}-\\u{1192F}\\u{1193F}\\u{11941}\\u{119A0}-\\u{119A7}\\u{119AA}-\\u{119D0}\\u{119E1}\\u{119E3}\\u{11A00}\\u{11A0B}-\\u{11A32}\\u{11A3A}\\u{11A50}\\u{11A5C}-\\u{11A89}\\u{11A9D}\\u{11AB0}-\\u{11AF8}\\u{11BC0}-\\u{11BE0}\\u{11C00}-\\u{11C08}\\u{11C0A}-\\u{11C2E}\\u{11C40}\\u{11C72}-\\u{11C8F}\\u{11D00}-\\u{11D06}\\u{11D08}-\\u{11D09}\\u{11D0B}-\\u{11D30}\\u{11D46}\\u{11D60}-\\u{11D65}\\u{11D67}-\\u{11D68}\\u{11D6A}-\\u{11D89}\\u{11D98}\\u{11DB0}-\\u{11DDB}\\u{11EE0}-\\u{11EF2}\\u{11F02}\\u{11F04}-\\u{11F10}\\u{11F12}-\\u{11F33}\\u{11FB0}\\u{12000}-\\u{12399}\\u{12480}-\\u{12543}\\u{12F90}-\\u{12FF0}\\u{13000}-\\u{1342F}\\u{13441}-\\u{13446}\\u{13460}-\\u{143FA}\\u{14400}-\\u{14646}\\u{16100}-\\u{1611D}\\u{16800}-\\u{16A38}\\u{16A40}-\\u{16A5E}\\u{16A70}-\\u{16ABE}\\u{16AD0}-\\u{16AED}\\u{16B00}-\\u{16B2F}\\u{16B40}-\\u{16B43}\\u{16B63}-\\u{16B77}\\u{16B7D}-\\u{16B8F}\\u{16D40}-\\u{16D6C}\\u{16E40}-\\u{16E7F}\\u{16EA0}-\\u{16EB8}\\u{16EBB}-\\u{16ED3}\\u{16F00}-\\u{16F4A}\\u{16F50}\\u{16F93}-\\u{16F9F}\\u{16FE0}-\\u{16FE1}\\u{16FE3}\\u{16FF2}-\\u{16FF3}\\u{17000}-\\u{18CD5}\\u{18CFF}-\\u{18D1E}\\u{18D80}-\\u{18DF2}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}-\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1B170}-\\u{1B2FB}\\u{1BC00}-\\u{1BC6A}\\u{1BC70}-\\u{1BC7C}\\u{1BC80}-\\u{1BC88}\\u{1BC90}-\\u{1BC99}\\u{1D400}-\\u{1D454}\\u{1D456}-\\u{1D49C}\\u{1D49E}-\\u{1D49F}\\u{1D4A2}\\u{1D4A5}-\\u{1D4A6}\\u{1D4A9}-\\u{1D4AC}\\u{1D4AE}-\\u{1D4B9}\\u{1D4BB}\\u{1D4BD}-\\u{1D4C3}\\u{1D4C5}-\\u{1D505}\\u{1D507}-\\u{1D50A}\\u{1D50D}-\\u{1D514}\\u{1D516}-\\u{1D51C}\\u{1D51E}-\\u{1D539}\\u{1D53B}-\\u{1D53E}\\u{1D540}-\\u{1D544}\\u{1D546}\\u{1D54A}-\\u{1D550}\\u{1D552}-\\u{1D6A5}\\u{1D6A8}-\\u{1D6C0}\\u{1D6C2}-\\u{1D6DA}\\u{1D6DC}-\\u{1D6FA}\\u{1D6FC}-\\u{1D714}\\u{1D716}-\\u{1D734}\\u{1D736}-\\u{1D74E}\\u{1D750}-\\u{1D76E}\\u{1D770}-\\u{1D788}\\u{1D78A}-\\u{1D7A8}\\u{1D7AA}-\\u{1D7C2}\\u{1D7C4}-\\u{1D7CB}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E100}-\\u{1E12C}\\u{1E137}-\\u{1E13D}\\u{1E14E}\\u{1E290}-\\u{1E2AD}\\u{1E2C0}-\\u{1E2EB}\\u{1E4D0}-\\u{1E4EB}\\u{1E5D0}-\\u{1E5ED}\\u{1E5F0}\\u{1E6C0}-\\u{1E6DE}\\u{1E6E0}-\\u{1E6E2}\\u{1E6E4}-\\u{1E6E5}\\u{1E6E7}-\\u{1E6ED}\\u{1E6F0}-\\u{1E6F4}\\u{1E6FE}-\\u{1E6FF}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}-\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1E800}-\\u{1E8C4}\\u{1E900}-\\u{1E943}\\u{1E94B}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}-\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}-\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}-\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}\\u0030-\\u0039\\u00B2-\\u00B3\\u00B9\\u00BC-\\u00BE\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u09F4-\\u09F9\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0B72-\\u0B77\\u0BE6-\\u0BF2\\u0C66-\\u0C6F\\u0C78-\\u0C7E\\u0CE6-\\u0CEF\\u0D58-\\u0D5E\\u0D66-\\u0D78\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F33\\u1040-\\u1049\\u1090-\\u1099\\u1369-\\u137C\\u16EE-\\u16F0\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19DA\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\u2070\\u2074-\\u2079\\u2080-\\u2089\\u2150-\\u2182\\u2185-\\u2189\\u2460-\\u249B\\u24EA-\\u24FF\\u2776-\\u2793\\u2CFD\\u3007\\u3021-\\u3029\\u3038-\\u303A\\u3192-\\u3195\\u3220-\\u3229\\u3248-\\u324F\\u3251-\\u325F\\u3280-\\u3289\\u32B1-\\u32BF\\uA620-\\uA629\\uA6E6-\\uA6EF\\uA830-\\uA835\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19\\u{10107}-\\u{10133}\\u{10140}-\\u{10178}\\u{1018A}-\\u{1018B}\\u{102E1}-\\u{102FB}\\u{10320}-\\u{10323}\\u{10341}\\u{1034A}\\u{103D1}-\\u{103D5}\\u{104A0}-\\u{104A9}\\u{10858}-\\u{1085F}\\u{10879}-\\u{1087F}\\u{108A7}-\\u{108AF}\\u{108FB}-\\u{108FF}\\u{10916}-\\u{1091B}\\u{109BC}-\\u{109BD}\\u{109C0}-\\u{109CF}\\u{109D2}-\\u{109FF}\\u{10A40}-\\u{10A48}\\u{10A7D}-\\u{10A7E}\\u{10A9D}-\\u{10A9F}\\u{10AEB}-\\u{10AEF}\\u{10B58}-\\u{10B5F}\\u{10B78}-\\u{10B7F}\\u{10BA9}-\\u{10BAF}\\u{10CFA}-\\u{10CFF}\\u{10D30}-\\u{10D39}\\u{10D40}-\\u{10D49}\\u{10E60}-\\u{10E7E}\\u{10F1D}-\\u{10F26}\\u{10F51}-\\u{10F54}\\u{10FC5}-\\u{10FCB}\\u{11052}-\\u{1106F}\\u{110F0}-\\u{110F9}\\u{11136}-\\u{1113F}\\u{111D0}-\\u{111D9}\\u{111E1}-\\u{111F4}\\u{112F0}-\\u{112F9}\\u{11450}-\\u{11459}\\u{114D0}-\\u{114D9}\\u{11650}-\\u{11659}\\u{116C0}-\\u{116C9}\\u{116D0}-\\u{116E3}\\u{11730}-\\u{1173B}\\u{118E0}-\\u{118F2}\\u{11950}-\\u{11959}\\u{11BF0}-\\u{11BF9}\\u{11C50}-\\u{11C6C}\\u{11D50}-\\u{11D59}\\u{11DA0}-\\u{11DA9}\\u{11DE0}-\\u{11DE9}\\u{11F50}-\\u{11F59}\\u{11FC0}-\\u{11FD4}\\u{12400}-\\u{1246E}\\u{16130}-\\u{16139}\\u{16A60}-\\u{16A69}\\u{16AC0}-\\u{16AC9}\\u{16B50}-\\u{16B59}\\u{16B5B}-\\u{16B61}\\u{16D70}-\\u{16D79}\\u{16E80}-\\u{16E96}\\u{16FF4}-\\u{16FF6}\\u{1CCF0}-\\u{1CCF9}\\u{1D2C0}-\\u{1D2D3}\\u{1D2E0}-\\u{1D2F3}\\u{1D360}-\\u{1D378}\\u{1D7CE}-\\u{1D7FF}\\u{1E140}-\\u{1E149}\\u{1E2F0}-\\u{1E2F9}\\u{1E4F0}-\\u{1E4F9}\\u{1E5F1}-\\u{1E5FA}\\u{1E8C7}-\\u{1E8CF}\\u{1E950}-\\u{1E959}\\u{1EC71}-\\u{1ECAB}\\u{1ECAD}-\\u{1ECAF}\\u{1ECB1}-\\u{1ECB4}\\u{1ED01}-\\u{1ED2D}\\u{1ED2F}-\\u{1ED3D}\\u{1F100}-\\u{1F10C}\\u{1FBF0}-\\u{1FBF9}]+", "gu"))) != null ? _text_match : []).length;
132
+ };
133
+ /** The input a page job carries, read defensively; `null` on every other job. */ export function aiSiteImportDocumentOf(inputs) {
134
+ const raw = inputs == null ? void 0 : inputs[AI_LAYOUT_IMPORTED_SECTIONS_INPUT];
135
+ if (!raw || typeof raw !== 'object') return null;
136
+ const value = raw;
137
+ const build = value['build'] === 'copied' || value['build'] === 'arranged' ? value['build'] : null;
138
+ if (!build || !Array.isArray(value['blocks'])) return null;
139
+ const blocks = value['blocks'].flatMap((entry)=>{
140
+ if (!entry || typeof entry !== 'object') return [];
141
+ const block = entry;
142
+ const text = typeof block['text'] === 'string' ? block['text'] : '';
143
+ const region = 'main';
144
+ switch(block['kind']){
145
+ case 'heading':
146
+ {
147
+ const level = Number(block['level']);
148
+ return [
149
+ {
150
+ kind: 'heading',
151
+ level: Number.isInteger(level) && level >= 1 && level <= 6 ? level : 2,
152
+ text,
153
+ region
154
+ }
155
+ ];
156
+ }
157
+ case 'paragraph':
158
+ case 'list-item':
159
+ case 'quote':
160
+ return [
161
+ {
162
+ kind: block['kind'],
163
+ text,
164
+ region
165
+ }
166
+ ];
167
+ case 'image':
168
+ return typeof block['url'] === 'string' ? [
169
+ {
170
+ kind: 'image',
171
+ url: block['url'],
172
+ alt: typeof block['alt'] === 'string' ? block['alt'] : '',
173
+ region
174
+ }
175
+ ] : [];
176
+ case 'link':
177
+ return typeof block['href'] === 'string' ? [
178
+ _extends({
179
+ kind: 'link',
180
+ text,
181
+ href: block['href'],
182
+ region
183
+ }, block['inline'] === true ? {
184
+ inline: true
185
+ } : {})
186
+ ] : [];
187
+ default:
188
+ return [];
189
+ }
190
+ });
191
+ const strings = (list)=>Array.isArray(list) ? list.filter((entry)=>typeof entry === 'string') : [];
192
+ return {
193
+ build,
194
+ title: typeof value['title'] === 'string' ? value['title'] : '',
195
+ url: typeof value['url'] === 'string' ? value['url'].slice(0, 2048) : '',
196
+ blocks,
197
+ photos: (Array.isArray(value['photos']) ? value['photos'] : []).flatMap((entry)=>{
198
+ const photo = entry;
199
+ return photo && typeof photo['mediaId'] === 'string' && typeof photo['src'] === 'string' ? [
200
+ _extends({
201
+ mediaId: photo['mediaId'],
202
+ src: photo['src']
203
+ }, typeof photo['alt'] === 'string' ? {
204
+ alt: photo['alt']
205
+ } : {}, typeof photo['from'] === 'string' ? {
206
+ from: photo['from']
207
+ } : {})
208
+ ] : [];
209
+ }),
210
+ links: (Array.isArray(value['links']) ? value['links'] : []).flatMap((entry)=>{
211
+ const link = entry;
212
+ return link && typeof link['path'] === 'string' && typeof link['id'] === 'string' ? [
213
+ {
214
+ path: link['path'],
215
+ id: link['id']
216
+ }
217
+ ] : [];
218
+ }),
219
+ origins: strings(value['origins'])
220
+ };
221
+ }
222
+ /*------------------------------------------
223
+ * Drawing the lines
224
+ *-----------------------------------------*/ /** A paragraph cut between sentences into parts a text element holds, every word kept in order. */ export function aiSiteImportTextParts(text, max = AI_SITE_IMPORT_TEXT_MAX_CHARS) {
225
+ var _words_match;
226
+ const words = clean(text);
227
+ if (words.length <= max) return words ? [
228
+ words
229
+ ] : [];
230
+ const sentences = (_words_match = words.match(/[^.!?…]+(?:[.!?…]+["'”’)\]]*\s*|$)/g)) != null ? _words_match : [
231
+ words
232
+ ];
233
+ const parts = [];
234
+ let part = '';
235
+ const push = ()=>{
236
+ if (part.trim()) parts.push(part.trim());
237
+ part = '';
238
+ };
239
+ for (const sentence of sentences){
240
+ if ((part + sentence).trim().length <= max) {
241
+ part += sentence;
242
+ continue;
243
+ }
244
+ push();
245
+ // One sentence longer than an element holds is cut between words.
246
+ let rest = sentence.trim();
247
+ while(rest.length > max){
248
+ const at = rest.lastIndexOf(' ', max);
249
+ const cut = at > 0 ? at : max;
250
+ parts.push(rest.slice(0, cut).trim());
251
+ rest = rest.slice(cut).trim();
252
+ }
253
+ part = rest ? `${rest} ` : '';
254
+ }
255
+ push();
256
+ return parts;
257
+ }
258
+ /** Whether the page has room for one more line of this many characters. */ function room(scope, chars) {
259
+ if (scope.cut) return false;
260
+ if (Object.keys(scope.tree.nodes).length >= AI_SITE_IMPORT_DOC_MAX_NODES || scope.chars + chars > AI_SITE_IMPORT_DOC_MAX_CHARS) {
261
+ scope.cut = true;
262
+ return false;
263
+ }
264
+ return true;
265
+ }
266
+ function took(scope, line) {
267
+ scope.placed.push(line.n);
268
+ const text = aiSiteImportLineText(line);
269
+ scope.chars += text.length;
270
+ if (line.block.kind !== 'image') scope.words += wordsIn(text);
271
+ }
272
+ /** A heading at its place in the outline: the page's one h1 first, then the section's h2, then h3 under it. */ function headingNode(scope, text, level, centered) {
273
+ // The outline never skips a level: an h3 straight under the h1 is drawn an h2.
274
+ const tag = !scope.titled ? 1 : Math.max(2, Math.min(3, level, scope.lastLevel + 1));
275
+ scope.titled = true;
276
+ scope.lastLevel = tag;
277
+ const variant = text.length > AI_SITE_IMPORT_HEADLINE_MAX_CHARS ? 'subtitle1' : tag === 1 ? 'h1' : tag === 2 ? 'h2' : 'h4';
278
+ return scope.tree.add('muiTypography', _extends({
279
+ children: text,
280
+ variant,
281
+ component: `h${tag}`
282
+ }, centered ? {
283
+ align: 'center'
284
+ } : {}), null, null, 'heading');
285
+ }
286
+ const VARIANTS = {
287
+ eyebrow: 'overline',
288
+ lede: 'lede',
289
+ text: 'body1',
290
+ note: 'body2'
291
+ };
292
+ /** Words in a style, split where a text element would cut them. */ function textNodes(scope, text, style, centered) {
293
+ return aiSiteImportTextParts(text).map((part)=>scope.tree.add('muiTypography', _extends({
294
+ children: part,
295
+ variant: VARIANTS[style],
296
+ component: 'p'
297
+ }, centered ? {
298
+ align: 'center'
299
+ } : {}), style === 'note' ? {
300
+ color: 'text.secondary'
301
+ } : null, null, style));
302
+ }
303
+ /** Where a link goes on the new site, or `null` where it goes nowhere a page of it may send a visitor. */ function linkProps(scope, href) {
304
+ if (/^mailto:[^\s@]+@[^\s@]+$/i.test(href) || /^tel:\+?[\d\s().-]{3,}$/i.test(href)) return {
305
+ href
306
+ };
307
+ let url;
308
+ try {
309
+ url = new URL(href);
310
+ } catch (unused) {
311
+ return null;
312
+ }
313
+ if (url.protocol !== 'https:' && url.protocol !== 'http:') return null;
314
+ if (scope.doc.origins.includes(url.origin)) {
315
+ // The old site's own page: the page it became, where that page may be linked.
316
+ const path = url.pathname.replace(/\/+$/, '') || '/';
317
+ const id = scope.pathTo.get(path);
318
+ return id && scope.pageIds.has(id) ? {
319
+ screenId: id
320
+ } : null;
321
+ }
322
+ return url.protocol === 'https:' ? {
323
+ href: url.toString(),
324
+ target: '_blank'
325
+ } : null;
326
+ }
327
+ /** A link line: a button that goes where the source's did, or its words as a line where it cannot. */ function linkNodes(scope, line, style, centered) {
328
+ const block = line.block;
329
+ if (block.kind !== 'link') return [];
330
+ const label = clean(block.text);
331
+ const goes = label.length <= AI_SITE_IMPORT_LABEL_CHARS ? linkProps(scope, block.href) : null;
332
+ if (!goes) return textNodes(scope, label, 'text', centered);
333
+ const look = style === 'primary' ? {
334
+ variant: 'contained',
335
+ color: 'primary'
336
+ } : style === 'secondary' ? {
337
+ variant: 'outlined',
338
+ color: 'primary'
339
+ } : {
340
+ variant: 'text',
341
+ color: 'primary'
342
+ };
343
+ return [
344
+ scope.tree.add('muiButton', _extends({
345
+ children: label
346
+ }, look, {
347
+ size: 'medium'
348
+ }, goes), {
349
+ alignSelf: centered ? 'center' : 'flex-start'
350
+ }, null, 'button')
351
+ ];
352
+ }
353
+ /** A picture line: the photo the library holds for it, or nothing where it could not be brought in. */ function imageNodes(scope, line) {
354
+ const block = line.block;
355
+ if (block.kind !== 'image') return [];
356
+ const photo = scope.photos.get(block.url);
357
+ if (!photo) return [];
358
+ const alt = clean(block.alt || photo.alt || '').slice(0, 200);
359
+ scope.pictures += 1;
360
+ return [
361
+ scope.tree.add('image', _extends({
362
+ src: photo.src
363
+ }, alt ? {
364
+ alt
365
+ } : {
366
+ decorative: true
367
+ }, {
368
+ objectFit: 'cover'
369
+ }, scope.pictures > 1 ? {
370
+ loading: 'lazy'
371
+ } : {}), null, null, 'image')
372
+ ];
373
+ }
374
+ /** One line in a style a block asked for; a picture is a picture and a link a link, wherever they are placed. */ function lineNodes(scope, line, style, centered, button = 'quiet') {
375
+ if (!room(scope, aiSiteImportLineText(line).length)) return [];
376
+ const block = line.block;
377
+ let ids;
378
+ if (block.kind === 'image') ids = imageNodes(scope, line);
379
+ else if (block.kind === 'link') ids = linkNodes(scope, line, button, centered);
380
+ else if (style === 'heading' || block.kind === 'heading' && style === 'text') ids = [
381
+ headingNode(scope, clean(block.text), block.kind === 'heading' ? block.level : 2, centered)
382
+ ];
383
+ else if (block.kind === 'quote' && style === 'text') {
384
+ ids = [
385
+ scope.tree.add('muiBox', {
386
+ component: 'blockquote'
387
+ }, null, textNodes(scope, block.text, 'text', centered), 'quote')
388
+ ];
389
+ } else ids = textNodes(scope, block.text, style, centered);
390
+ // A picture the library could not bring in is not on the page.
391
+ if (ids.length) took(scope, line);
392
+ return ids;
393
+ }
394
+ /** A run of lines as a list, one item each. */ function listNode(scope, lines) {
395
+ const rows = [];
396
+ const rest = [];
397
+ for (const line of lines){
398
+ if (line.block.kind === 'image' || line.block.kind === 'link') {
399
+ rest.push(...lineNodes(scope, line, 'text', false));
400
+ continue;
401
+ }
402
+ const text = aiSiteImportLineText(line);
403
+ if (!room(scope, text.length)) break;
404
+ for (const part of aiSiteImportTextParts(text)){
405
+ rows.push(scope.tree.add('muiListItem', {
406
+ disableGutters: true
407
+ }, null, [
408
+ scope.tree.add('muiListItemText', {
409
+ primary: part
410
+ }, null, null, 'line')
411
+ ], 'row'));
412
+ }
413
+ took(scope, line);
414
+ }
415
+ return [
416
+ ...rows.length ? [
417
+ scope.tree.add('muiList', {
418
+ disablePadding: true
419
+ }, null, rows, 'list')
420
+ ] : [],
421
+ ...rest
422
+ ];
423
+ }
424
+ /** A group's items, each a title line over its text lines, laid out side by side. */ function groupNode(scope, kind, items) {
425
+ const pairs = [];
426
+ const rest = [];
427
+ for (const item of items){
428
+ const words = item.filter((line)=>line.block.kind !== 'image' && line.block.kind !== 'link');
429
+ for (const line of item)if (line.block.kind === 'image' || line.block.kind === 'link') rest.push(...lineNodes(scope, line, 'text', false));
430
+ if (!words.length) continue;
431
+ const [title, ...body] = words;
432
+ const text = body.map(aiSiteImportLineText).join(' ');
433
+ if (!room(scope, aiSiteImportLineText(title).length + text.length)) break;
434
+ const primary = aiSiteImportLineText(title);
435
+ if (primary.length > AI_SITE_IMPORT_TEXT_MAX_CHARS || text.length > AI_SITE_IMPORT_TEXT_MAX_CHARS) {
436
+ // An item too long for its element is its lines, one under another.
437
+ for (const line of words)rest.push(...lineNodes(scope, line, 'text', false));
438
+ continue;
439
+ }
440
+ pairs.push(scope.tree.add('muiListItemText', _extends({
441
+ primary
442
+ }, text ? {
443
+ secondary: text
444
+ } : {}), null, null, 'pair'));
445
+ for (const line of words)took(scope, line);
446
+ }
447
+ if (!pairs.length) return rest;
448
+ const perRow = kind === 'faq' || kind === 'steps' || pairs.length === 1 ? 1 : Math.min(3, pairs.length);
449
+ if (perRow === 1) return [
450
+ scope.tree.add('muiStack', {
451
+ spacing: '3'
452
+ }, null, pairs, kind),
453
+ ...rest
454
+ ];
455
+ const size = perRow === 2 ? 'xs:12 sm:6' : 'xs:12 md:4';
456
+ const cells = pairs.map((id)=>scope.tree.add('muiGrid', {
457
+ size
458
+ }, null, [
459
+ id
460
+ ], 'cell'));
461
+ return [
462
+ scope.tree.add('muiGrid', {
463
+ container: true,
464
+ spacing: '3'
465
+ }, null, cells, kind),
466
+ ...rest
467
+ ];
468
+ }
469
+ /** A section root: its band, its container and its content, under the id its plan stores it by. */ function sectionNode(scope, index, name, band, parts, id, wide) {
470
+ const tree = scope.tree;
471
+ const content = parts.length === 1 ? parts[0] : tree.add('muiStack', {
472
+ spacing: '3',
473
+ useFlexGap: true
474
+ }, null, parts, 'content');
475
+ const container = tree.add('muiContainer', {
476
+ maxWidth: wide ? 'lg' : 'md'
477
+ }, {
478
+ py: _extends({}, SECTION_PADDING)
479
+ }, [
480
+ content
481
+ ], 'container');
482
+ return tree.add('section', _extends({
483
+ element: 'section',
484
+ ariaLabel: name || `Section ${index + 1}`
485
+ }, band === 'dark' ? {
486
+ colorScheme: 'dark'
487
+ } : {}), bandSx(band), [
488
+ container
489
+ ], 'section', id);
490
+ }
491
+ /** The lines of a section, in source order, as the source draws them: lists as lists, the rest one under another. */ function copiedParts(scope, lines) {
492
+ const parts = [];
493
+ for(let at = 0; at < lines.length; at += 1){
494
+ const line = lines[at];
495
+ if (line.block.kind === 'list-item') {
496
+ const run = [];
497
+ while(at < lines.length && lines[at].block.kind === 'list-item')run.push(lines[at++]);
498
+ at -= 1;
499
+ parts.push(...listNode(scope, run));
500
+ continue;
501
+ }
502
+ parts.push(...lineNodes(scope, line, 'text', false));
503
+ }
504
+ return parts;
505
+ }
506
+ /** One arranged block's lines, still unplaced and of its own section; `null` where it named a line already placed. */ function ownLines(lineOf, numbers, section, used) {
507
+ const lines = [];
508
+ for (const n of numbers){
509
+ const line = lineOf(n);
510
+ if (!line || line.section !== section) continue;
511
+ if (used.has(n)) return null;
512
+ lines.push(line);
513
+ }
514
+ return lines;
515
+ }
516
+ /** An arranged block drawn: its lines in the kind it asked for. */ function arrangedBlock(scope, block, lines, items, centered) {
517
+ switch(block.kind){
518
+ case 'list':
519
+ return listNode(scope, lines);
520
+ case 'cards':
521
+ case 'steps':
522
+ case 'stats':
523
+ case 'faq':
524
+ return groupNode(scope, block.kind, items.length ? items : lines.map((line)=>[
525
+ line
526
+ ]));
527
+ case 'button':
528
+ {
529
+ const style = block.style === 'primary' || block.style === 'secondary' ? block.style : 'quiet';
530
+ return lines.flatMap((line)=>lineNodes(scope, line, 'text', centered, style));
531
+ }
532
+ case 'image':
533
+ return lines.flatMap((line)=>lineNodes(scope, line, 'text', centered));
534
+ case 'heading':
535
+ case 'eyebrow':
536
+ case 'lede':
537
+ case 'note':
538
+ {
539
+ const style = block.kind;
540
+ return lines.flatMap((line, position)=>// A heading block's first line is the heading; any more are its words.
541
+ lineNodes(scope, line, style === 'heading' && position > 0 ? 'text' : style, centered));
542
+ }
543
+ default:
544
+ return lines.flatMap((line)=>lineNodes(scope, line, line.block.kind === 'heading' ? 'heading' : 'text', centered));
545
+ }
546
+ }
547
+ /** One section as the arrangement lays it out, every line of it that the arrangement left out added at its end. */ function arrangedParts(scope, arranged, index, lines, lineOf, used) {
548
+ const centered = arranged.align === 'center';
549
+ const cols = arranged.cols && arranged.cols.length >= 2 ? arranged.cols : null;
550
+ const head = [];
551
+ const tail = [];
552
+ const columns = cols ? cols.map(()=>[]) : [];
553
+ let placedInRow = false;
554
+ for (const block of arranged.blocks){
555
+ var _block_items, _block_items1;
556
+ const groups = AI_LAYOUT_ARRANGE_ITEM_KINDS.has(block.kind);
557
+ const named = groups && ((_block_items = block.items) == null ? void 0 : _block_items.length) ? block.items.flat() : block.from;
558
+ const taken = ownLines(lineOf, named, index, used);
559
+ // A block that names a line twice is dropped; its other lines are added at the end.
560
+ if (!(taken == null ? void 0 : taken.length)) continue;
561
+ for (const line of taken)used.add(line.n);
562
+ const items = groups && ((_block_items1 = block.items) == null ? void 0 : _block_items1.length) ? block.items.map((item)=>taken.filter((line)=>item.includes(line.n))).filter((item)=>item.length) : [];
563
+ const ids = arrangedBlock(scope, block, taken, items, centered && block.col === undefined);
564
+ if (cols && block.col !== undefined) {
565
+ columns[Math.min(block.col, cols.length - 1)].push(...ids);
566
+ placedInRow = true;
567
+ } else (placedInRow ? tail : head).push(...ids);
568
+ }
569
+ // Every line the arrangement did not place, in source order, at the section's end.
570
+ const left = lines.filter((line)=>!used.has(line.n));
571
+ for (const line of left)used.add(line.n);
572
+ tail.push(...copiedParts(scope, left));
573
+ const filled = columns.map((ids, position)=>{
574
+ var _ref;
575
+ return {
576
+ ids,
577
+ weight: (_ref = cols == null ? void 0 : cols[position]) != null ? _ref : 1
578
+ };
579
+ }).filter((entry)=>entry.ids.length);
580
+ const parts = [
581
+ ...head
582
+ ];
583
+ if (filled.length >= 2) {
584
+ const spans = aiLayoutSpans(filled.map((entry)=>entry.weight));
585
+ const cells = filled.map((entry, position)=>scope.tree.add('muiGrid', {
586
+ size: `xs:12 md:${spans[position]}`
587
+ }, null, [
588
+ entry.ids.length === 1 ? entry.ids[0] : scope.tree.add('muiStack', {
589
+ spacing: '3'
590
+ }, null, entry.ids, 'column')
591
+ ], 'cell'));
592
+ parts.push(scope.tree.add('muiGrid', {
593
+ container: true,
594
+ spacing: '6'
595
+ }, null, cells, 'row'));
596
+ } else if (filled.length === 1) parts.push(...filled[0].ids);
597
+ parts.push(...tail);
598
+ return {
599
+ parts,
600
+ wide: filled.length >= 2
601
+ };
602
+ }
603
+ /**
604
+ * The page brought in, compiled into its tree (AGL-4084): copied as the
605
+ * source has it, or as the arrangement lays it out, with every line on it
606
+ * exactly once in either case and never a word that is not the source's.
607
+ */ export function aiCompileImportedDocument(input) {
608
+ const { doc } = input;
609
+ const { lines, sections } = aiSiteImportDocLines(doc.blocks, doc.title);
610
+ const tree = new AiLayoutTreeBuilder('li');
611
+ const pageIds = new Set(input.pages.map((page)=>page.id));
612
+ const scope = {
613
+ tree,
614
+ doc,
615
+ pageIds,
616
+ pathTo: new Map(doc.links.map((link)=>[
617
+ link.path.replace(/\/+$/, '') || '/',
618
+ link.id
619
+ ])),
620
+ photos: new Map(doc.photos.flatMap((photo)=>photo.from ? [
621
+ [
622
+ photo.from,
623
+ photo
624
+ ]
625
+ ] : [])),
626
+ titled: false,
627
+ lastLevel: 1,
628
+ pictures: 0,
629
+ placed: [],
630
+ words: 0,
631
+ chars: 0,
632
+ cut: false
633
+ };
634
+ const lineOf = (n)=>lines[n - 1];
635
+ const used = new Set();
636
+ const arranged = doc.build === 'arranged' ? input.arrangement : null;
637
+ // An arranged opening with no heading block takes its first heading line as one, so the page keeps its h1.
638
+ const opening = arranged == null ? void 0 : arranged.sections[0];
639
+ if (opening && !opening.blocks.some((block)=>block.kind === 'heading')) {
640
+ const first = opening.blocks.find((block)=>block.from.some((n)=>{
641
+ var _lineOf;
642
+ return ((_lineOf = lineOf(n)) == null ? void 0 : _lineOf.block.kind) === 'heading';
643
+ }));
644
+ if (first && !AI_LAYOUT_ARRANGE_ITEM_KINDS.has(first.kind) && first.kind !== 'list') first.kind = 'heading';
645
+ }
646
+ const roots = sections.map((section, index)=>{
647
+ var _ref, _ref1, _input_sectionIds_index;
648
+ var _arranged_sections_;
649
+ const own = section.lines.map(lineOf);
650
+ // The page's h1: its title, where its opening shows no heading of its own.
651
+ const titleParts = [];
652
+ if (index === 0 && !own.some((line)=>line.block.kind === 'heading') && !(arranged == null ? void 0 : (_arranged_sections_ = arranged.sections[0]) == null ? void 0 : _arranged_sections_.blocks.some((block)=>block.kind === 'heading'))) {
653
+ titleParts.push(headingNode(scope, clean(doc.title) || section.name, 1, false));
654
+ }
655
+ const plan = (_ref = arranged == null ? void 0 : arranged.sections[index]) != null ? _ref : null;
656
+ const drawn = plan ? arrangedParts(scope, plan, index, own, lineOf, used) : {
657
+ parts: copiedParts(scope, own.filter((line)=>!used.has(line.n))),
658
+ wide: false
659
+ };
660
+ for (const line of own)used.add(line.n);
661
+ const band = (_ref1 = plan == null ? void 0 : plan.band) != null ? _ref1 : index % 2 === 1 ? 'soft' : 'plain';
662
+ const parts = [
663
+ ...titleParts,
664
+ ...drawn.parts
665
+ ];
666
+ if (!parts.length) {
667
+ // A section whose lines could not come through (its pictures, the page's weight) keeps its place by its name.
668
+ parts.push(headingNode(scope, section.name, 2, false));
669
+ }
670
+ return sectionNode(scope, index, section.name, band, parts, (_input_sectionIds_index = input.sectionIds[index]) != null ? _input_sectionIds_index : `section-${index + 1}`, drawn.wide);
671
+ });
672
+ const rootId = tree.add('div', null, null, roots, 'page', CANVAS_ROOT_ELEMENT_ID);
673
+ for (const root of roots)tree.prune(root);
674
+ const sourceWords = lines.reduce((total, line)=>total + (line.block.kind === 'image' ? 0 : wordsIn(aiSiteImportLineText(line))), 0);
675
+ return {
676
+ tree: {
677
+ rootId,
678
+ nodes: tree.nodes
679
+ },
680
+ placed: scope.placed,
681
+ lines: lines.length,
682
+ words: scope.words,
683
+ sourceWords,
684
+ cut: scope.cut
685
+ };
686
+ }
687
+ /*------------------------------------------
688
+ * What the arrangement is shown
689
+ *-----------------------------------------*/ /** The most characters of a page's numbered lines an arrangement prompt shows. */ export const AI_SITE_IMPORT_ARRANGE_MAX_CHARS = 60000;
690
+ const LINE_KIND = {
691
+ heading: 'heading',
692
+ paragraph: 'text',
693
+ 'list-item': 'list item',
694
+ quote: 'quote',
695
+ link: 'link',
696
+ image: 'picture'
697
+ };
698
+ /** The page's lines as the arrangement reads them: each section, its numbered lines and their kinds. */ export function aiSiteImportArrangeText(doc) {
699
+ const { lines, sections } = aiSiteImportDocLines(doc.blocks, doc.title);
700
+ return sections.map((section, index)=>[
701
+ `Section ${index + 1}: ${section.name}`,
702
+ ...section.lines.map((n)=>{
703
+ const line = lines[n - 1];
704
+ const kind = line.block.kind === 'heading' ? `heading ${line.block.level}` : LINE_KIND[line.block.kind];
705
+ return `[${n}] (${kind}) ${aiSiteImportLineText(line) || '(no description)'}`;
706
+ })
707
+ ].join('\n')).join('\n\n');
708
+ }
709
+
710
+ //# sourceMappingURL=ai-site-import-document.js.map