@webstudio-is/sdk 0.263.0 → 0.265.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -97,10 +97,6 @@ var commonPageFields = {
97
97
  )
98
98
  };
99
99
  var HomePagePath = z2.string().refine((path) => path === "", "Home page path must be empty");
100
- var HomePage = z2.object({
101
- ...commonPageFields,
102
- path: HomePagePath
103
- });
104
100
  var DefaultPagePage = z2.string().refine((path) => path !== "", "Can't be empty").refine((path) => path !== "/", "Can't be just a /").refine((path) => path.endsWith("/") === false, "Can't end with a /").refine((path) => path.includes("//") === false, "Can't contain repeating /").refine(
105
101
  (path) => /^[-_a-z0-9*:?\\/.]*$/.test(path),
106
102
  "Only a-z, 0-9, -, _, /, :, ?, . and * are allowed"
@@ -133,7 +129,7 @@ var PagePath = DefaultPagePage.refine(
133
129
  );
134
130
  var Page = z2.object({
135
131
  ...commonPageFields,
136
- path: PagePath
132
+ path: z2.union([HomePagePath, PagePath])
137
133
  });
138
134
  var ProjectMeta = z2.object({
139
135
  // All fields are optional to ensure consistency and allow for the addition of new fields without requiring migration
@@ -163,9 +159,123 @@ var Pages = z2.object({
163
159
  meta: ProjectMeta.optional(),
164
160
  compiler: CompilerSettings.optional(),
165
161
  redirects: z2.array(PageRedirect).optional(),
166
- homePage: HomePage,
167
- pages: z2.array(Page),
168
- folders: z2.array(Folder).refine((folders) => folders.length > 0, "Folders can't be empty")
162
+ homePageId: PageId,
163
+ rootFolderId: FolderId,
164
+ pages: z2.map(PageId, Page),
165
+ folders: z2.map(FolderId, Folder).refine((folders) => folders.size > 0, "Folders can't be empty")
166
+ }).superRefine((pages, context) => {
167
+ const homePage = pages.pages.get(pages.homePageId);
168
+ const rootFolder = pages.folders.get(pages.rootFolderId);
169
+ if (homePage === void 0) {
170
+ context.addIssue({
171
+ code: z2.ZodIssueCode.custom,
172
+ path: ["homePageId"],
173
+ message: "Home page must reference an existing page"
174
+ });
175
+ }
176
+ if (rootFolder === void 0) {
177
+ context.addIssue({
178
+ code: z2.ZodIssueCode.custom,
179
+ path: ["rootFolderId"],
180
+ message: "Root folder must reference an existing folder"
181
+ });
182
+ }
183
+ if (homePage !== void 0 && homePage.path !== "") {
184
+ context.addIssue({
185
+ code: z2.ZodIssueCode.custom,
186
+ path: ["pages", pages.homePageId, "path"],
187
+ message: "Home page path must be empty"
188
+ });
189
+ }
190
+ for (const [pageId, page] of pages.pages) {
191
+ if (page.id !== pageId) {
192
+ context.addIssue({
193
+ code: z2.ZodIssueCode.custom,
194
+ path: ["pages", pageId, "id"],
195
+ message: "Page id must match its record key"
196
+ });
197
+ }
198
+ if (pageId !== pages.homePageId && page.path === "") {
199
+ context.addIssue({
200
+ code: z2.ZodIssueCode.custom,
201
+ path: ["pages", pageId, "path"],
202
+ message: "Page path can't be empty"
203
+ });
204
+ }
205
+ }
206
+ for (const [folderId, folder] of pages.folders) {
207
+ if (folder.id !== folderId) {
208
+ context.addIssue({
209
+ code: z2.ZodIssueCode.custom,
210
+ path: ["folders", folderId, "id"],
211
+ message: "Folder id must match its record key"
212
+ });
213
+ }
214
+ for (const [index, childId] of folder.children.entries()) {
215
+ if (pages.pages.has(childId) === false && pages.folders.has(childId) === false) {
216
+ context.addIssue({
217
+ code: z2.ZodIssueCode.custom,
218
+ path: ["folders", folderId, "children", index],
219
+ message: "Folder child must reference an existing page or folder"
220
+ });
221
+ }
222
+ if (childId === pages.rootFolderId) {
223
+ context.addIssue({
224
+ code: z2.ZodIssueCode.custom,
225
+ path: ["folders", folderId, "children", index],
226
+ message: "Root folder can't be nested"
227
+ });
228
+ }
229
+ }
230
+ }
231
+ if (rootFolder !== void 0 && rootFolder.children[0] !== pages.homePageId) {
232
+ context.addIssue({
233
+ code: z2.ZodIssueCode.custom,
234
+ path: ["folders", pages.rootFolderId, "children"],
235
+ message: "Root folder must start with the home page"
236
+ });
237
+ }
238
+ const childParents = /* @__PURE__ */ new Map();
239
+ for (const [folderId, folder] of pages.folders) {
240
+ for (const [index, childId] of folder.children.entries()) {
241
+ const parentId = childParents.get(childId);
242
+ if (parentId !== void 0) {
243
+ context.addIssue({
244
+ code: z2.ZodIssueCode.custom,
245
+ path: ["folders", folderId, "children", index],
246
+ message: `Child is already registered in folder "${parentId}"`
247
+ });
248
+ continue;
249
+ }
250
+ childParents.set(childId, folderId);
251
+ }
252
+ }
253
+ const hasFolderCycle = (folderId, path = /* @__PURE__ */ new Set()) => {
254
+ if (path.has(folderId)) {
255
+ return true;
256
+ }
257
+ const folder = pages.folders.get(folderId);
258
+ if (folder === void 0) {
259
+ return false;
260
+ }
261
+ path.add(folderId);
262
+ for (const childId of folder.children) {
263
+ if (pages.folders.has(childId) && hasFolderCycle(childId, path)) {
264
+ return true;
265
+ }
266
+ }
267
+ path.delete(folderId);
268
+ return false;
269
+ };
270
+ for (const folderId of pages.folders.keys()) {
271
+ if (hasFolderCycle(folderId)) {
272
+ context.addIssue({
273
+ code: z2.ZodIssueCode.custom,
274
+ path: ["folders", folderId, "children"],
275
+ message: "Folders can't contain cycles"
276
+ });
277
+ }
278
+ }
169
279
  });
170
280
 
171
281
  // src/schema/instances.ts
@@ -700,7 +810,8 @@ import { z as z14 } from "zod";
700
810
  var common = {
701
811
  label: z14.string().optional(),
702
812
  description: z14.string().optional(),
703
- required: z14.boolean()
813
+ required: z14.boolean(),
814
+ contentMode: z14.boolean().optional()
704
815
  };
705
816
  var Tag = z14.object({
706
817
  ...common,
@@ -2364,16 +2475,36 @@ var isAbsoluteUrl = (href) => {
2364
2475
  // src/page-utils.ts
2365
2476
  var ROOT_FOLDER_ID = "root";
2366
2477
  var isRootFolder = ({ id }) => id === ROOT_FOLDER_ID;
2478
+ var getPageById = (pages, pageId) => {
2479
+ return pages.pages.get(pageId);
2480
+ };
2481
+ var getFolderById = (pages, folderId) => {
2482
+ return pages.folders.get(folderId);
2483
+ };
2484
+ var getAllPages = (pages) => {
2485
+ return Array.from(pages.pages.values());
2486
+ };
2487
+ var getAllFolders = (pages) => {
2488
+ return Array.from(pages.folders.values());
2489
+ };
2490
+ var getHomePage = (pages) => {
2491
+ const homePage = getPageById(pages, pages.homePageId);
2492
+ if (homePage === void 0) {
2493
+ throw new Error(`Home page "${pages.homePageId}" was not found.`);
2494
+ }
2495
+ return homePage;
2496
+ };
2367
2497
  var findPageByIdOrPath = (idOrPath, pages) => {
2368
- if (idOrPath === "" || idOrPath === "/" || idOrPath === pages.homePage.id) {
2369
- return pages.homePage;
2498
+ if (idOrPath === "" || idOrPath === "/" || idOrPath === pages.homePageId) {
2499
+ return getHomePage(pages);
2370
2500
  }
2371
- return pages.pages.find(
2501
+ return getAllPages(pages).find(
2372
2502
  (page) => page.id === idOrPath || getPagePath(page.id, pages) === idOrPath
2373
2503
  );
2374
2504
  };
2375
2505
  var findParentFolderByChildId = (id, folders) => {
2376
- for (const folder of folders) {
2506
+ const folderList = folders instanceof Map ? folders.values() : folders;
2507
+ for (const folder of folderList) {
2377
2508
  if (folder.children.includes(id)) {
2378
2509
  return folder;
2379
2510
  }
@@ -2382,7 +2513,7 @@ var findParentFolderByChildId = (id, folders) => {
2382
2513
  var getPagePath = (id, pages) => {
2383
2514
  const foldersMap = /* @__PURE__ */ new Map();
2384
2515
  const childParentMap = /* @__PURE__ */ new Map();
2385
- for (const folder of pages.folders) {
2516
+ for (const folder of getAllFolders(pages)) {
2386
2517
  foldersMap.set(folder.id, folder);
2387
2518
  for (const childId of folder.children) {
2388
2519
  childParentMap.set(childId, folder.id);
@@ -2390,7 +2521,7 @@ var getPagePath = (id, pages) => {
2390
2521
  }
2391
2522
  const paths = [];
2392
2523
  let currentId = id;
2393
- const allPages = [pages.homePage, ...pages.pages];
2524
+ const allPages = getAllPages(pages);
2394
2525
  for (const page of allPages) {
2395
2526
  if (page.id === id) {
2396
2527
  paths.push(page.path);
@@ -2409,7 +2540,7 @@ var getPagePath = (id, pages) => {
2409
2540
  return paths.reverse().join("/").replace(/\/+/g, "/");
2410
2541
  };
2411
2542
  var getStaticSiteMapXml = (pages, updatedAt) => {
2412
- const allPages = [pages.homePage, ...pages.pages];
2543
+ const allPages = getAllPages(pages);
2413
2544
  return allPages.filter((page) => (page.meta.documentType ?? "html") === "html").filter(
2414
2545
  (page) => executeExpression(page.meta.excludePageFromSearch) !== true
2415
2546
  ).filter((page) => false === isPathnamePattern(page.path)).map((page) => ({
@@ -2418,6 +2549,117 @@ var getStaticSiteMapXml = (pages, updatedAt) => {
2418
2549
  }));
2419
2550
  };
2420
2551
 
2552
+ // src/migrations/pages.ts
2553
+ var toMap = (items, normalizeItem = (item) => item) => {
2554
+ if (items instanceof Map) {
2555
+ return new Map(
2556
+ Array.from(items, ([id, item]) => [id, normalizeItem(item)])
2557
+ );
2558
+ }
2559
+ const list = Array.isArray(items) ? items : Object.values(items);
2560
+ return new Map(list.map((item) => [item.id, normalizeItem(item)]));
2561
+ };
2562
+ var normalizePage = (page) => ({
2563
+ ...page,
2564
+ meta: page.meta ?? {}
2565
+ });
2566
+ var isLegacyPages = (pages) => {
2567
+ if (typeof pages !== "object" || pages === null) {
2568
+ return false;
2569
+ }
2570
+ return "homePage" in pages && Array.isArray(pages.pages);
2571
+ };
2572
+ var isSerializedPages = (pages) => {
2573
+ if (typeof pages !== "object" || pages === null) {
2574
+ return false;
2575
+ }
2576
+ const candidate = pages;
2577
+ return typeof candidate.homePageId === "string" && typeof candidate.rootFolderId === "string" && candidate.pages !== void 0 && candidate.folders !== void 0;
2578
+ };
2579
+ var serializePages = (pages) => {
2580
+ const parsedPages = Pages.parse(pages);
2581
+ return {
2582
+ meta: parsedPages.meta,
2583
+ compiler: parsedPages.compiler,
2584
+ redirects: parsedPages.redirects,
2585
+ homePageId: parsedPages.homePageId,
2586
+ rootFolderId: parsedPages.rootFolderId,
2587
+ pages: Array.from(parsedPages.pages.values()),
2588
+ folders: Array.from(parsedPages.folders.values())
2589
+ };
2590
+ };
2591
+ var migratePages = (pages) => {
2592
+ if (isSerializedPages(pages) && pages.pages instanceof Map && pages.folders instanceof Map) {
2593
+ return pages;
2594
+ }
2595
+ if (isSerializedPages(pages)) {
2596
+ return {
2597
+ meta: pages.meta,
2598
+ compiler: pages.compiler,
2599
+ redirects: pages.redirects,
2600
+ homePageId: pages.homePageId,
2601
+ rootFolderId: pages.rootFolderId,
2602
+ pages: toMap(pages.pages, normalizePage),
2603
+ folders: toMap(pages.folders)
2604
+ };
2605
+ }
2606
+ if (isLegacyPages(pages) === false) {
2607
+ throw new Error("Pages data has unsupported shape.");
2608
+ }
2609
+ const homePage = {
2610
+ ...normalizePage(pages.homePage),
2611
+ path: ""
2612
+ };
2613
+ const nextPages = /* @__PURE__ */ new Map([[homePage.id, homePage]]);
2614
+ for (const page of pages.pages) {
2615
+ if (page.id === homePage.id) {
2616
+ continue;
2617
+ }
2618
+ nextPages.set(page.id, normalizePage(page));
2619
+ }
2620
+ const nextFolders = /* @__PURE__ */ new Map();
2621
+ for (const folder of pages.folders ?? []) {
2622
+ nextFolders.set(folder.id, { ...folder, children: [...folder.children] });
2623
+ }
2624
+ const rootFolder = Array.from(nextFolders.values()).find(isRootFolder) ?? pages.folders?.[0] ?? {
2625
+ id: ROOT_FOLDER_ID,
2626
+ name: "Root",
2627
+ slug: "",
2628
+ children: []
2629
+ };
2630
+ if (nextFolders.has(rootFolder.id) === false) {
2631
+ nextFolders.set(rootFolder.id, { ...rootFolder, children: [] });
2632
+ }
2633
+ const nextRootFolder = nextFolders.get(rootFolder.id);
2634
+ if (nextRootFolder === void 0) {
2635
+ throw new Error("Pages must include a root folder.");
2636
+ }
2637
+ for (const folder of nextFolders.values()) {
2638
+ folder.children = folder.children.filter(
2639
+ (childId) => childId !== homePage.id
2640
+ );
2641
+ }
2642
+ nextRootFolder.children.unshift(homePage.id);
2643
+ const referencedIds = new Set(
2644
+ Array.from(nextFolders.values()).flatMap((folder) => folder.children)
2645
+ );
2646
+ for (const page of pages.pages) {
2647
+ if (page.id !== homePage.id && referencedIds.has(page.id) === false) {
2648
+ nextRootFolder.children.push(page.id);
2649
+ referencedIds.add(page.id);
2650
+ }
2651
+ }
2652
+ return {
2653
+ meta: pages.meta,
2654
+ compiler: pages.compiler,
2655
+ redirects: pages.redirects,
2656
+ homePageId: homePage.id,
2657
+ rootFolderId: rootFolder.id,
2658
+ pages: nextPages,
2659
+ folders: nextFolders
2660
+ };
2661
+ };
2662
+
2421
2663
  // src/scope.ts
2422
2664
  import reservedIdentifiers from "reserved-identifiers";
2423
2665
  var identifiers = reservedIdentifiers({ includeGlobalProperties: true });
@@ -3008,6 +3250,7 @@ export {
3008
3250
  FONT_EXTENSIONS,
3009
3251
  FileAsset,
3010
3252
  Folder,
3253
+ FolderId,
3011
3254
  FolderName,
3012
3255
  FontAsset,
3013
3256
  HomePagePath,
@@ -3021,6 +3264,7 @@ export {
3021
3264
  Instances,
3022
3265
  MIME_CATEGORIES,
3023
3266
  OldPagePath,
3267
+ PageId,
3024
3268
  PageName,
3025
3269
  PagePath,
3026
3270
  PageRedirect,
@@ -3087,12 +3331,17 @@ export {
3087
3331
  generateObjectExpression,
3088
3332
  generatePageMeta,
3089
3333
  generateResources,
3334
+ getAllFolders,
3335
+ getAllPages,
3090
3336
  getAssetMime,
3091
3337
  getAssetUrl,
3092
3338
  getExpressionIdentifiers,
3339
+ getFolderById,
3340
+ getHomePage,
3093
3341
  getIndexesWithinAncestors,
3094
3342
  getMimeTypeByExtension,
3095
3343
  getMimeTypeByFilename,
3344
+ getPageById,
3096
3345
  getPagePath,
3097
3346
  getStaticSiteMapXml,
3098
3347
  getStyleDeclKey,
@@ -3108,6 +3357,7 @@ export {
3108
3357
  isRootFolder,
3109
3358
  lintExpression,
3110
3359
  matchPathnameParams,
3360
+ migratePages,
3111
3361
  parseComponentName,
3112
3362
  parseObjectExpression,
3113
3363
  portalComponent,
@@ -3115,6 +3365,7 @@ export {
3115
3365
  replaceFormActionsWithResources,
3116
3366
  rootComponent,
3117
3367
  scrollAnimationSchema,
3368
+ serializePages,
3118
3369
  systemParameter,
3119
3370
  tags,
3120
3371
  toRuntimeAsset,
@@ -0,0 +1,163 @@
1
+ // src/page-utils.ts
2
+ var ROOT_FOLDER_ID = "root";
3
+ var isRootFolder = ({ id }) => id === ROOT_FOLDER_ID;
4
+
5
+ // src/migrations/pages.ts
6
+ var toMap = (items, normalizeItem = (item) => item) => {
7
+ if (items instanceof Map) {
8
+ return new Map(
9
+ Array.from(items, ([id, item]) => [id, normalizeItem(item)])
10
+ );
11
+ }
12
+ const list = Array.isArray(items) ? items : Object.values(items);
13
+ return new Map(list.map((item) => [item.id, normalizeItem(item)]));
14
+ };
15
+ var normalizePage = (page) => ({
16
+ ...page,
17
+ meta: page.meta ?? {}
18
+ });
19
+ var isLegacyPages = (pages) => {
20
+ if (typeof pages !== "object" || pages === null) {
21
+ return false;
22
+ }
23
+ return "homePage" in pages && Array.isArray(pages.pages);
24
+ };
25
+ var isSerializedPages = (pages) => {
26
+ if (typeof pages !== "object" || pages === null) {
27
+ return false;
28
+ }
29
+ const candidate = pages;
30
+ return typeof candidate.homePageId === "string" && typeof candidate.rootFolderId === "string" && candidate.pages !== void 0 && candidate.folders !== void 0;
31
+ };
32
+ var migratePages = (pages) => {
33
+ if (isSerializedPages(pages) && pages.pages instanceof Map && pages.folders instanceof Map) {
34
+ return pages;
35
+ }
36
+ if (isSerializedPages(pages)) {
37
+ return {
38
+ meta: pages.meta,
39
+ compiler: pages.compiler,
40
+ redirects: pages.redirects,
41
+ homePageId: pages.homePageId,
42
+ rootFolderId: pages.rootFolderId,
43
+ pages: toMap(pages.pages, normalizePage),
44
+ folders: toMap(pages.folders)
45
+ };
46
+ }
47
+ if (isLegacyPages(pages) === false) {
48
+ throw new Error("Pages data has unsupported shape.");
49
+ }
50
+ const homePage = {
51
+ ...normalizePage(pages.homePage),
52
+ path: ""
53
+ };
54
+ const nextPages = /* @__PURE__ */ new Map([[homePage.id, homePage]]);
55
+ for (const page of pages.pages) {
56
+ if (page.id === homePage.id) {
57
+ continue;
58
+ }
59
+ nextPages.set(page.id, normalizePage(page));
60
+ }
61
+ const nextFolders = /* @__PURE__ */ new Map();
62
+ for (const folder of pages.folders ?? []) {
63
+ nextFolders.set(folder.id, { ...folder, children: [...folder.children] });
64
+ }
65
+ const rootFolder = Array.from(nextFolders.values()).find(isRootFolder) ?? pages.folders?.[0] ?? {
66
+ id: ROOT_FOLDER_ID,
67
+ name: "Root",
68
+ slug: "",
69
+ children: []
70
+ };
71
+ if (nextFolders.has(rootFolder.id) === false) {
72
+ nextFolders.set(rootFolder.id, { ...rootFolder, children: [] });
73
+ }
74
+ const nextRootFolder = nextFolders.get(rootFolder.id);
75
+ if (nextRootFolder === void 0) {
76
+ throw new Error("Pages must include a root folder.");
77
+ }
78
+ for (const folder of nextFolders.values()) {
79
+ folder.children = folder.children.filter(
80
+ (childId) => childId !== homePage.id
81
+ );
82
+ }
83
+ nextRootFolder.children.unshift(homePage.id);
84
+ const referencedIds = new Set(
85
+ Array.from(nextFolders.values()).flatMap((folder) => folder.children)
86
+ );
87
+ for (const page of pages.pages) {
88
+ if (page.id !== homePage.id && referencedIds.has(page.id) === false) {
89
+ nextRootFolder.children.push(page.id);
90
+ referencedIds.add(page.id);
91
+ }
92
+ }
93
+ return {
94
+ meta: pages.meta,
95
+ compiler: pages.compiler,
96
+ redirects: pages.redirects,
97
+ homePageId: homePage.id,
98
+ rootFolderId: rootFolder.id,
99
+ pages: nextPages,
100
+ folders: nextFolders
101
+ };
102
+ };
103
+
104
+ // src/migrations/styles.ts
105
+ import { hyphenateProperty, toValue } from "@webstudio-is/css-engine";
106
+ import {
107
+ camelCaseProperty,
108
+ expandShorthands,
109
+ parseCssValue
110
+ } from "@webstudio-is/css-data";
111
+
112
+ // src/schema/styles.ts
113
+ import { z } from "zod";
114
+ import { StyleValue } from "@webstudio-is/css-engine";
115
+ var StyleDeclRaw = z.object({
116
+ styleSourceId: z.string(),
117
+ breakpointId: z.string(),
118
+ state: z.optional(z.string()),
119
+ // @todo can't figure out how to make property to be enum
120
+ property: z.string(),
121
+ value: StyleValue,
122
+ listed: z.boolean().optional().describe("Whether the style is from the Advanced panel")
123
+ });
124
+ var StyleDecl = StyleDeclRaw;
125
+ var getStyleDeclKey = (styleDecl) => {
126
+ return `${styleDecl.styleSourceId}:${styleDecl.breakpointId}:${styleDecl.property}:${styleDecl.state ?? ""}`;
127
+ };
128
+ var Styles = z.map(z.string(), StyleDecl);
129
+
130
+ // src/migrations/styles.ts
131
+ var migratedShorthands = /* @__PURE__ */ new Set([
132
+ "overflow",
133
+ "transition",
134
+ "white-space",
135
+ "background-position"
136
+ ]);
137
+ var migrateStylesMutable = (styles) => {
138
+ for (const [styleDeclKey, styleDecl] of styles) {
139
+ const property = hyphenateProperty(styleDecl.property);
140
+ if (migratedShorthands.has(property) === false) {
141
+ continue;
142
+ }
143
+ styles.delete(styleDeclKey);
144
+ const longhands = expandShorthands([[property, toValue(styleDecl.value)]]);
145
+ for (const [hyphenedProperty, value] of longhands) {
146
+ const longhandStyleDecl = {
147
+ ...styleDecl,
148
+ property: camelCaseProperty(hyphenedProperty),
149
+ value: parseCssValue(hyphenedProperty, value)
150
+ };
151
+ styles.set(getStyleDeclKey(longhandStyleDecl), longhandStyleDecl);
152
+ }
153
+ }
154
+ };
155
+
156
+ // src/migrations/webstudio-data.ts
157
+ var migrateWebstudioDataMutable = (data) => {
158
+ data.pages = migratePages(data.pages);
159
+ migrateStylesMutable(data.styles);
160
+ };
161
+ export {
162
+ migrateWebstudioDataMutable
163
+ };
@@ -16,6 +16,7 @@ export * from "./assets";
16
16
  export * from "./core-metas";
17
17
  export * from "./instances-utils";
18
18
  export * from "./page-utils";
19
+ export * from "./migrations";
19
20
  export * from "./scope";
20
21
  export * from "./expression";
21
22
  export * from "./resources-generator";
@@ -0,0 +1 @@
1
+ export * from "./pages";
@@ -0,0 +1,7 @@
1
+ import { type Folder, type Page, type Pages } from "../schema/pages";
2
+ export type SerializedPages = Omit<Pages, "pages" | "folders"> & {
3
+ pages: Page[];
4
+ folders: Folder[];
5
+ };
6
+ export declare const serializePages: (pages: Pages) => SerializedPages;
7
+ export declare const migratePages: (pages: unknown) => Pages;
@@ -0,0 +1,2 @@
1
+ import type { Styles } from "../schema/styles";
2
+ export declare const migrateStylesMutable: (styles: Styles) => void;
@@ -0,0 +1,8 @@
1
+ import type { WebstudioData } from "../schema/webstudio";
2
+ /**
3
+ * Normalizes persisted project data after loading.
4
+ *
5
+ * This is intentionally idempotent because data can pass through multiple
6
+ * load boundaries before all callers stop seeing older persisted shapes.
7
+ */
8
+ export declare const migrateWebstudioDataMutable: (data: WebstudioData) => void;
@@ -6,6 +6,11 @@ export declare const ROOT_FOLDER_ID = "root";
6
6
  export declare const isRootFolder: ({ id }: {
7
7
  id: Folder["id"];
8
8
  }) => boolean;
9
+ export declare const getPageById: (pages: Pages, pageId: Page["id"]) => Page | undefined;
10
+ export declare const getFolderById: (pages: Pages, folderId: Folder["id"]) => Folder | undefined;
11
+ export declare const getAllPages: (pages: Pages) => Page[];
12
+ export declare const getAllFolders: (pages: Pages) => Folder[];
13
+ export declare const getHomePage: (pages: Pages) => Page;
9
14
  /**
10
15
  * Find a page by id or path.
11
16
  */
@@ -13,7 +18,7 @@ export declare const findPageByIdOrPath: (idOrPath: string, pages: Pages) => Pag
13
18
  /**
14
19
  * Find a folder that has has that id in the children.
15
20
  */
16
- export declare const findParentFolderByChildId: (id: Folder["id"] | Page["id"], folders: Array<Folder>) => Folder | undefined;
21
+ export declare const findParentFolderByChildId: (id: Folder["id"] | Page["id"], folders: Iterable<Folder> | Map<Folder["id"], Folder>) => Folder | undefined;
17
22
  /**
18
23
  * Get a path from all folder slugs from root to the current folder or page.
19
24
  */