@frontlit/page-builder 0.1.0-alpha.8 → 0.1.0-alpha.9

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.
@@ -4046,14 +4046,14 @@ var coerce = {
4046
4046
  var NEVER = INVALID;
4047
4047
 
4048
4048
  // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
4049
- function createScanner(text, ignoreTrivia = false) {
4050
- const len = text.length;
4049
+ function createScanner(text2, ignoreTrivia = false) {
4050
+ const len = text2.length;
4051
4051
  let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
4052
4052
  function scanHexDigits(count, exact) {
4053
4053
  let digits = 0;
4054
4054
  let value2 = 0;
4055
4055
  while (digits < count || !exact) {
4056
- let ch = text.charCodeAt(pos);
4056
+ let ch = text2.charCodeAt(pos);
4057
4057
  if (ch >= 48 && ch <= 57) {
4058
4058
  value2 = value2 * 16 + ch - 48;
4059
4059
  } else if (ch >= 65 && ch <= 70) {
@@ -4080,35 +4080,35 @@ function createScanner(text, ignoreTrivia = false) {
4080
4080
  }
4081
4081
  function scanNumber() {
4082
4082
  let start = pos;
4083
- if (text.charCodeAt(pos) === 48) {
4083
+ if (text2.charCodeAt(pos) === 48) {
4084
4084
  pos++;
4085
4085
  } else {
4086
4086
  pos++;
4087
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
4087
+ while (pos < text2.length && isDigit(text2.charCodeAt(pos))) {
4088
4088
  pos++;
4089
4089
  }
4090
4090
  }
4091
- if (pos < text.length && text.charCodeAt(pos) === 46) {
4091
+ if (pos < text2.length && text2.charCodeAt(pos) === 46) {
4092
4092
  pos++;
4093
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
4093
+ if (pos < text2.length && isDigit(text2.charCodeAt(pos))) {
4094
4094
  pos++;
4095
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
4095
+ while (pos < text2.length && isDigit(text2.charCodeAt(pos))) {
4096
4096
  pos++;
4097
4097
  }
4098
4098
  } else {
4099
4099
  scanError = 3;
4100
- return text.substring(start, pos);
4100
+ return text2.substring(start, pos);
4101
4101
  }
4102
4102
  }
4103
4103
  let end = pos;
4104
- if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
4104
+ if (pos < text2.length && (text2.charCodeAt(pos) === 69 || text2.charCodeAt(pos) === 101)) {
4105
4105
  pos++;
4106
- if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
4106
+ if (pos < text2.length && text2.charCodeAt(pos) === 43 || text2.charCodeAt(pos) === 45) {
4107
4107
  pos++;
4108
4108
  }
4109
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
4109
+ if (pos < text2.length && isDigit(text2.charCodeAt(pos))) {
4110
4110
  pos++;
4111
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
4111
+ while (pos < text2.length && isDigit(text2.charCodeAt(pos))) {
4112
4112
  pos++;
4113
4113
  }
4114
4114
  end = pos;
@@ -4116,30 +4116,30 @@ function createScanner(text, ignoreTrivia = false) {
4116
4116
  scanError = 3;
4117
4117
  }
4118
4118
  }
4119
- return text.substring(start, end);
4119
+ return text2.substring(start, end);
4120
4120
  }
4121
4121
  function scanString() {
4122
4122
  let result = "", start = pos;
4123
4123
  while (true) {
4124
4124
  if (pos >= len) {
4125
- result += text.substring(start, pos);
4125
+ result += text2.substring(start, pos);
4126
4126
  scanError = 2;
4127
4127
  break;
4128
4128
  }
4129
- const ch = text.charCodeAt(pos);
4129
+ const ch = text2.charCodeAt(pos);
4130
4130
  if (ch === 34) {
4131
- result += text.substring(start, pos);
4131
+ result += text2.substring(start, pos);
4132
4132
  pos++;
4133
4133
  break;
4134
4134
  }
4135
4135
  if (ch === 92) {
4136
- result += text.substring(start, pos);
4136
+ result += text2.substring(start, pos);
4137
4137
  pos++;
4138
4138
  if (pos >= len) {
4139
4139
  scanError = 2;
4140
4140
  break;
4141
4141
  }
4142
- const ch2 = text.charCodeAt(pos++);
4142
+ const ch2 = text2.charCodeAt(pos++);
4143
4143
  switch (ch2) {
4144
4144
  case 34:
4145
4145
  result += '"';
@@ -4181,7 +4181,7 @@ function createScanner(text, ignoreTrivia = false) {
4181
4181
  }
4182
4182
  if (ch >= 0 && ch <= 31) {
4183
4183
  if (isLineBreak(ch)) {
4184
- result += text.substring(start, pos);
4184
+ result += text2.substring(start, pos);
4185
4185
  scanError = 2;
4186
4186
  break;
4187
4187
  } else {
@@ -4202,19 +4202,19 @@ function createScanner(text, ignoreTrivia = false) {
4202
4202
  tokenOffset = len;
4203
4203
  return token = 17;
4204
4204
  }
4205
- let code = text.charCodeAt(pos);
4205
+ let code = text2.charCodeAt(pos);
4206
4206
  if (isWhiteSpace(code)) {
4207
4207
  do {
4208
4208
  pos++;
4209
4209
  value += String.fromCharCode(code);
4210
- code = text.charCodeAt(pos);
4210
+ code = text2.charCodeAt(pos);
4211
4211
  } while (isWhiteSpace(code));
4212
4212
  return token = 15;
4213
4213
  }
4214
4214
  if (isLineBreak(code)) {
4215
4215
  pos++;
4216
4216
  value += String.fromCharCode(code);
4217
- if (code === 13 && text.charCodeAt(pos) === 10) {
4217
+ if (code === 13 && text2.charCodeAt(pos) === 10) {
4218
4218
  pos++;
4219
4219
  value += "\n";
4220
4220
  }
@@ -4250,31 +4250,31 @@ function createScanner(text, ignoreTrivia = false) {
4250
4250
  // comments
4251
4251
  case 47:
4252
4252
  const start = pos - 1;
4253
- if (text.charCodeAt(pos + 1) === 47) {
4253
+ if (text2.charCodeAt(pos + 1) === 47) {
4254
4254
  pos += 2;
4255
4255
  while (pos < len) {
4256
- if (isLineBreak(text.charCodeAt(pos))) {
4256
+ if (isLineBreak(text2.charCodeAt(pos))) {
4257
4257
  break;
4258
4258
  }
4259
4259
  pos++;
4260
4260
  }
4261
- value = text.substring(start, pos);
4261
+ value = text2.substring(start, pos);
4262
4262
  return token = 12;
4263
4263
  }
4264
- if (text.charCodeAt(pos + 1) === 42) {
4264
+ if (text2.charCodeAt(pos + 1) === 42) {
4265
4265
  pos += 2;
4266
4266
  const safeLength = len - 1;
4267
4267
  let commentClosed = false;
4268
4268
  while (pos < safeLength) {
4269
- const ch = text.charCodeAt(pos);
4270
- if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
4269
+ const ch = text2.charCodeAt(pos);
4270
+ if (ch === 42 && text2.charCodeAt(pos + 1) === 47) {
4271
4271
  pos += 2;
4272
4272
  commentClosed = true;
4273
4273
  break;
4274
4274
  }
4275
4275
  pos++;
4276
4276
  if (isLineBreak(ch)) {
4277
- if (ch === 13 && text.charCodeAt(pos) === 10) {
4277
+ if (ch === 13 && text2.charCodeAt(pos) === 10) {
4278
4278
  pos++;
4279
4279
  }
4280
4280
  lineNumber++;
@@ -4285,7 +4285,7 @@ function createScanner(text, ignoreTrivia = false) {
4285
4285
  pos++;
4286
4286
  scanError = 1;
4287
4287
  }
4288
- value = text.substring(start, pos);
4288
+ value = text2.substring(start, pos);
4289
4289
  return token = 13;
4290
4290
  }
4291
4291
  value += String.fromCharCode(code);
@@ -4295,7 +4295,7 @@ function createScanner(text, ignoreTrivia = false) {
4295
4295
  case 45:
4296
4296
  value += String.fromCharCode(code);
4297
4297
  pos++;
4298
- if (pos === len || !isDigit(text.charCodeAt(pos))) {
4298
+ if (pos === len || !isDigit(text2.charCodeAt(pos))) {
4299
4299
  return token = 16;
4300
4300
  }
4301
4301
  // found a minus, followed by a number so
@@ -4317,10 +4317,10 @@ function createScanner(text, ignoreTrivia = false) {
4317
4317
  default:
4318
4318
  while (pos < len && isUnknownContentCharacter(code)) {
4319
4319
  pos++;
4320
- code = text.charCodeAt(pos);
4320
+ code = text2.charCodeAt(pos);
4321
4321
  }
4322
4322
  if (tokenOffset !== pos) {
4323
- value = text.substring(tokenOffset, pos);
4323
+ value = text2.substring(tokenOffset, pos);
4324
4324
  switch (value) {
4325
4325
  case "true":
4326
4326
  return token = 8;
@@ -4503,7 +4503,7 @@ var ParseOptions;
4503
4503
  allowTrailingComma: false
4504
4504
  };
4505
4505
  })(ParseOptions || (ParseOptions = {}));
4506
- function parse(text, errors = [], options = ParseOptions.DEFAULT) {
4506
+ function parse(text2, errors = [], options = ParseOptions.DEFAULT) {
4507
4507
  let currentProperty = null;
4508
4508
  let currentParent = [];
4509
4509
  const previousParents = [];
@@ -4543,11 +4543,11 @@ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
4543
4543
  errors.push({ error, offset, length });
4544
4544
  }
4545
4545
  };
4546
- visit(text, visitor, options);
4546
+ visit(text2, visitor, options);
4547
4547
  return currentParent[0];
4548
4548
  }
4549
- function visit(text, visitor, options = ParseOptions.DEFAULT) {
4550
- const _scanner = createScanner(text, false);
4549
+ function visit(text2, visitor, options = ParseOptions.DEFAULT) {
4550
+ const _scanner = createScanner(text2, false);
4551
4551
  const _jsonPath = [];
4552
4552
  let suppressedCallbacks = 0;
4553
4553
  function toNoArgVisit(visitFunction) {
@@ -6125,18 +6125,22 @@ var siteFileSchema = external_exports.object({
6125
6125
  theme: themeStyleSchema.optional().describe("The site theme."),
6126
6126
  header: fileSettings.header.optional().describe("Site header, shown on every page."),
6127
6127
  footer: fileSettings.footer.optional().describe("Site footer, shown on every page."),
6128
- redirects: external_exports.array(redirectSchema).optional()
6128
+ redirects: external_exports.array(redirectSchema).optional(),
6129
+ agentInstructions: external_exports.string().max(1e4).optional().describe(
6130
+ "Markdown for AI agents: what this site is for and when to use it. Shown in /llms.txt."
6131
+ )
6129
6132
  }).strict();
6130
6133
  function parseSiteFile(source) {
6131
6134
  const result = siteFileSchema.safeParse(parseJson(source));
6132
6135
  if (!result.success)
6133
6136
  throw new SchemaValidationError(issuesToDiagnostics(result.error));
6134
- const { theme, header, footer, redirects } = result.data;
6137
+ const { theme, header, footer, redirects, agentInstructions } = result.data;
6135
6138
  const site = {};
6136
6139
  if (theme) site.theme = theme;
6137
6140
  if (header) site.header = canonicalizeSettings("header", header, ["header"]);
6138
6141
  if (footer) site.footer = canonicalizeSettings("footer", footer, ["footer"]);
6139
6142
  if (redirects) site.redirects = redirects;
6143
+ if (agentInstructions?.trim()) site.agentInstructions = agentInstructions.trim();
6140
6144
  return site;
6141
6145
  }
6142
6146
  function serializeSiteFile(site) {
@@ -6160,11 +6164,131 @@ function serializeSiteFile(site) {
6160
6164
  theme,
6161
6165
  header: header && Object.keys(header).length ? header : void 0,
6162
6166
  footer: footer && Object.keys(footer).length ? footer : void 0,
6163
- redirects
6167
+ redirects,
6168
+ agentInstructions: site.agentInstructions || void 0
6164
6169
  };
6165
6170
  return `${JSON.stringify(file, null, 2)}
6166
6171
  `;
6167
6172
  }
6173
+
6174
+ // src/schema/markdown.ts
6175
+ var SKIPPED = /* @__PURE__ */ new Set(["header", "footer", "media", "marquee", "embed"]);
6176
+ var text = (value) => typeof value === "string" ? value.trim() : "";
6177
+ function link(caption, href) {
6178
+ const label = text(caption);
6179
+ if (!label) return "";
6180
+ const target = text(href);
6181
+ return target ? `[${label}](${target})` : label;
6182
+ }
6183
+ function heading(level, value) {
6184
+ const title = text(value);
6185
+ return title ? `${"#".repeat(level)} ${title}` : "";
6186
+ }
6187
+ function links(...pairs) {
6188
+ return pairs.map(([caption, href]) => link(caption, href)).filter(Boolean).join(" \xB7 ");
6189
+ }
6190
+ function blockMarkdown(name, s) {
6191
+ switch (name) {
6192
+ case "hero":
6193
+ return [
6194
+ text(s.preTitle),
6195
+ heading(2, s.title),
6196
+ text(s.description),
6197
+ text(s.command) ? `\`\`\`sh
6198
+ ${text(s.command)}
6199
+ \`\`\`` : "",
6200
+ links(
6201
+ [s.buttonCaption, s.buttonAction],
6202
+ [s.secondaryButtonCaption, s.secondaryButtonAction]
6203
+ ),
6204
+ text(s.smallPrint)
6205
+ ];
6206
+ case "content":
6207
+ return [heading(2, s.title), text(s.body)];
6208
+ case "rich-text":
6209
+ return [text(s.text)];
6210
+ case "featured":
6211
+ return [
6212
+ heading(2, s.title),
6213
+ text(s.description),
6214
+ (s.items ?? []).map(
6215
+ (item) => [`- **${text(item.title)}**`, text(item.description)].filter(Boolean).join(": ")
6216
+ ).join("\n")
6217
+ ];
6218
+ case "grid":
6219
+ return [
6220
+ heading(2, s.title),
6221
+ text(s.description),
6222
+ (s.items ?? []).map(
6223
+ (item) => [
6224
+ `- **${text(item.title)}**`,
6225
+ [text(item.description), link(item.buttonCaption, item.buttonAction)].filter(Boolean).join(" ")
6226
+ ].filter(Boolean).join(": ")
6227
+ ).join("\n"),
6228
+ link(s.buttonCaption, s.buttonAction)
6229
+ ];
6230
+ case "pricing":
6231
+ return [
6232
+ heading(2, s.title),
6233
+ text(s.description),
6234
+ ...(s.tiers ?? []).map(
6235
+ (tier) => [
6236
+ heading(3, tier.name),
6237
+ [text(tier.price), text(tier.priceYearly)].filter(Boolean).join(" or "),
6238
+ text(tier.description),
6239
+ (tier.features ?? []).map((f) => `- ${text(f)}`).join("\n"),
6240
+ link(tier.buttonCaption, tier.buttonAction)
6241
+ ].filter(Boolean).join("\n\n")
6242
+ )
6243
+ ];
6244
+ case "faq":
6245
+ return [
6246
+ heading(2, s.title),
6247
+ ...(s.items ?? []).map(
6248
+ (item) => [heading(3, item.question), text(item.answer)].filter(Boolean).join("\n\n")
6249
+ )
6250
+ ];
6251
+ case "banner":
6252
+ return [
6253
+ heading(2, s.title),
6254
+ text(s.description),
6255
+ links(
6256
+ [s.buttonCaption, s.buttonAction],
6257
+ [s.secondaryButtonCaption, s.secondaryButtonAction]
6258
+ )
6259
+ ];
6260
+ case "email-form":
6261
+ case "support-form":
6262
+ return [heading(2, s.title), text(s.description)];
6263
+ case "code-snippet":
6264
+ return [text(s.code) ? `\`\`\`
6265
+ ${text(s.code)}
6266
+ \`\`\`` : "", text(s.caption)];
6267
+ default:
6268
+ return [];
6269
+ }
6270
+ }
6271
+ function layoutToMarkdown(layout, slot = () => "") {
6272
+ const parts = [];
6273
+ for (const block of layout) {
6274
+ if (block.name === DATA_SLOT_BLOCK) {
6275
+ parts.push(slot());
6276
+ continue;
6277
+ }
6278
+ if (SKIPPED.has(block.name)) continue;
6279
+ let settings;
6280
+ try {
6281
+ settings = {
6282
+ ...fileBlockDefaults[block.name],
6283
+ ...toFileSettings(block.name, block.settings)
6284
+ };
6285
+ } catch {
6286
+ continue;
6287
+ }
6288
+ parts.push(...blockMarkdown(block.name, settings));
6289
+ }
6290
+ return parts.filter((part) => part.trim()).join("\n\n");
6291
+ }
6168
6292
  export {
6169
6293
  CHROME_BLOCK_NAMES,
6170
6294
  CONTENT_FEED_BLOCK,
@@ -6182,6 +6306,7 @@ export {
6182
6306
  fileMediaSchema,
6183
6307
  formatDiagnostic,
6184
6308
  fromFileSettings,
6309
+ layoutToMarkdown,
6185
6310
  pageFileSchema,
6186
6311
  parsePageFile,
6187
6312
  parseSiteFile,