@webstudio-is/sdk 0.267.0 → 0.269.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
@@ -44,6 +44,7 @@ var Assets = z.map(AssetId, Asset);
44
44
 
45
45
  // src/schema/pages.ts
46
46
  import { z as z2 } from "zod";
47
+ import { validateBasicAuth } from "@webstudio-is/wsauth";
47
48
  var MIN_TITLE_LENGTH = 2;
48
49
  var PageId = z2.string();
49
50
  var FolderId = z2.string();
@@ -63,7 +64,36 @@ var PageTitle = z2.string().refine(
63
64
  (val) => val.length >= MIN_TITLE_LENGTH,
64
65
  `Minimum ${MIN_TITLE_LENGTH} characters required`
65
66
  );
66
- var documentTypes = ["html", "xml"];
67
+ var documentTypes = ["html", "xml", "text"];
68
+ var BasicAuthFields = {
69
+ login: z2.string(),
70
+ password: z2.string()
71
+ };
72
+ var validateBasicAuthFields = ({
73
+ login,
74
+ password
75
+ }, context) => {
76
+ for (const issue of validateBasicAuth({ login, password }).issues ?? []) {
77
+ context.addIssue({
78
+ code: z2.ZodIssueCode.custom,
79
+ path: issue.path,
80
+ message: issue.message
81
+ });
82
+ }
83
+ };
84
+ var PageBasicAuth = z2.object({
85
+ method: z2.literal("basic"),
86
+ ...BasicAuthFields
87
+ }).superRefine(validateBasicAuthFields);
88
+ var LegacyPageBasicAuth = z2.object({
89
+ type: z2.literal("basic"),
90
+ ...BasicAuthFields
91
+ }).superRefine(validateBasicAuthFields).transform(({ login, password }) => ({
92
+ method: "basic",
93
+ login,
94
+ password
95
+ }));
96
+ var PageAuth = z2.union([PageBasicAuth, LegacyPageBasicAuth]);
67
97
  var commonPageFields = {
68
98
  id: PageId,
69
99
  name: PageName,
@@ -81,6 +111,8 @@ var commonPageFields = {
81
111
  status: z2.string().optional(),
82
112
  redirect: z2.string().optional(),
83
113
  documentType: z2.optional(z2.enum(documentTypes)),
114
+ content: z2.string().optional(),
115
+ auth: PageAuth.optional(),
84
116
  custom: z2.array(
85
117
  z2.object({
86
118
  property: z2.string(),
@@ -131,12 +163,21 @@ var Page = z2.object({
131
163
  ...commonPageFields,
132
164
  path: z2.union([HomePagePath, PagePath])
133
165
  });
166
+ var PageTemplate = z2.object({
167
+ id: PageId,
168
+ name: PageName,
169
+ title: PageTitle,
170
+ rootInstanceId: z2.string(),
171
+ systemDataSourceId: z2.string().optional(),
172
+ meta: commonPageFields.meta
173
+ });
134
174
  var ProjectMeta = z2.object({
135
175
  // All fields are optional to ensure consistency and allow for the addition of new fields without requiring migration
136
176
  siteName: z2.string().optional(),
137
177
  contactEmail: z2.string().optional(),
138
178
  faviconAssetId: z2.string().optional(),
139
- code: z2.string().optional()
179
+ code: z2.string().optional(),
180
+ auth: z2.string().optional()
140
181
  });
141
182
  var ProjectNewRedirectPath = z2.string().min(1, "Path is required").refine((data) => {
142
183
  try {
@@ -162,6 +203,7 @@ var Pages = z2.object({
162
203
  homePageId: PageId,
163
204
  rootFolderId: FolderId,
164
205
  pages: z2.map(PageId, Page),
206
+ pageTemplates: z2.map(PageId, PageTemplate).optional(),
165
207
  folders: z2.map(FolderId, Folder).refine((folders) => folders.size > 0, "Folders can't be empty")
166
208
  }).superRefine((pages, context) => {
167
209
  const homePage = pages.pages.get(pages.homePageId);
@@ -203,6 +245,22 @@ var Pages = z2.object({
203
245
  });
204
246
  }
205
247
  }
248
+ for (const [templateId, template] of pages.pageTemplates ?? []) {
249
+ if (template.id !== templateId) {
250
+ context.addIssue({
251
+ code: z2.ZodIssueCode.custom,
252
+ path: ["pageTemplates", templateId, "id"],
253
+ message: "Page template id must match its record key"
254
+ });
255
+ }
256
+ if (pages.pages.has(templateId)) {
257
+ context.addIssue({
258
+ code: z2.ZodIssueCode.custom,
259
+ path: ["pageTemplates", templateId, "id"],
260
+ message: "Page template id must not match an existing page id"
261
+ });
262
+ }
263
+ }
206
264
  for (const [folderId, folder] of pages.folders) {
207
265
  if (folder.id !== folderId) {
208
266
  context.addIssue({
@@ -895,6 +953,13 @@ var Select = z14.object({
895
953
  defaultValue: z14.string().optional(),
896
954
  options: z14.array(z14.string())
897
955
  });
956
+ var TimeZone = z14.object({
957
+ ...common,
958
+ control: z14.literal("timeZone"),
959
+ type: z14.literal("string"),
960
+ defaultValue: z14.string().optional(),
961
+ options: z14.array(z14.string())
962
+ });
898
963
  var Check = z14.object({
899
964
  ...common,
900
965
  control: z14.literal("check"),
@@ -975,6 +1040,7 @@ var PropMeta = z14.union([
975
1040
  Radio,
976
1041
  InlineRadio,
977
1042
  Select,
1043
+ TimeZone,
978
1044
  MultiSelect,
979
1045
  Check,
980
1046
  InlineCheck,
@@ -1006,6 +1072,7 @@ var componentCategories = [
1006
1072
  "localization",
1007
1073
  "radix",
1008
1074
  "xml",
1075
+ "text",
1009
1076
  "other",
1010
1077
  "hidden",
1011
1078
  "internal"
@@ -2052,6 +2119,29 @@ var parseComponentName = (componentName) => {
2052
2119
  }
2053
2120
  return [namespace, name];
2054
2121
  };
2122
+ var getHtmlTagsFromProps = (props) => {
2123
+ const tags2 = /* @__PURE__ */ new Map();
2124
+ for (const prop of props.values()) {
2125
+ if (prop.type === "string" && prop.name === "tag") {
2126
+ tags2.set(prop.instanceId, prop.value);
2127
+ }
2128
+ }
2129
+ return tags2;
2130
+ };
2131
+ var getHtmlTagFromInstance = ({
2132
+ instance,
2133
+ metas,
2134
+ props,
2135
+ htmlTagsByInstanceId
2136
+ }) => {
2137
+ if (instance.component === "XmlNode") {
2138
+ return;
2139
+ }
2140
+ const meta = metas.get(instance.component);
2141
+ const metaTag = Object.keys(meta?.presetStyle ?? {}).at(0);
2142
+ const propTag = htmlTagsByInstanceId?.get(instance.id) ?? getHtmlTagsFromProps(props).get(instance.id);
2143
+ return instance.tag ?? propTag ?? metaTag;
2144
+ };
2055
2145
  var getIndexesWithinAncestors = (metas, instances, rootIds) => {
2056
2146
  const ancestors = /* @__PURE__ */ new Set();
2057
2147
  for (const meta of metas.values()) {
@@ -2111,24 +2201,175 @@ var systemParameter = {
2111
2201
  type: "parameter",
2112
2202
  name: "system"
2113
2203
  };
2114
- var allowedStringMethods = /* @__PURE__ */ new Set([
2115
- "toLowerCase",
2116
- "replace",
2117
- "split",
2118
- "slice",
2119
- "at",
2120
- "endsWith",
2121
- "includes",
2122
- "startsWith",
2123
- "toUpperCase",
2124
- "toLocaleLowerCase",
2125
- "toLocaleUpperCase"
2204
+ var walkAssignmentTarget = (node, visitor) => {
2205
+ if (node.type === "Identifier") {
2206
+ visitor.Identifier?.(node, "binding");
2207
+ return;
2208
+ }
2209
+ if (node.type === "MemberExpression") {
2210
+ visitor.MemberExpression?.(node);
2211
+ const { object } = node;
2212
+ if (object.type === "Identifier") {
2213
+ visitor.Identifier?.(object, "memberObject");
2214
+ } else if (object.type === "MemberExpression") {
2215
+ walkAssignmentTarget(object, visitor);
2216
+ }
2217
+ return;
2218
+ }
2219
+ visitor.UnsupportedPattern?.(node);
2220
+ };
2221
+ var stringMethodReturnKindByName = /* @__PURE__ */ new Map([
2222
+ ["toLowerCase", "string"],
2223
+ ["replace", "string"],
2224
+ ["split", "array"],
2225
+ ["slice", "string"],
2226
+ ["at", "unknown"],
2227
+ ["endsWith", "boolean"],
2228
+ ["includes", "boolean"],
2229
+ ["startsWith", "boolean"],
2230
+ ["toString", "string"],
2231
+ ["toUpperCase", "string"],
2232
+ ["toLocaleLowerCase", "string"],
2233
+ ["toLocaleUpperCase", "string"]
2234
+ ]);
2235
+ var arrayMethodReturnKindByName = /* @__PURE__ */ new Map([
2236
+ ["at", "unknown"],
2237
+ ["includes", "boolean"],
2238
+ ["join", "string"],
2239
+ ["slice", "array"],
2240
+ ["toString", "string"]
2126
2241
  ]);
2127
- var allowedArrayMethods = /* @__PURE__ */ new Set(["at", "includes", "join", "slice"]);
2242
+ var allowedStringMethods = new Set(
2243
+ stringMethodReturnKindByName.keys()
2244
+ );
2245
+ var allowedArrayMethods = new Set(arrayMethodReturnKindByName.keys());
2246
+ var getVariableValue = (variableValues, name) => {
2247
+ if (variableValues === void 0) {
2248
+ return;
2249
+ }
2250
+ const maybeMap = variableValues;
2251
+ if (typeof maybeMap.has === "function" && typeof maybeMap.get === "function") {
2252
+ if (maybeMap.has(name)) {
2253
+ return { value: maybeMap.get(name) };
2254
+ }
2255
+ return;
2256
+ }
2257
+ const record = variableValues;
2258
+ if (Object.hasOwn(record, name)) {
2259
+ return { value: record[name] };
2260
+ }
2261
+ };
2262
+ var getValueKind = (value) => {
2263
+ if (Array.isArray(value)) {
2264
+ return "array";
2265
+ }
2266
+ if (value === void 0 || value === null) {
2267
+ return "nullish";
2268
+ }
2269
+ switch (typeof value) {
2270
+ case "bigint":
2271
+ return "bigint";
2272
+ case "boolean":
2273
+ return "boolean";
2274
+ case "number":
2275
+ return "number";
2276
+ case "string":
2277
+ return "string";
2278
+ case "object":
2279
+ return "object";
2280
+ default:
2281
+ return "unknown";
2282
+ }
2283
+ };
2284
+ var getMethodReturnKind = (receiverKind, methodName) => {
2285
+ if (receiverKind === "array") {
2286
+ return arrayMethodReturnKindByName.get(methodName) ?? "unknown";
2287
+ }
2288
+ if (receiverKind === "string") {
2289
+ return stringMethodReturnKindByName.get(methodName) ?? "unknown";
2290
+ }
2291
+ if (receiverKind === "unknown") {
2292
+ const stringReturnKind = stringMethodReturnKindByName.get(methodName);
2293
+ const arrayReturnKind = arrayMethodReturnKindByName.get(methodName);
2294
+ if (stringReturnKind && arrayReturnKind === void 0) {
2295
+ return stringReturnKind;
2296
+ }
2297
+ if (arrayReturnKind && stringReturnKind === void 0) {
2298
+ return arrayReturnKind;
2299
+ }
2300
+ if (stringReturnKind === arrayReturnKind) {
2301
+ return stringReturnKind ?? "unknown";
2302
+ }
2303
+ return "unknown";
2304
+ }
2305
+ return methodName === "toString" ? "string" : "unknown";
2306
+ };
2307
+ var isMethodSupported = (receiverKind, methodName) => {
2308
+ if (receiverKind === "unknown") {
2309
+ return allowedStringMethods.has(methodName) || allowedArrayMethods.has(methodName);
2310
+ }
2311
+ if (receiverKind === "string") {
2312
+ return stringMethodReturnKindByName.has(methodName);
2313
+ }
2314
+ if (receiverKind === "array") {
2315
+ return arrayMethodReturnKindByName.has(methodName);
2316
+ }
2317
+ if (receiverKind === "nullish") {
2318
+ return false;
2319
+ }
2320
+ return methodName === "toString";
2321
+ };
2322
+ var getExpressionNodeValueKind = (node, variableValues) => {
2323
+ if (node.type === "Identifier") {
2324
+ if (node.name === "undefined") {
2325
+ return "nullish";
2326
+ }
2327
+ const variable = getVariableValue(variableValues, node.name);
2328
+ return variable ? getValueKind(variable.value) : "unknown";
2329
+ }
2330
+ if (node.type === "Literal") {
2331
+ return getValueKind(node.value);
2332
+ }
2333
+ if (node.type === "ArrayExpression") {
2334
+ return "array";
2335
+ }
2336
+ if (node.type === "ObjectExpression") {
2337
+ return "object";
2338
+ }
2339
+ if (node.type === "TemplateLiteral") {
2340
+ return "string";
2341
+ }
2342
+ if (node.type === "ChainExpression" || node.type === "ParenthesizedExpression") {
2343
+ return getExpressionNodeValueKind(node.expression, variableValues);
2344
+ }
2345
+ if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type !== "Super" && node.callee.property.type === "Identifier") {
2346
+ const receiverKind = getExpressionNodeValueKind(
2347
+ node.callee.object,
2348
+ variableValues
2349
+ );
2350
+ const methodName = node.callee.property.name;
2351
+ if (isMethodSupported(receiverKind, methodName)) {
2352
+ return getMethodReturnKind(receiverKind, methodName);
2353
+ }
2354
+ }
2355
+ return "unknown";
2356
+ };
2357
+ var getExpressionValueKind = ({
2358
+ expression,
2359
+ variableValues
2360
+ }) => {
2361
+ try {
2362
+ const node = parseExpressionAt(expression, 0, { ecmaVersion: "latest" });
2363
+ return getExpressionNodeValueKind(node, variableValues);
2364
+ } catch {
2365
+ return "unknown";
2366
+ }
2367
+ };
2128
2368
  var lintExpression = ({
2129
2369
  expression,
2130
2370
  availableVariables = /* @__PURE__ */ new Set(),
2131
- allowAssignment = false
2371
+ allowAssignment = false,
2372
+ variableValues
2132
2373
  }) => {
2133
2374
  const diagnostics = [];
2134
2375
  const addMessage = (message, severity = "error") => {
@@ -2193,15 +2434,21 @@ var lintExpression = ({
2193
2434
  addMessage("Assignment is supported only inside actions")(node);
2194
2435
  return;
2195
2436
  }
2196
- simple(node.left, {
2197
- Identifier(node2) {
2437
+ walkAssignmentTarget(node.left, {
2438
+ Identifier(node2, kind) {
2439
+ if (kind !== "binding") {
2440
+ return;
2441
+ }
2198
2442
  if (availableVariables.has(node2.name) === false) {
2199
2443
  addMessage(
2200
2444
  `"${node2.name}" is not defined in the scope`,
2201
2445
  "warning"
2202
2446
  )(node2);
2203
2447
  }
2204
- }
2448
+ },
2449
+ UnsupportedPattern: addMessage(
2450
+ "Destructuring assignment is not supported"
2451
+ )
2205
2452
  });
2206
2453
  },
2207
2454
  // parser forbids to yield inside module
@@ -2215,7 +2462,11 @@ var lintExpression = ({
2215
2462
  if (node.callee.type === "MemberExpression") {
2216
2463
  if (node.callee.property.type === "Identifier") {
2217
2464
  const methodName = node.callee.property.name;
2218
- if (allowedStringMethods.has(methodName) || allowedArrayMethods.has(methodName)) {
2465
+ const receiverKind = node.callee.object.type === "Super" ? "unknown" : getExpressionNodeValueKind(
2466
+ node.callee.object,
2467
+ variableValues
2468
+ );
2469
+ if (isMethodSupported(receiverKind, methodName)) {
2219
2470
  return;
2220
2471
  }
2221
2472
  calleeName = methodName;
@@ -2295,7 +2546,7 @@ var getExpressionIdentifiers = (expression) => {
2295
2546
  simple(root, {
2296
2547
  Identifier: (node) => identifiers2.add(node.name),
2297
2548
  AssignmentExpression(node) {
2298
- simple(node.left, {
2549
+ walkAssignmentTarget(node.left, {
2299
2550
  Identifier: (node2) => identifiers2.add(node2.name)
2300
2551
  });
2301
2552
  }
@@ -2316,17 +2567,44 @@ var transpileExpression = ({
2316
2567
  const message = error.message;
2317
2568
  throw Error(`${message} in ${JSON.stringify(expression)}`);
2318
2569
  }
2570
+ const assignmentTargetMemberRanges = [];
2571
+ if (executable) {
2572
+ simple(root, {
2573
+ AssignmentExpression(node) {
2574
+ walkAssignmentTarget(node.left, {
2575
+ MemberExpression(node2) {
2576
+ assignmentTargetMemberRanges.push([node2.start, node2.end]);
2577
+ }
2578
+ });
2579
+ }
2580
+ });
2581
+ }
2319
2582
  const replacements = [];
2583
+ const replacementIndexByRange = /* @__PURE__ */ new Map();
2584
+ const addReplacement = (start, end, fragment, { replaceExisting = false } = {}) => {
2585
+ const range = `${start}:${end}`;
2586
+ const existingIndex = replacementIndexByRange.get(range);
2587
+ if (existingIndex !== void 0) {
2588
+ if (replaceExisting) {
2589
+ replacements[existingIndex] = [start, end, fragment];
2590
+ }
2591
+ return;
2592
+ }
2593
+ replacementIndexByRange.set(range, replacements.length);
2594
+ replacements.push([start, end, fragment]);
2595
+ };
2320
2596
  const replaceIdentifier = (node, assignee) => {
2321
2597
  const newName = replaceVariable?.(node.name, assignee);
2322
2598
  if (newName) {
2323
- replacements.push([node.start, node.end, newName]);
2599
+ addReplacement(node.start, node.end, newName, {
2600
+ replaceExisting: assignee
2601
+ });
2324
2602
  }
2325
2603
  };
2326
2604
  simple(root, {
2327
2605
  Identifier: (node) => replaceIdentifier(node, false),
2328
2606
  AssignmentExpression(node) {
2329
- simple(node.left, {
2607
+ walkAssignmentTarget(node.left, {
2330
2608
  Identifier: (node2) => replaceIdentifier(node2, true)
2331
2609
  });
2332
2610
  },
@@ -2334,13 +2612,18 @@ var transpileExpression = ({
2334
2612
  if (executable === false || node.optional) {
2335
2613
  return;
2336
2614
  }
2615
+ if (assignmentTargetMemberRanges.some(
2616
+ ([start, end]) => start === node.start && end === node.end
2617
+ )) {
2618
+ return;
2619
+ }
2337
2620
  if (node.computed === false) {
2338
2621
  const dotIndex = expression.indexOf(".", node.object.end);
2339
- replacements.push([dotIndex, dotIndex, "?"]);
2622
+ addReplacement(dotIndex, dotIndex, "?");
2340
2623
  }
2341
2624
  if (node.computed === true) {
2342
2625
  const dotIndex = expression.indexOf("[", node.object.end);
2343
- replacements.push([dotIndex, dotIndex, "?."]);
2626
+ addReplacement(dotIndex, dotIndex, "?.");
2344
2627
  }
2345
2628
  },
2346
2629
  CallExpression(node) {
@@ -2350,7 +2633,7 @@ var transpileExpression = ({
2350
2633
  if (node.callee.type === "MemberExpression") {
2351
2634
  const openParenIndex = expression.indexOf("(", node.callee.end);
2352
2635
  if (openParenIndex !== -1) {
2353
- replacements.push([openParenIndex, openParenIndex, "?."]);
2636
+ addReplacement(openParenIndex, openParenIndex, "?.");
2354
2637
  }
2355
2638
  }
2356
2639
  }
@@ -2474,6 +2757,8 @@ var isAbsoluteUrl = (href) => {
2474
2757
 
2475
2758
  // src/page-utils.ts
2476
2759
  var ROOT_FOLDER_ID = "root";
2760
+ var isPage = (page) => page !== void 0 && "path" in page;
2761
+ var isPageTemplate = (page) => page !== void 0 && !("path" in page);
2477
2762
  var isRootFolder = ({ id }) => id === ROOT_FOLDER_ID;
2478
2763
  var getPageById = (pages, pageId) => {
2479
2764
  return pages.pages.get(pageId);
@@ -2494,14 +2779,20 @@ var getHomePage = (pages) => {
2494
2779
  }
2495
2780
  return homePage;
2496
2781
  };
2497
- var findPageByIdOrPath = (idOrPath, pages) => {
2782
+ function findPageByIdOrPath(idOrPath, pages, options = {}) {
2498
2783
  if (idOrPath === "" || idOrPath === "/" || idOrPath === pages.homePageId) {
2499
2784
  return getHomePage(pages);
2500
2785
  }
2501
- return getAllPages(pages).find(
2786
+ const found = getAllPages(pages).find(
2502
2787
  (page) => page.id === idOrPath || getPagePath(page.id, pages) === idOrPath
2503
2788
  );
2504
- };
2789
+ if (found) {
2790
+ return found;
2791
+ }
2792
+ if (options.includeTemplates) {
2793
+ return pages.pageTemplates?.get(idOrPath);
2794
+ }
2795
+ }
2505
2796
  var findParentFolderByChildId = (id, folders) => {
2506
2797
  const folderList = folders instanceof Map ? folders.values() : folders;
2507
2798
  for (const folder of folderList) {
@@ -2826,6 +3117,12 @@ var generatePageMeta = ({
2826
3117
  usedDataSources,
2827
3118
  scope: localScope
2828
3119
  });
3120
+ const contentExpression = generateExpression({
3121
+ expression: page.meta.content ?? "undefined",
3122
+ dataSources,
3123
+ usedDataSources,
3124
+ scope: localScope
3125
+ });
2829
3126
  let customExpression = "";
2830
3127
  customExpression += `[
2831
3128
  `;
@@ -2834,7 +3131,7 @@ var generatePageMeta = ({
2834
3131
  continue;
2835
3132
  }
2836
3133
  const propertyExpression = JSON.stringify(customMeta.property);
2837
- const contentExpression = generateExpression({
3134
+ const contentExpression2 = generateExpression({
2838
3135
  expression: customMeta.content,
2839
3136
  dataSources,
2840
3137
  usedDataSources,
@@ -2844,7 +3141,7 @@ var generatePageMeta = ({
2844
3141
  `;
2845
3142
  customExpression += ` property: ${propertyExpression},
2846
3143
  `;
2847
- customExpression += ` content: ${contentExpression},
3144
+ customExpression += ` content: ${contentExpression2},
2848
3145
  `;
2849
3146
  customExpression += ` },
2850
3147
  `;
@@ -2909,6 +3206,8 @@ var generatePageMeta = ({
2909
3206
  generated += ` status: ${statusExpression},
2910
3207
  `;
2911
3208
  generated += ` redirect: ${redirectExpression},
3209
+ `;
3210
+ generated += ` content: ${contentExpression},
2912
3211
  `;
2913
3212
  generated += ` custom: ${customExpression},
2914
3213
  `;
@@ -2919,6 +3218,29 @@ var generatePageMeta = ({
2919
3218
  return generated;
2920
3219
  };
2921
3220
 
3221
+ // src/link-utils.ts
3222
+ var isInternalHref = (href, assetBaseUrl) => /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href) === false && (assetBaseUrl !== "" && href.startsWith("/") && href.startsWith(assetBaseUrl)) === false;
3223
+ var resolveLocalLinkUrl = (href, location, resolvedPath) => {
3224
+ if (href === "") {
3225
+ return {
3226
+ pathname: location.pathname,
3227
+ search: location.search,
3228
+ hash: ""
3229
+ };
3230
+ }
3231
+ if (href.startsWith("#")) {
3232
+ return {
3233
+ pathname: location.pathname,
3234
+ search: location.search,
3235
+ hash: href === "#" ? "" : href
3236
+ };
3237
+ }
3238
+ return resolvedPath;
3239
+ };
3240
+ var isLocalLinkActive = (current, target) => {
3241
+ return current.pathname === target.pathname && current.search === target.search && current.hash === target.hash;
3242
+ };
3243
+
2922
3244
  // src/css.ts
2923
3245
  import { kebabCase } from "change-case";
2924
3246
  import {
@@ -2980,22 +3302,19 @@ var generateCss = ({
2980
3302
  const scope = createScope([], normalizeClassName, "-");
2981
3303
  const tagsByComponent = /* @__PURE__ */ new Map();
2982
3304
  tagsByComponent.set(rootComponent, /* @__PURE__ */ new Set(["html"]));
2983
- const tagByInstanceId = /* @__PURE__ */ new Map();
2984
- for (const prop of props.values()) {
2985
- if (prop.type === "string" && prop.name === "tag") {
2986
- tagByInstanceId.set(prop.instanceId, prop.value);
2987
- }
2988
- }
3305
+ const htmlTagsByInstanceId = getHtmlTagsFromProps(props);
2989
3306
  for (const instance of instances.values()) {
2990
- const propTag = tagByInstanceId.get(instance.id);
2991
- const meta = componentMetas.get(instance.component);
2992
- const metaTag = Object.keys(meta?.presetStyle ?? {}).at(0);
2993
3307
  let componentTags = tagsByComponent.get(instance.component);
2994
3308
  if (componentTags === void 0) {
2995
3309
  componentTags = /* @__PURE__ */ new Set();
2996
3310
  tagsByComponent.set(instance.component, componentTags);
2997
3311
  }
2998
- const tag = instance.tag ?? propTag ?? metaTag;
3312
+ const tag = getHtmlTagFromInstance({
3313
+ instance,
3314
+ metas: componentMetas,
3315
+ props,
3316
+ htmlTagsByInstanceId
3317
+ });
2999
3318
  if (tag) {
3000
3319
  componentTags.add(tag);
3001
3320
  }
@@ -3153,10 +3472,12 @@ export {
3153
3472
  Instances,
3154
3473
  MIME_CATEGORIES,
3155
3474
  OldPagePath,
3475
+ PageAuth,
3156
3476
  PageId,
3157
3477
  PageName,
3158
3478
  PagePath,
3159
3479
  PageRedirect,
3480
+ PageTemplate,
3160
3481
  PageTitle,
3161
3482
  Pages,
3162
3483
  PresetStyleDecl,
@@ -3225,8 +3546,11 @@ export {
3225
3546
  getAssetMime,
3226
3547
  getAssetUrl,
3227
3548
  getExpressionIdentifiers,
3549
+ getExpressionValueKind,
3228
3550
  getFolderById,
3229
3551
  getHomePage,
3552
+ getHtmlTagFromInstance,
3553
+ getHtmlTagsFromProps,
3230
3554
  getIndexesWithinAncestors,
3231
3555
  getMimeTypeByExtension,
3232
3556
  getMimeTypeByFilename,
@@ -3241,7 +3565,11 @@ export {
3241
3565
  isAllowedMimeCategory,
3242
3566
  isComponentDetachable,
3243
3567
  isCoreComponent,
3568
+ isInternalHref,
3244
3569
  isLiteralExpression,
3570
+ isLocalLinkActive,
3571
+ isPage,
3572
+ isPageTemplate,
3245
3573
  isPathnamePattern,
3246
3574
  isRootFolder,
3247
3575
  lintExpression,
@@ -3251,6 +3579,7 @@ export {
3251
3579
  portalComponent,
3252
3580
  rangeUnitValueSchema,
3253
3581
  replaceFormActionsWithResources,
3582
+ resolveLocalLinkUrl,
3254
3583
  rootComponent,
3255
3584
  scrollAnimationSchema,
3256
3585
  systemParameter,
@@ -0,0 +1,27 @@
1
+ // src/link-utils.ts
2
+ var isInternalHref = (href, assetBaseUrl) => /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href) === false && (assetBaseUrl !== "" && href.startsWith("/") && href.startsWith(assetBaseUrl)) === false;
3
+ var resolveLocalLinkUrl = (href, location, resolvedPath) => {
4
+ if (href === "") {
5
+ return {
6
+ pathname: location.pathname,
7
+ search: location.search,
8
+ hash: ""
9
+ };
10
+ }
11
+ if (href.startsWith("#")) {
12
+ return {
13
+ pathname: location.pathname,
14
+ search: location.search,
15
+ hash: href === "#" ? "" : href
16
+ };
17
+ }
18
+ return resolvedPath;
19
+ };
20
+ var isLocalLinkActive = (current, target) => {
21
+ return current.pathname === target.pathname && current.search === target.search && current.hash === target.hash;
22
+ };
23
+ export {
24
+ isInternalHref,
25
+ isLocalLinkActive,
26
+ resolveLocalLinkUrl
27
+ };
@@ -9,12 +9,19 @@ export type Diagnostic = {
9
9
  severity: "error" | "hint" | "info" | "warning";
10
10
  message: string;
11
11
  };
12
+ export type VariableValues = ReadonlyMap<Identifier["name"], unknown> | Readonly<Record<Identifier["name"], unknown>>;
13
+ export type ExpressionValueKind = "array" | "bigint" | "boolean" | "nullish" | "number" | "object" | "string" | "unknown";
12
14
  export declare const allowedStringMethods: Set<string>;
13
15
  export declare const allowedArrayMethods: Set<string>;
14
- export declare const lintExpression: ({ expression, availableVariables, allowAssignment, }: {
16
+ export declare const getExpressionValueKind: ({ expression, variableValues, }: {
17
+ expression: string;
18
+ variableValues?: VariableValues;
19
+ }) => ExpressionValueKind;
20
+ export declare const lintExpression: ({ expression, availableVariables, allowAssignment, variableValues, }: {
15
21
  expression: string;
16
22
  availableVariables?: Set<Identifier["name"]>;
17
23
  allowAssignment?: boolean;
24
+ variableValues?: VariableValues;
18
25
  }) => Diagnostic[];
19
26
  /**
20
27
  * check whether provided expression is a literal value