@writedocs/generator 0.4.7 → 0.4.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.
@@ -259,6 +259,125 @@ function mergeSeo(site, page) {
259
259
  noindex: page.noindex ?? site.noindex
260
260
  };
261
261
  }
262
+ const MINTLIFY_MODE_ALIASES = { center: "frame", assistant: "default" };
263
+ const pageFrontmatterSchema = z.object({
264
+ title: z.string(),
265
+ description: z.string().optional(),
266
+ // Overrides the URL this page is served at, independent of where the
267
+ // file actually lives - writedocs.json's `pages` arrays always keep
268
+ // referencing the file's own path regardless. This is Astro's own
269
+ // glob()-loader convention (a `slug` frontmatter field becomes
270
+ // `entry.id` verbatim - see generateIdDefault in
271
+ // astro/dist/content/loaders/glob.js), not writedocs-specific
272
+ // behavior; declaring it here just brings it into the schema (and
273
+ // its docs) rather than leaving it an undocumented Astro feature.
274
+ // See fileIdForEntry() in lib/config.ts for how routes/links still
275
+ // resolve a page by its file id once this diverges from `entry.id`.
276
+ // Leading/trailing slashes are fine either way ("/", "/guides/x",
277
+ // "guides/x" and "guides/x/" all mean the same thing) - see
278
+ // normalizeEntryId() in lib/config.ts, which is what actually
279
+ // strips them before this value is ever used as a route or href.
280
+ slug: z.string().optional(),
281
+ // Marks this page as an OpenAPI operation reference: "METHOD /path"
282
+ // matching an operation in the owning group's OpenAPI spec, e.g.
283
+ // "GET /pets/{petId}" - [...slug].astro renders <ApiPlayground /> for
284
+ // any page with this field set, below the page's own MDX body (if
285
+ // any). Sites don't write this by hand for most pages; it's either
286
+ // set on a generated stub in the `generatedDocs` collection below (see
287
+ // generate-api-pages.js) or hand-authored to "eject" one specific
288
+ // operation into a real file (in `docs`) with custom prose - either
289
+ // way, the value is always exactly the same "METHOD /path" key
290
+ // generate-api-pages.js uses to look up the operation's full resolved
291
+ // schema/examples at render time.
292
+ openapi: z.string().optional(),
293
+ // Controls how much of the site's own chrome (topbar, sidebar, table of
294
+ // contents) wraps this page - see BaseLayout.astro/[...slug].astro for
295
+ // what each value actually removes:
296
+ // default - the normal three-column reading layout (all chrome).
297
+ // wide - drops the table of contents; the article itself also
298
+ // renders wider, for content that wants the extra room
299
+ // (wide tables, side-by-side images).
300
+ // frame - drops the sidebar and table of contents, but keeps the
301
+ // topbar and the article's own normal presentation
302
+ // ("frame" as in: still inside the site's outer frame).
303
+ // custom - drops the sidebar and table of contents, the
304
+ // auto-rendered <h1>, and prev/next nav, and skips the
305
+ // article's own prose width/padding too - a blank canvas
306
+ // for a hand-built landing/home page made entirely of
307
+ // components - but keeps the topbar, so the page still
308
+ // has site branding/nav/search/theme-toggle available.
309
+ // blank - everything 'custom' drops, plus the topbar too: no site
310
+ // chrome at all, just <slot />. For a page that wants to
311
+ // look nothing like the rest of the site (an auth screen,
312
+ // a print-style page).
313
+ //
314
+ // Two Mintlify values are accepted so a migrated page doesn't fail the
315
+ // build (see MINTLIFY_MODE_ALIASES above): `center` is the same layout
316
+ // as our `frame`, and `assistant` (a full-page Mintlify AI chat, which
317
+ // writedocs doesn't have) falls back to `default`. Mintlify's own
318
+ // `frame` means something else (a canvas that keeps the sidebar) - it's
319
+ // left as our `frame`; see docs/dev/docs/mintlify-compat.mdx.
320
+ mode: z.preprocess(
321
+ (value) => typeof value === "string" && value in MINTLIFY_MODE_ALIASES ? MINTLIFY_MODE_ALIASES[value] : value,
322
+ z.enum(["default", "wide", "frame", "custom", "blank"])
323
+ ).default("default"),
324
+ // Per-page meta tag overrides - same shape as writedocs.json's top-level
325
+ // `seo` (see seoFieldsSchema in lib/config.ts, the single source of
326
+ // truth for this shape). A page only needs to set the specific fields
327
+ // it wants to override; mergeSeo() falls back to the site-wide default
328
+ // for anything left unset. See BaseLayout.astro for where this and the
329
+ // site-wide seo actually get merged and rendered.
330
+ seo: seoFieldsSchema.optional(),
331
+ // Mintlify's spelling of `seo.noindex` - a top-level `noindex: true`.
332
+ // Folded into `seo` by the transform below, so everything downstream
333
+ // (the robots meta tag, sitemap.xml, llms.txt) keeps reading
334
+ // `seo.noindex` only.
335
+ noindex: z.boolean().optional(),
336
+ // Mintlify's short navigation label - used for the sidebar and the
337
+ // topbar dropdown menus in place of `title` ([...slug].astro's
338
+ // navTitleForSlug). The page's own <h1> and prev/next links keep `title`.
339
+ sidebarTitle: z.string().optional(),
340
+ // Mintlify's spellings of `seo.keywords`, `seo.ogImage`, `seo.ogType`
341
+ // and `seo.twitterCard`, folded into `seo` below like `noindex`.
342
+ keywords: z.array(z.string()).optional(),
343
+ "og:image": z.string().optional(),
344
+ "og:type": z.string().optional(),
345
+ "twitter:card": z.enum(["summary", "summary_large_image"]).optional(),
346
+ // Mintlify's sidebar/page-chrome fields - see NavTree.astro and
347
+ // [...slug].astro for where each is used:
348
+ // icon - shown before the page's label in the sidebar.
349
+ // tag - a short label after it (e.g. "NEW").
350
+ // deprecated - a "Deprecated" label in the sidebar and next
351
+ // to the page's <h1>.
352
+ // hidden - left out of the sidebar, dropdowns and
353
+ // prev/next, but still built and reachable by
354
+ // URL. Also noindexed, as on Mintlify.
355
+ // url - an external link: the page's sidebar entry
356
+ // links straight to it, and the page's own URL
357
+ // redirects there.
358
+ // hideFooterPagination - no prev/next links on this page.
359
+ // hideApiMarker - no HTTP method badge on this page's sidebar
360
+ // entry.
361
+ icon: z.string().optional(),
362
+ tag: z.string().optional(),
363
+ deprecated: z.boolean().optional(),
364
+ hidden: z.boolean().optional(),
365
+ url: z.string().optional(),
366
+ hideFooterPagination: z.boolean().optional(),
367
+ hideApiMarker: z.boolean().optional()
368
+ }).transform(
369
+ ({ noindex, keywords, "og:image": ogImage, "og:type": ogType, "twitter:card": twitterCard, ...data }) => {
370
+ const fromMintlify = { noindex: noindex ?? (data.hidden ? true : void 0), keywords, ogImage, ogType, twitterCard };
371
+ const seo = { ...data.seo };
372
+ let changed = false;
373
+ for (const [key, value] of Object.entries(fromMintlify)) {
374
+ if (value === void 0 || seo[key] !== void 0) continue;
375
+ seo[key] = value;
376
+ changed = true;
377
+ }
378
+ return changed ? { ...data, seo } : data;
379
+ }
380
+ );
262
381
  const apiSchema = z.object({
263
382
  // Whether the Try-it modal's Send button routes its request through
264
383
  // writedocs' own CORS proxy (https://proxy.writechoice.io/) rather
@@ -505,6 +624,9 @@ function desembrulharUnioes(issues, prefixo = []) {
505
624
  }
506
625
  return saida;
507
626
  }
627
+ function createJsonLocator(rawText) {
628
+ return criarLocalizador(rawText);
629
+ }
508
630
  function criarLocalizador(rawText) {
509
631
  let arvore;
510
632
  try {
@@ -700,10 +822,12 @@ function validateDocsConfig(rawText) {
700
822
  }
701
823
  export {
702
824
  ROOT_ALLOWED_EXTRA_KEYS,
825
+ createJsonLocator,
703
826
  docsConfigSchema,
704
827
  formatValidationIssues,
705
828
  formatValidationIssuesDetailed,
706
829
  mergeSeo,
830
+ pageFrontmatterSchema,
707
831
  seoFieldsSchema,
708
832
  unknownRootKeyIssues,
709
833
  validateDocsConfig