@qualcomm-ui/mdx-vite 2.8.0 → 2.10.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/dist/cli.js CHANGED
@@ -520,9 +520,9 @@ var require_help = __commonJS({
520
520
  * @param {Help} helper
521
521
  * @returns string[]
522
522
  */
523
- formatItemList(heading2, items, helper) {
523
+ formatItemList(heading, items, helper) {
524
524
  if (items.length === 0) return [];
525
- return [helper.styleTitle(heading2), ...items, ""];
525
+ return [helper.styleTitle(heading), ...items, ""];
526
526
  }
527
527
  /**
528
528
  * Group items by their help group heading.
@@ -1002,8 +1002,8 @@ var require_option = __commonJS({
1002
1002
  * @param {string} heading
1003
1003
  * @return {Option}
1004
1004
  */
1005
- helpGroup(heading2) {
1006
- this.helpGroupHeading = heading2;
1005
+ helpGroup(heading) {
1006
+ this.helpGroupHeading = heading;
1007
1007
  return this;
1008
1008
  }
1009
1009
  /**
@@ -3099,9 +3099,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3099
3099
  * @param {string} [heading]
3100
3100
  * @return {Command | string}
3101
3101
  */
3102
- helpGroup(heading2) {
3103
- if (heading2 === void 0) return this._helpGroupHeading ?? "";
3104
- this._helpGroupHeading = heading2;
3102
+ helpGroup(heading) {
3103
+ if (heading === void 0) return this._helpGroupHeading ?? "";
3104
+ this._helpGroupHeading = heading;
3105
3105
  return this;
3106
3106
  }
3107
3107
  /**
@@ -3117,9 +3117,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3117
3117
  * @param {string} [heading]
3118
3118
  * @returns {Command | string}
3119
3119
  */
3120
- commandsGroup(heading2) {
3121
- if (heading2 === void 0) return this._defaultCommandGroup ?? "";
3122
- this._defaultCommandGroup = heading2;
3120
+ commandsGroup(heading) {
3121
+ if (heading === void 0) return this._defaultCommandGroup ?? "";
3122
+ this._defaultCommandGroup = heading;
3123
3123
  return this;
3124
3124
  }
3125
3125
  /**
@@ -3135,9 +3135,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3135
3135
  * @param {string} [heading]
3136
3136
  * @returns {Command | string}
3137
3137
  */
3138
- optionsGroup(heading2) {
3139
- if (heading2 === void 0) return this._defaultOptionGroup ?? "";
3140
- this._defaultOptionGroup = heading2;
3138
+ optionsGroup(heading) {
3139
+ if (heading === void 0) return this._defaultOptionGroup ?? "";
3140
+ this._defaultOptionGroup = heading;
3141
3141
  return this;
3142
3142
  }
3143
3143
  /**
@@ -3552,13 +3552,23 @@ var typeDocPropsSchema = implement().with({
3552
3552
  var knowledgeExtraFileSchema = implement().with({
3553
3553
  contents: z2.string(),
3554
3554
  id: z2.string(),
3555
- title: z2.string()
3555
+ processAsMdx: z2.boolean().optional(),
3556
+ title: z2.string().optional()
3557
+ });
3558
+ var knowledgeExportsSchema = implement().with({
3559
+ enabled: z2.boolean().optional(),
3560
+ exclude: z2.array(z2.string()).optional(),
3561
+ extraFiles: z2.array(knowledgeExtraFileSchema).optional(),
3562
+ metadata: z2.record(z2.string(), z2.string()).optional(),
3563
+ pageTitlePrefix: z2.string().optional(),
3564
+ staticPath: z2.string().optional()
3556
3565
  });
3557
3566
  var knowledgeIntegrationSchema = implement().with(
3558
3567
  {
3559
3568
  baseUrl: z2.string().optional(),
3560
3569
  description: z2.string().optional(),
3561
3570
  exclude: z2.array(z2.string()).optional(),
3571
+ exports: knowledgeExportsSchema.optional(),
3562
3572
  extraFiles: z2.array(knowledgeExtraFileSchema).optional(),
3563
3573
  metadata: z2.record(z2.string(), z2.string()).optional(),
3564
3574
  name: z2.string().optional(),
@@ -3871,7 +3881,7 @@ var DocPropsIndexer = class {
3871
3881
  }
3872
3882
  assembleProp(prop, id) {
3873
3883
  const name = prop.name;
3874
- const heading2 = {
3884
+ const heading = {
3875
3885
  headingLevel: 4,
3876
3886
  id,
3877
3887
  tagName: "a",
@@ -3879,7 +3889,7 @@ var DocPropsIndexer = class {
3879
3889
  };
3880
3890
  const comment = prop.comment;
3881
3891
  if (!comment) {
3882
- return { content: [], heading: heading2, richContent: [] };
3892
+ return { content: [], heading, richContent: [] };
3883
3893
  }
3884
3894
  const content = {
3885
3895
  tagName: "p",
@@ -3887,7 +3897,7 @@ var DocPropsIndexer = class {
3887
3897
  comment.summary.map((entry) => entry.text.replaceAll("\n", " ")).join("")
3888
3898
  ]
3889
3899
  };
3890
- return { content: [content], heading: heading2, richContent: [] };
3900
+ return { content: [content], heading, richContent: [] };
3891
3901
  }
3892
3902
  };
3893
3903
 
@@ -4354,6 +4364,36 @@ var alertToEmphasis = {
4354
4364
  warning: "warning"
4355
4365
  };
4356
4366
 
4367
+ // src/docs-plugin/remark/remark-frontmatter-interpolation.ts
4368
+ import { visit as visit4 } from "unist-util-visit";
4369
+ var FRONTMATTER_PATTERN = /^\s*frontmatter\.(\w+)\s*$/;
4370
+ function isMdxExpression(node) {
4371
+ const n = node;
4372
+ return (n.type === "mdxFlowExpression" || n.type === "mdxTextExpression") && typeof n.value === "string";
4373
+ }
4374
+ var remarkFrontmatterInterpolation = (frontmatter) => {
4375
+ return (tree) => {
4376
+ visit4(tree, (node, index, parent) => {
4377
+ if (!isMdxExpression(node) || index === void 0 || !parent) {
4378
+ return;
4379
+ }
4380
+ const match = node.value.match(FRONTMATTER_PATTERN);
4381
+ if (!match) {
4382
+ return;
4383
+ }
4384
+ const key = match[1];
4385
+ const value = frontmatter[key];
4386
+ if (typeof value === "string" || typeof value === "number") {
4387
+ const textNode = {
4388
+ type: "text",
4389
+ value: String(value)
4390
+ };
4391
+ parent.children[index] = textNode;
4392
+ }
4393
+ });
4394
+ };
4395
+ };
4396
+
4357
4397
  // src/docs-plugin/internal/services/markdown/remark-remove-code-blocks.ts
4358
4398
  import { remove } from "unist-util-remove";
4359
4399
  var remarkRemoveMermaidCodeBlocks = () => {
@@ -4398,8 +4438,8 @@ var MarkdownIndexer = class {
4398
4438
  this.resetSection();
4399
4439
  this.headingLevels = headingLevels;
4400
4440
  }
4401
- appendTocItem(heading2) {
4402
- this._toc.push(heading2);
4441
+ appendTocItem(heading) {
4442
+ this._toc.push(heading);
4403
4443
  }
4404
4444
  warn(...data) {
4405
4445
  if (process.env.DEBUG) {
@@ -4434,11 +4474,11 @@ var MarkdownIndexer = class {
4434
4474
  this.sections.push(clone(this.currentSection));
4435
4475
  this.resetSection();
4436
4476
  }
4437
- const heading2 = this.parseHeading(element);
4477
+ const heading = this.parseHeading(element);
4438
4478
  if (!isRootHeading) {
4439
- this.appendTocItem(heading2);
4479
+ this.appendTocItem(heading);
4440
4480
  }
4441
- this.currentSection.heading = heading2;
4481
+ this.currentSection.heading = heading;
4442
4482
  return;
4443
4483
  }
4444
4484
  this.currentSection.richContent.push(element);
@@ -4451,14 +4491,9 @@ var MarkdownIndexer = class {
4451
4491
  }
4452
4492
  }
4453
4493
  parseMarkdown(fileContents, frontmatter) {
4454
- const file = unified3().use(remarkMdx2).use(remarkRemoveJsx).use(remarkRemoveMermaidCodeBlocks).use(remarkParse3).use(remarkGfm).use(remarkAlerts).use(remarkRehype).use(rehypeStringify).processSync(fileContents);
4494
+ const file = unified3().use(remarkMdx2).use(remarkRemoveJsx).use(remarkRemoveMermaidCodeBlocks).use(remarkParse3).use(remarkGfm).use(remarkAlerts).use(remarkFrontmatterInterpolation, frontmatter).use(remarkRehype).use(rehypeStringify).processSync(fileContents);
4455
4495
  let contents = file.toString();
4456
4496
  contents = contents.substring(contents.indexOf("<h1>"));
4457
- for (const [key, value] of Object.entries(frontmatter)) {
4458
- if (typeof value === "string" || typeof value === "number") {
4459
- contents = contents.replaceAll(`frontmatter.${key}`, `${value}`);
4460
- }
4461
- }
4462
4497
  const htmlAst = unified3().data("settings", { fragment: true }).use(rehypeParse).use(rehypeStringify).use(rehypeSlug).processSync(contents);
4463
4498
  contents = htmlAst.toString();
4464
4499
  return this.build(contents);
@@ -4825,7 +4860,7 @@ function getRemixFlatRoutesSegments(name, index, paramPrefixChar = "$") {
4825
4860
  let routeSegments = [];
4826
4861
  let i = 0;
4827
4862
  let routeSegment = "";
4828
- let state2 = "START";
4863
+ let state = "START";
4829
4864
  let subState = "NORMAL";
4830
4865
  let hasPlus = false;
4831
4866
  if (name.endsWith("_layout")) {
@@ -4852,7 +4887,7 @@ function getRemixFlatRoutesSegments(name, index, paramPrefixChar = "$") {
4852
4887
  };
4853
4888
  while (i < name.length) {
4854
4889
  const char = name[i];
4855
- switch (state2) {
4890
+ switch (state) {
4856
4891
  case "START":
4857
4892
  if (routeSegment.includes(paramPrefixChar) && !(routeSegment.startsWith(paramPrefixChar) || routeSegment.startsWith(`(${paramPrefixChar}`))) {
4858
4893
  throw new Error(
@@ -4866,12 +4901,12 @@ function getRemixFlatRoutesSegments(name, index, paramPrefixChar = "$") {
4866
4901
  }
4867
4902
  pushRouteSegment(routeSegment);
4868
4903
  routeSegment = "";
4869
- state2 = "PATH";
4904
+ state = "PATH";
4870
4905
  continue;
4871
4906
  // restart without advancing index
4872
4907
  case "PATH":
4873
4908
  if (isPathSeparator(char) && subState === "NORMAL") {
4874
- state2 = "START";
4909
+ state = "START";
4875
4910
  break;
4876
4911
  } else if (char === "[") {
4877
4912
  subState = "ESCAPE";
@@ -5363,7 +5398,7 @@ var FilesApi = class {
5363
5398
  if (status.status === "completed" || status.status === "failed") {
5364
5399
  return status;
5365
5400
  }
5366
- await new Promise((resolve9) => setTimeout(resolve9, intervalMs));
5401
+ await new Promise((resolve8) => setTimeout(resolve8, intervalMs));
5367
5402
  }
5368
5403
  throw new Error(`File processing timed out after ${maxAttempts} attempts`);
5369
5404
  }
@@ -5623,238 +5658,19 @@ import {
5623
5658
  stat,
5624
5659
  writeFile as writeFile3
5625
5660
  } from "node:fs/promises";
5626
- import { basename, dirname, extname, join as join3, relative as relative2, resolve as resolve5 } from "node:path";
5627
- import remarkFrontmatter3 from "remark-frontmatter";
5661
+ import { basename, dirname, extname, join as join3, relative as relative2, resolve as resolve4 } from "node:path";
5662
+ import remarkFrontmatter2 from "remark-frontmatter";
5628
5663
  import remarkMdx3 from "remark-mdx";
5629
5664
  import remarkParse4 from "remark-parse";
5630
5665
  import remarkParseFrontmatter2 from "remark-parse-frontmatter";
5631
5666
  import remarkStringify3 from "remark-stringify";
5632
5667
  import { unified as unified4 } from "unified";
5633
- import { visit as visit8 } from "unist-util-visit";
5634
- import { kebabCase } from "@qualcomm-ui/utils/change-case";
5635
-
5636
- // src/docs-plugin/docs-plugin.ts
5637
- import chalk3 from "chalk";
5638
- import chokidar from "chokidar";
5639
- import { glob as glob2 } from "glob";
5640
- import { readFileSync as readFileSync2 } from "node:fs";
5641
- import { resolve as resolve3 } from "node:path";
5642
- import prettyMilliseconds from "pretty-ms";
5643
- var isDev = process.env.NODE_ENV === "development";
5644
- var VIRTUAL_MODULE_ID = "\0@qualcomm-ui/mdx-vite-plugin";
5645
- var PluginState = class {
5646
- buildCount = 0;
5647
- configFilePath = "";
5648
- docPropsFilePath = "";
5649
- indexer;
5650
- configLoader = null;
5651
- routesDir;
5652
- servers = [];
5653
- timeout = void 0;
5654
- watching = false;
5655
- cwd;
5656
- init(cwd2) {
5657
- this.cwd = cwd2;
5658
- }
5659
- get docPropsDirectory() {
5660
- if (!this.docPropsFilePath) {
5661
- return "";
5662
- }
5663
- return this.docPropsFilePath.substring(
5664
- 0,
5665
- this.docPropsFilePath.lastIndexOf("/")
5666
- );
5667
- }
5668
- get siteData() {
5669
- return {
5670
- navItems: state.indexer.navItems,
5671
- pageDocProps: state.indexer.pageDocProps,
5672
- pageMap: state.indexer.pageMap,
5673
- searchIndex: state.indexer.searchIndex
5674
- };
5675
- }
5676
- resolveDocProps() {
5677
- if (!this.docPropsFilePath) {
5678
- return {};
5679
- }
5680
- try {
5681
- return JSON.parse(readFileSync2(this.docPropsFilePath, "utf-8"))?.props;
5682
- } catch (e) {
5683
- console.debug(
5684
- "Invalid doc props file. Unable to parse JSON. Please check the file"
5685
- );
5686
- return {};
5687
- }
5688
- }
5689
- createIndexer(config2) {
5690
- this.configFilePath = config2.filePath;
5691
- this.docPropsFilePath = config2.typeDocProps ? fixPath(resolve3(this.cwd, config2.typeDocProps)) : "";
5692
- this.routesDir = fixPath(resolve3(config2.appDirectory, config2.pageDirectory));
5693
- this.indexer = new SearchIndexer({
5694
- ...config2,
5695
- srcDir: fixPath(resolve3(this.cwd, config2.appDirectory)),
5696
- typeDocProps: this.resolveDocProps()
5697
- });
5698
- }
5699
- buildIndex(shouldLog) {
5700
- const files = glob2.sync(
5701
- [`${this.routesDir}/**/*.mdx`, `${this.routesDir}/**/*.tsx`],
5702
- {
5703
- absolute: true,
5704
- cwd: this.cwd
5705
- }
5706
- );
5707
- if (!files.length) {
5708
- return [];
5709
- }
5710
- const startTime = Date.now();
5711
- const compiledMdxFiles = this.indexer.buildIndex(files, shouldLog);
5712
- if (isDev && shouldLog) {
5713
- console.debug(
5714
- `${chalk3.magenta.bold(`@qualcomm-ui/mdx-vite/docs-plugin:`)} Compiled search index in: ${chalk3.blueBright.bold(prettyMilliseconds(Date.now() - startTime))}${state.indexer.cachedFileCount ? chalk3.greenBright.bold(` (${state.indexer.cachedFileCount}/${state.indexer.mdxFileCount} files cached)`) : ""}`
5715
- );
5716
- }
5717
- return compiledMdxFiles;
5718
- }
5719
- /**
5720
- * When the user adds or removes mdx files, we re-index the site. This function
5721
- * handles module invalidation so that virtual file imports are refreshed as
5722
- * expected by the consumer's dev server.
5723
- */
5724
- sendUpdate() {
5725
- for (const server of this.servers) {
5726
- const virtualModule = server.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
5727
- if (virtualModule) {
5728
- server.moduleGraph.invalidateModule(virtualModule);
5729
- server.reloadModule(virtualModule);
5730
- }
5731
- }
5732
- }
5733
- handleChange(opts = {}) {
5734
- clearTimeout(this.timeout);
5735
- this.timeout = setTimeout(() => {
5736
- this.buildIndex(true);
5737
- this.sendUpdate();
5738
- opts?.onComplete?.();
5739
- }, 300);
5740
- }
5741
- initWatchers(configFile) {
5742
- if (this.watching) {
5743
- return;
5744
- }
5745
- this.initConfigWatcher(configFile);
5746
- this.watching = true;
5747
- }
5748
- initConfigWatcher(configFile) {
5749
- const paths = [this.configFilePath];
5750
- if (this.docPropsFilePath) {
5751
- paths.push(this.docPropsFilePath);
5752
- }
5753
- chokidar.watch(paths, {
5754
- cwd: this.cwd
5755
- }).on("change", () => {
5756
- console.debug(`qui-docs config changed, reloading plugin`);
5757
- this.configLoader = new ConfigLoader({ configFile });
5758
- const resolvedConfig = this.configLoader.loadConfig();
5759
- this.configFilePath = resolvedConfig.filePath;
5760
- this.createIndexer(resolvedConfig);
5761
- this.handleChange({
5762
- onComplete: () => {
5763
- this.servers.forEach(
5764
- (server) => server.ws.send({ type: "full-reload" })
5765
- );
5766
- }
5767
- });
5768
- });
5769
- }
5770
- };
5771
- var state = new PluginState();
5772
-
5773
- // src/docs-plugin/mdx-plugins.ts
5774
- import rehypeShiki from "@shikijs/rehype";
5775
- import {
5776
- transformerNotationDiff,
5777
- transformerNotationErrorLevel,
5778
- transformerNotationFocus,
5779
- transformerNotationHighlight,
5780
- transformerNotationWordHighlight,
5781
- transformerRemoveNotationEscape,
5782
- transformerRenderIndentGuides
5783
- } from "@shikijs/transformers";
5784
- import { merge } from "lodash-es";
5785
- import { quiCustomDarkTheme } from "@qualcomm-ui/mdx-common";
5786
-
5787
- // src/exports.ts
5788
- import rehypeMdxCodeProps from "rehype-mdx-code-props";
5789
- import remarkFrontmatter2 from "remark-frontmatter";
5790
- import remarkGfm2 from "remark-gfm";
5791
- import remarkMdxFrontmatter from "remark-mdx-frontmatter";
5792
-
5793
- // src/docs-plugin/rehype/rehype-sectionize.ts
5794
- import { heading } from "hast-util-heading";
5795
- import { headingRank as headingRank2 } from "hast-util-heading-rank";
5796
-
5797
- // src/docs-plugin/remark/remark-code-tabs.ts
5798
- import { visit as visit4 } from "unist-util-visit";
5799
-
5800
- // src/docs-plugin/remark/remark-frontmatter-description.ts
5801
5668
  import { visit as visit5 } from "unist-util-visit";
5802
-
5803
- // src/docs-plugin/remark/remark-self-link-headings.ts
5804
- import { toString as toString2 } from "mdast-util-to-string";
5805
- import { visit as visit6 } from "unist-util-visit";
5806
- var emptyOptions2 = {};
5807
- function remarkSelfLinkHeadings(baseUrl = "", options) {
5808
- if (!baseUrl) {
5809
- return () => {
5810
- };
5811
- }
5812
- return () => {
5813
- const settings = options || emptyOptions2;
5814
- const prefix = settings.prefix || "";
5815
- const allowedLevels = new Set(settings.allowedLevels || [2, 3, 4]);
5816
- const seenIds = /* @__PURE__ */ new Map();
5817
- function createSlug(text) {
5818
- const cleaned = text.replace(/[<>]/g, "").replace(/[^\w\s-]/g, "").trim();
5819
- let slug;
5820
- if (cleaned.includes(" ")) {
5821
- slug = cleaned.toLowerCase().replace(/\s+/g, "-").replace(/^-+|-+$/g, "");
5822
- } else if ((cleaned.match(/[A-Z]/g) || []).length >= 2) {
5823
- slug = cleaned.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
5824
- } else {
5825
- slug = cleaned.toLowerCase();
5826
- }
5827
- const count = seenIds.get(slug) || 0;
5828
- seenIds.set(slug, count + 1);
5829
- return count > 0 ? `${slug}-${count}` : slug;
5830
- }
5831
- return (tree) => {
5832
- seenIds.clear();
5833
- visit6(tree, "heading", (node) => {
5834
- if (allowedLevels.has(node.depth)) {
5835
- const text = toString2(node);
5836
- const slug = prefix + createSlug(text);
5837
- const linkNode = {
5838
- children: node.children,
5839
- type: "link",
5840
- url: `${baseUrl}#${slug}`
5841
- };
5842
- node.children = [linkNode];
5843
- }
5844
- });
5845
- };
5846
- };
5847
- }
5848
-
5849
- // src/docs-plugin/remark/remark-spoilers.ts
5850
- import { visit as visit7 } from "unist-util-visit";
5851
-
5852
- // src/docs-plugin/shiki/shiki-transformer-preview-block.ts
5853
- import { dedent } from "@qualcomm-ui/utils/dedent";
5669
+ import { kebabCase } from "@qualcomm-ui/utils/change-case";
5854
5670
 
5855
5671
  // src/open-web-ui-knowledge/load-config-from-env.ts
5856
5672
  import { existsSync } from "node:fs";
5857
- import { join as join2, resolve as resolve4 } from "node:path";
5673
+ import { join as join2, resolve as resolve3 } from "node:path";
5858
5674
  function parseCliMetadata(cliMetadata) {
5859
5675
  if (!cliMetadata?.length) {
5860
5676
  return void 0;
@@ -5874,7 +5690,7 @@ function loadKnowledgeConfigFromEnv(options) {
5874
5690
  resolvedConfig.appDirectory,
5875
5691
  resolvedConfig.pageDirectory
5876
5692
  );
5877
- if (!existsSync(resolve4(routeDir))) {
5693
+ if (!existsSync(resolve3(routeDir))) {
5878
5694
  throw new Error(`Route directory ${routeDir} does not exist`);
5879
5695
  }
5880
5696
  const cliMetadata = parseCliMetadata(options.metadata);
@@ -5938,7 +5754,7 @@ function extractRelativeImports(content) {
5938
5754
  }
5939
5755
  async function resolveModulePath(importPath, fromFile) {
5940
5756
  const fromDir = dirname(fromFile);
5941
- const baseResolved = resolve5(fromDir, importPath);
5757
+ const baseResolved = resolve4(fromDir, importPath);
5942
5758
  const extensions = [".ts", ".tsx", ".js", ".jsx", ""];
5943
5759
  for (const ext of extensions) {
5944
5760
  const fullPath = baseResolved + ext;
@@ -5959,7 +5775,7 @@ function extractMetadata(metadata) {
5959
5775
  }
5960
5776
  var replaceNpmInstallTabs = () => {
5961
5777
  return (tree, _file, done) => {
5962
- visit8(tree, "mdxJsxFlowElement", (node) => {
5778
+ visit5(tree, "mdxJsxFlowElement", (node) => {
5963
5779
  if (node?.name === "NpmInstallTabs") {
5964
5780
  const packages = node.attributes?.find(
5965
5781
  (attr) => attr.type === "mdxJsxAttribute" && attr.name === "packages"
@@ -5982,6 +5798,37 @@ function getPath(obj, path) {
5982
5798
  obj
5983
5799
  );
5984
5800
  }
5801
+ function escapeText(value) {
5802
+ return value.replace(/\n/g, " ");
5803
+ }
5804
+ function propsToDefinitionList(props) {
5805
+ if (props.length === 0) {
5806
+ return "";
5807
+ }
5808
+ return props.map((prop) => {
5809
+ const parts = [`- **${prop.name}** (\`${escapeText(prop.type)}\``];
5810
+ if (prop.defaultValue) {
5811
+ parts.push(`, default: \`${escapeText(prop.defaultValue)}\``);
5812
+ }
5813
+ if (prop.required) {
5814
+ parts.push(", required");
5815
+ }
5816
+ parts.push(")");
5817
+ if (prop.description) {
5818
+ parts.push(` - ${escapeText(prop.description)}`);
5819
+ }
5820
+ return parts.join("");
5821
+ }).join("\n");
5822
+ }
5823
+ function themeDataToJson(data, cssPropertyName) {
5824
+ if (!data || typeof data !== "object") {
5825
+ return "";
5826
+ }
5827
+ if (cssPropertyName) {
5828
+ return JSON.stringify({ cssProperty: cssPropertyName, data }, null, 2);
5829
+ }
5830
+ return JSON.stringify(data, null, 2);
5831
+ }
5985
5832
  var KnowledgeGenerator = class {
5986
5833
  config;
5987
5834
  docProps = null;
@@ -6003,7 +5850,7 @@ var KnowledgeGenerator = class {
6003
5850
  this.docProps = docProps;
6004
5851
  if (pages.length === 0) {
6005
5852
  console.log("No pages found.");
6006
- return;
5853
+ return [];
6007
5854
  }
6008
5855
  if (this.config.verbose) {
6009
5856
  console.log(`Found ${pages.length} page(s)`);
@@ -6011,7 +5858,7 @@ var KnowledgeGenerator = class {
6011
5858
  const processedPages = [];
6012
5859
  for (const page of pages) {
6013
5860
  try {
6014
- const processed = await this.processComponent(page);
5861
+ const processed = await this.processMdxPage(page);
6015
5862
  processedPages.push(processed);
6016
5863
  } catch (error) {
6017
5864
  console.error(`Failed to process page: ${page.name}`);
@@ -6036,9 +5883,10 @@ var KnowledgeGenerator = class {
6036
5883
  );
6037
5884
  await this.generateExtraFiles(extractedMetadata);
6038
5885
  }
5886
+ return pages;
6039
5887
  }
6040
5888
  async loadDocProps() {
6041
- const resolvedDocPropsPath = this.config.docPropsPath ? await exists(this.config.docPropsPath) ? this.config.docPropsPath : resolve5(process.cwd(), this.config.docPropsPath) : join3(dirname(this.config.routeDir), "doc-props.json");
5889
+ const resolvedDocPropsPath = this.config.docPropsPath ? await exists(this.config.docPropsPath) ? this.config.docPropsPath : resolve4(process.cwd(), this.config.docPropsPath) : join3(dirname(this.config.routeDir), "doc-props.json");
6042
5890
  if (!await exists(resolvedDocPropsPath)) {
6043
5891
  if (this.config.verbose) {
6044
5892
  console.log(`Doc props file not found at: ${resolvedDocPropsPath}`);
@@ -6097,10 +5945,11 @@ var KnowledgeGenerator = class {
6097
5945
  const url = getPathnameFromPathSegments(segments);
6098
5946
  components.push({
6099
5947
  demosFolder: demosFolderPath,
5948
+ filePath: dirPath,
6100
5949
  id: segments.join("-").trim(),
6101
5950
  mdxFile: join3(dirPath, mdxFile.name),
6102
5951
  name: segments.at(-1),
6103
- path: dirPath,
5952
+ pathname: url,
6104
5953
  url: this.config.baseUrl ? new URL(url, this.config.baseUrl).toString() : void 0
6105
5954
  });
6106
5955
  if (this.config.verbose) {
@@ -6120,7 +5969,7 @@ var KnowledgeGenerator = class {
6120
5969
  return components;
6121
5970
  }
6122
5971
  async collectRelativeImports(filePath, visited = /* @__PURE__ */ new Set()) {
6123
- const normalizedPath = resolve5(filePath);
5972
+ const normalizedPath = resolve4(filePath);
6124
5973
  if (visited.has(normalizedPath)) {
6125
5974
  return [];
6126
5975
  }
@@ -6228,7 +6077,9 @@ ${codeText}
6228
6077
  }
6229
6078
  default:
6230
6079
  if (this.config.outputMode === "per-page" && "tag" in part && part.tag === "@link" && typeof part.target === "string") {
6231
- return `[${part.text}](${part.target})`;
6080
+ if (part.text === "Learn more") {
6081
+ return "";
6082
+ }
6232
6083
  }
6233
6084
  return part.text;
6234
6085
  }
@@ -6247,8 +6098,8 @@ ${codeText}
6247
6098
  };
6248
6099
  }
6249
6100
  /**
6250
- * Creates a remark plugin that replaces TypeDocProps JSX elements with JSON
6251
- * code blocks containing component prop documentation.
6101
+ * Creates a remark plugin that replaces theme JSX elements with
6102
+ * markdown tables containing theme data.
6252
6103
  */
6253
6104
  async replaceThemeNodes() {
6254
6105
  let themes = null;
@@ -6275,7 +6126,7 @@ ${codeText}
6275
6126
  }
6276
6127
  };
6277
6128
  return () => (tree, _file, done) => {
6278
- visit8(tree, "mdxJsxFlowElement", (node) => {
6129
+ visit5(tree, "mdxJsxFlowElement", (node) => {
6279
6130
  const handler = node.name && handlers[node.name];
6280
6131
  if (!handler) {
6281
6132
  return;
@@ -6285,11 +6136,21 @@ ${codeText}
6285
6136
  console.warn(`No theme data for ${node.name}`);
6286
6137
  return;
6287
6138
  }
6139
+ let markdownTable;
6140
+ if (typeof data === "object" && data !== null && "cssPropertyName" in data && "data" in data) {
6141
+ const { cssPropertyName, data: themeData } = data;
6142
+ markdownTable = themeDataToJson(themeData, cssPropertyName);
6143
+ } else {
6144
+ markdownTable = themeDataToJson(data);
6145
+ }
6146
+ if (!markdownTable) {
6147
+ return;
6148
+ }
6288
6149
  Object.assign(node, {
6289
6150
  lang: "json",
6290
6151
  meta: null,
6291
6152
  type: "code",
6292
- value: JSON.stringify(data, null, 2)
6153
+ value: markdownTable
6293
6154
  });
6294
6155
  });
6295
6156
  done();
@@ -6310,12 +6171,30 @@ ${codeText}
6310
6171
  return null;
6311
6172
  }
6312
6173
  /**
6313
- * Creates a remark plugin that replaces TypeDocProps JSX elements with JSON
6314
- * code blocks containing component prop documentation.
6174
+ * Creates a remark plugin that transforms relative URLs to absolute URLs.
6175
+ */
6176
+ transformRelativeUrls(pageUrl) {
6177
+ const baseUrl = this.config.baseUrl;
6178
+ return () => (tree) => {
6179
+ if (!baseUrl || this.config.outputMode !== "per-page") {
6180
+ return;
6181
+ }
6182
+ visit5(tree, "link", (node) => {
6183
+ if (node.url.startsWith("/")) {
6184
+ node.url = `${baseUrl}${node.url}`;
6185
+ } else if (node.url.startsWith("./#") && pageUrl) {
6186
+ node.url = `${pageUrl}${node.url.slice(2)}`;
6187
+ }
6188
+ });
6189
+ };
6190
+ }
6191
+ /**
6192
+ * Creates a remark plugin that replaces TypeDocProps JSX elements with
6193
+ * markdown tables containing component prop documentation.
6315
6194
  */
6316
6195
  replaceTypeDocProps() {
6317
6196
  return () => (tree, _file, done) => {
6318
- visit8(
6197
+ visit5(
6319
6198
  tree,
6320
6199
  "mdxJsxFlowElement",
6321
6200
  (node, index, parent) => {
@@ -6358,11 +6237,35 @@ ${codeText}
6358
6237
  ` Replaced TypeDocProps ${propsName} with API documentation`
6359
6238
  );
6360
6239
  }
6240
+ const regularProps = propsDoc.filter((p) => p.propType === void 0);
6241
+ const inputs = propsDoc.filter((p) => p.propType === "input");
6242
+ const outputs = propsDoc.filter((p) => p.propType === "output");
6243
+ const sections = [];
6244
+ if (regularProps.length > 0) {
6245
+ sections.push(propsToDefinitionList(regularProps));
6246
+ }
6247
+ if (inputs.length > 0) {
6248
+ sections.push(`**Inputs**
6249
+
6250
+ ${propsToDefinitionList(inputs)}`);
6251
+ }
6252
+ if (outputs.length > 0) {
6253
+ sections.push(`**Outputs**
6254
+
6255
+ ${propsToDefinitionList(outputs)}`);
6256
+ }
6257
+ const markdownContent = sections.join("\n\n");
6258
+ if (!markdownContent) {
6259
+ if (parent && index !== void 0) {
6260
+ parent.children.splice(index, 1);
6261
+ }
6262
+ return;
6263
+ }
6361
6264
  Object.assign(node, {
6362
- lang: "json",
6265
+ lang: null,
6363
6266
  meta: null,
6364
6267
  type: "code",
6365
- value: JSON.stringify(propsDoc, null, 2)
6268
+ value: markdownContent
6366
6269
  });
6367
6270
  }
6368
6271
  );
@@ -6376,7 +6279,7 @@ ${codeText}
6376
6279
  replaceDemos(demosFolder, demoFiles) {
6377
6280
  return () => async (tree) => {
6378
6281
  const promises = [];
6379
- visit8(
6282
+ visit5(
6380
6283
  tree,
6381
6284
  "mdxJsxFlowElement",
6382
6285
  (node, index, parent) => {
@@ -6464,9 +6367,9 @@ ${codeText}
6464
6367
  await Promise.all(promises);
6465
6368
  };
6466
6369
  }
6467
- replaceFrontmatterDescription(frontmatter) {
6370
+ replaceFrontmatterExpressions(frontmatter) {
6468
6371
  return () => (tree) => {
6469
- visit8(
6372
+ visit5(
6470
6373
  tree,
6471
6374
  "mdxFlowExpression",
6472
6375
  (node, index, parent) => {
@@ -6483,6 +6386,18 @@ ${codeText}
6483
6386
  }
6484
6387
  }
6485
6388
  );
6389
+ const root = tree;
6390
+ const h1Index = root.children.findIndex((node) => {
6391
+ if (node.type !== "heading" || node.depth !== 1) {
6392
+ return false;
6393
+ }
6394
+ return node.children?.some(
6395
+ (child) => child.type === "mdxTextExpression" && child.value?.includes("frontmatter")
6396
+ );
6397
+ });
6398
+ if (h1Index >= 0) {
6399
+ root.children.splice(h1Index, 1);
6400
+ }
6486
6401
  };
6487
6402
  }
6488
6403
  /**
@@ -6491,57 +6406,41 @@ ${codeText}
6491
6406
  */
6492
6407
  async processMdxContent(mdxContent, pageUrl, demosFolder, frontmatter) {
6493
6408
  const demoFiles = [];
6494
- let processedContent = mdxContent;
6495
- const lines = processedContent.split("\n");
6496
- const titleLine = lines.findIndex((line) => line.startsWith("# "));
6497
- processedContent = titleLine >= 0 ? lines.slice(titleLine + 1).join("\n") : processedContent;
6498
- processedContent = processedContent.replace(
6499
- /\[([^\]]+)\]\(\.\/#([^)]+)\)/g,
6500
- (_, text, anchor) => pageUrl && this.config.outputMode === "per-page" ? `[${text}](${pageUrl}#${anchor})` : text
6501
- );
6502
- const processor = unified4().use(remarkParse4).use(remarkMdx3).use(this.replaceTypeDocProps()).use(this.replaceFrontmatterDescription(frontmatter)).use(await this.replaceThemeNodes()).use(this.replaceDemos(demosFolder, demoFiles)).use(remarkStringify3);
6503
- const processed = await processor.process(processedContent);
6504
- processedContent = String(processed);
6505
- processedContent = processedContent.replace(/\n\s*\n\s*\n/g, "\n\n");
6409
+ const processor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkFrontmatter2, ["yaml"]).use(this.replaceTypeDocProps()).use(this.replaceFrontmatterExpressions(frontmatter)).use(await this.replaceThemeNodes()).use(this.replaceDemos(demosFolder, demoFiles)).use(this.transformRelativeUrls(pageUrl)).use(remarkStringify3);
6410
+ const processed = await processor.process(mdxContent);
6411
+ const processedContent = String(processed).replace(/\n\s*\n\s*\n/g, "\n\n");
6506
6412
  return { content: processedContent, demoFiles };
6507
6413
  }
6508
- async processComponent(component) {
6414
+ async processMdxPage(pageInfo) {
6509
6415
  try {
6510
- const mdxContent = await readFile(component.mdxFile, "utf-8");
6416
+ const mdxContent = await readFile(pageInfo.mdxFile, "utf-8");
6511
6417
  if (this.config.verbose) {
6512
- console.log(`Processing page: ${component.name}`);
6513
- }
6514
- const processor = unified4().use(remarkParse4).use(remarkMdx3).use(replaceNpmInstallTabs).use(remarkFrontmatter3, ["yaml"]).use(remarkParseFrontmatter2);
6515
- if (this.config.outputMode === "per-page") {
6516
- processor.use(remarkSelfLinkHeadings(component.url));
6418
+ console.log(`Processing page: ${pageInfo.name}`);
6517
6419
  }
6518
- processor.use(remarkStringify3);
6420
+ const processor = unified4().use(remarkParse4).use(remarkMdx3).use(replaceNpmInstallTabs).use(remarkFrontmatter2, ["yaml"]).use(remarkParseFrontmatter2).use(remarkStringify3);
6519
6421
  const parsed = await processor.process(mdxContent);
6520
6422
  const frontmatter = parsed.data?.frontmatter || {};
6521
6423
  const { content: processedContent, demoFiles } = await this.processMdxContent(
6522
6424
  String(parsed),
6523
- component.url,
6524
- component.demosFolder,
6425
+ pageInfo.url,
6426
+ pageInfo.demosFolder,
6525
6427
  frontmatter
6526
6428
  );
6527
- const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkRemoveJsx).use(remarkStringify3);
6429
+ const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkFrontmatter2, ["yaml"]).use(remarkRemoveJsx).use(remarkStringify3);
6528
6430
  const removedJsx = String(
6529
6431
  await removeJsxProcessor.process(processedContent)
6530
6432
  );
6531
- const contentWithoutFrontmatter = removedJsx.replace(
6532
- /^---[\s\S]*?---\n/,
6533
- ""
6534
- );
6535
- const title = frontmatter.title || component.name;
6433
+ const contentWithoutFrontmatter = removedJsx.replace(/^---[\s\S]*?---\n/, "").replace(/(^#{1,6} .*\\<[^>]+)>/gm, "$1\\>");
6434
+ const title = frontmatter.title || pageInfo.name;
6536
6435
  return {
6537
6436
  content: contentWithoutFrontmatter.trim(),
6538
6437
  demoFiles,
6539
6438
  frontmatter,
6540
6439
  title,
6541
- url: component.url
6440
+ url: pageInfo.url
6542
6441
  };
6543
6442
  } catch (error) {
6544
- console.error(`Error processing component ${component.name}:`, error);
6443
+ console.error(`Error processing component ${pageInfo.name}:`, error);
6545
6444
  throw error;
6546
6445
  }
6547
6446
  }
@@ -6589,6 +6488,11 @@ ${codeText}
6589
6488
  let totalSize = 0;
6590
6489
  await Promise.all(
6591
6490
  extraFiles.map(async (extraFile) => {
6491
+ let contents = extraFile.contents;
6492
+ if (extraFile.processAsMdx) {
6493
+ const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkFrontmatter2, ["yaml"]).use(remarkRemoveJsx).use(this.transformRelativeUrls()).use(remarkStringify3);
6494
+ contents = String(await removeJsxProcessor.process(contents));
6495
+ }
6592
6496
  const lines = [];
6593
6497
  if (metadata.length) {
6594
6498
  lines.push("---");
@@ -6598,11 +6502,13 @@ ${codeText}
6598
6502
  lines.push("---");
6599
6503
  lines.push("");
6600
6504
  }
6601
- lines.push(`# ${extraFile.title}`);
6602
- lines.push("");
6603
- lines.push(extraFile.contents);
6505
+ if (extraFile.title) {
6506
+ lines.push(`# ${extraFile.title}`);
6507
+ lines.push("");
6508
+ }
6509
+ lines.push(contents);
6604
6510
  lines.push("");
6605
- const outfile = `${resolve5(this.config.outputPath)}/${kebabCase(extraFile.id)}.md`;
6511
+ const outfile = `${resolve4(this.config.outputPath)}/${kebabCase(extraFile.id)}.md`;
6606
6512
  await writeFile3(outfile, lines.join("\n"), "utf-8");
6607
6513
  const stats = await stat(outfile);
6608
6514
  totalSize += stats.size / 1024;
@@ -6642,6 +6548,10 @@ ${codeText}
6642
6548
  page.name = processedPage.frontmatter.title;
6643
6549
  }
6644
6550
  let content = processedPage.content;
6551
+ content = content.replace(
6552
+ new RegExp(`^# ${processedPage.title}\\n+`, ""),
6553
+ ""
6554
+ );
6645
6555
  if (this.config.pageTitlePrefix) {
6646
6556
  content = content.replace(
6647
6557
  `# ${page.name}`,
@@ -6687,7 +6597,7 @@ ${codeText}
6687
6597
  }
6688
6598
  }
6689
6599
  }
6690
- const outfile = `${resolve5(this.config.outputPath)}/${kebabCase(page.id || page.name)}.md`;
6600
+ const outfile = `${resolve4(this.config.outputPath)}/${kebabCase(page.id || page.name)}.md`;
6691
6601
  await writeFile3(outfile, lines.join("\n"), "utf-8");
6692
6602
  const stats = await stat(outfile);
6693
6603
  totalSize += stats.size / 1024;
@@ -6699,7 +6609,7 @@ ${codeText}
6699
6609
  };
6700
6610
  async function generate(config2) {
6701
6611
  const generator = new KnowledgeGenerator(config2);
6702
- await generator.run();
6612
+ return generator.run();
6703
6613
  }
6704
6614
  function addGenerateKnowledgeCommand() {
6705
6615
  program.description("Generate llms.txt from QUI Docs documentation").command("generate-llms-txt").option("-n, --name <name>", "Project name for llms.txt header").requiredOption("-m, --output-mode <outputMode>").option("-o, --outputPath <outputPath>", "Output file or directory.").option(
@@ -6723,7 +6633,7 @@ function addGenerateKnowledgeCommand() {
6723
6633
  import { createHash as createHash2 } from "node:crypto";
6724
6634
  import { writeFileSync } from "node:fs";
6725
6635
  import { access as access2, readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
6726
- import { resolve as resolve6 } from "node:path";
6636
+ import { resolve as resolve5 } from "node:path";
6727
6637
  import { setTimeout as setTimeout2 } from "node:timers/promises";
6728
6638
  import ora from "ora";
6729
6639
 
@@ -6853,7 +6763,7 @@ var Uploader = class {
6853
6763
  const files = await Promise.all(
6854
6764
  fileNames.map(async (name) => ({
6855
6765
  contents: await readFile2(
6856
- resolve6(this.config.knowledgeFilePath, name),
6766
+ resolve5(this.config.knowledgeFilePath, name),
6857
6767
  "utf-8"
6858
6768
  ),
6859
6769
  name
@@ -6902,7 +6812,7 @@ var Uploader = class {
6902
6812
  try {
6903
6813
  const fileId = knowledgeFile.id;
6904
6814
  const fileString = await readFile2(
6905
- resolve6(this.config.knowledgeFilePath, name),
6815
+ resolve5(this.config.knowledgeFilePath, name),
6906
6816
  "utf-8"
6907
6817
  );
6908
6818
  const spinner2 = ora(`Updating ${name}`).start();
@@ -6917,7 +6827,7 @@ var Uploader = class {
6917
6827
  }
6918
6828
  const spinner = ora(`Uploading ${name}`).start();
6919
6829
  const fileBuffer = await readFile2(
6920
- resolve6(this.config.knowledgeFilePath, name)
6830
+ resolve5(this.config.knowledgeFilePath, name)
6921
6831
  );
6922
6832
  let uploadedFileId = void 0;
6923
6833
  try {
@@ -6955,7 +6865,7 @@ var Uploader = class {
6955
6865
  }
6956
6866
  }
6957
6867
  async uploadKnowledge() {
6958
- const resolvedPath = resolve6(this.config.knowledgeFilePath);
6868
+ const resolvedPath = resolve5(this.config.knowledgeFilePath);
6959
6869
  if (!await access2(resolvedPath).then(() => true).catch(() => false)) {
6960
6870
  throw new Error(`File or folder not found at ${resolvedPath}`);
6961
6871
  }
@@ -6995,7 +6905,7 @@ function addUploadKnowledgeCommand() {
6995
6905
  const files = await uploader.filesApi.search("*");
6996
6906
  console.debug(`found ${files.length} files`);
6997
6907
  writeFileSync(
6998
- resolve6(uploader.config.knowledgeFilePath, "files.json"),
6908
+ resolve5(uploader.config.knowledgeFilePath, "files.json"),
6999
6909
  JSON.stringify(files, null, 2),
7000
6910
  "utf-8"
7001
6911
  );
@@ -7038,16 +6948,16 @@ function addUploadKnowledgeCommand() {
7038
6948
  }
7039
6949
 
7040
6950
  // src/react-demo-plugin/generate-lazy-demo-map.ts
7041
- import { glob as glob3 } from "glob";
6951
+ import { glob as glob2 } from "glob";
7042
6952
  import { uniqBy } from "lodash-es";
7043
6953
  import { writeFile as writeFile4 } from "node:fs/promises";
7044
- import { resolve as resolve8 } from "node:path";
7045
- import { dedent as dedent2 } from "@qualcomm-ui/utils/dedent";
6954
+ import { resolve as resolve7 } from "node:path";
6955
+ import { dedent } from "@qualcomm-ui/utils/dedent";
7046
6956
 
7047
6957
  // src/react-demo-plugin/demo-plugin-utils.ts
7048
- import chalk4 from "chalk";
7049
- import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
7050
- import { dirname as dirname2, join as join4, relative as relative3, resolve as resolve7, sep } from "node:path";
6958
+ import chalk3 from "chalk";
6959
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
6960
+ import { dirname as dirname2, join as join4, relative as relative3, resolve as resolve6, sep } from "node:path";
7051
6961
  import * as ts from "typescript";
7052
6962
  import { pascalCase } from "@qualcomm-ui/utils/change-case";
7053
6963
  function extractPageId(filePath, routesDir) {
@@ -7061,7 +6971,7 @@ function extractPageId(filePath, routesDir) {
7061
6971
  }
7062
6972
  function isDemoFile(filePath) {
7063
6973
  try {
7064
- return filePath.includes("/demos/") && filePath.endsWith(".tsx") && !readFileSync3(filePath).includes("export default");
6974
+ return filePath.includes("/demos/") && filePath.endsWith(".tsx") && !readFileSync2(filePath).includes("export default");
7065
6975
  } catch (error) {
7066
6976
  return false;
7067
6977
  }
@@ -7072,7 +6982,7 @@ async function scanForDemoPages({
7072
6982
  demoPattern = "src/routes/**/demos/*.tsx",
7073
6983
  routesDir = "src/routes"
7074
6984
  }) {
7075
- const demoFiles = (await glob3(demoPattern)).filter((file) => isDemoFile(file));
6985
+ const demoFiles = (await glob2(demoPattern)).filter((file) => isDemoFile(file));
7076
6986
  return uniqBy(
7077
6987
  demoFiles.map((file) => ({
7078
6988
  pageId: extractPageId(file, routesDir),
@@ -7086,7 +6996,7 @@ function generateLazyDemoLoader(demoPages) {
7086
6996
  return ` "${routePath}": () =>
7087
6997
  import("virtual:qui-demo-scope/page:${pageId}")`;
7088
6998
  }).sort().join(",\n");
7089
- return dedent2`
6999
+ return dedent`
7090
7000
  /* eslint-disable */
7091
7001
 
7092
7002
  // This file is generated automatically. Don't edit it directly.
@@ -7104,7 +7014,7 @@ function generateLazyDemoLoader(demoPages) {
7104
7014
  }
7105
7015
  async function generateLazyDemoMap(options) {
7106
7016
  const routesDir = options.routesDir;
7107
- const outputPath = resolve8(options.output);
7017
+ const outputPath = resolve7(options.output);
7108
7018
  console.log(`Scanning for demo pages in: ${routesDir}`);
7109
7019
  const demoPages = await scanForDemoPages({ routesDir });
7110
7020
  console.log(`Found ${demoPages.length} pages with demos`);