@qualcomm-ui/mdx-vite 2.7.0 → 2.9.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.
Files changed (29) hide show
  1. package/dist/cli.js +168 -39
  2. package/dist/cli.js.map +4 -4
  3. package/dist/docs-plugin/__tests__/remark-frontmatter-description.spec.d.ts +2 -0
  4. package/dist/docs-plugin/__tests__/remark-frontmatter-description.spec.d.ts.map +1 -0
  5. package/dist/docs-plugin/__tests__/remark-frontmatter-interpolation.spec.d.ts +2 -0
  6. package/dist/docs-plugin/__tests__/remark-frontmatter-interpolation.spec.d.ts.map +1 -0
  7. package/dist/docs-plugin/docs-plugin.d.ts.map +1 -1
  8. package/dist/docs-plugin/internal/config-schema.d.ts +12 -0
  9. package/dist/docs-plugin/internal/config-schema.d.ts.map +1 -1
  10. package/dist/docs-plugin/internal/search-indexer.d.ts.map +1 -1
  11. package/dist/docs-plugin/internal/services/markdown/markdown-indexer.d.ts.map +1 -1
  12. package/dist/docs-plugin/internal/utils.d.ts.map +1 -1
  13. package/dist/docs-plugin/mdx-plugins.d.ts.map +1 -1
  14. package/dist/docs-plugin/remark/index.d.ts +3 -0
  15. package/dist/docs-plugin/remark/index.d.ts.map +1 -1
  16. package/dist/docs-plugin/remark/remark-frontmatter-description.d.ts +8 -0
  17. package/dist/docs-plugin/remark/remark-frontmatter-description.d.ts.map +1 -0
  18. package/dist/docs-plugin/remark/remark-frontmatter-interpolation.d.ts +10 -0
  19. package/dist/docs-plugin/remark/remark-frontmatter-interpolation.d.ts.map +1 -0
  20. package/dist/docs-plugin/remark/remark-frontmatter-title.d.ts +10 -0
  21. package/dist/docs-plugin/remark/remark-frontmatter-title.d.ts.map +1 -0
  22. package/dist/docs-plugin/types.d.ts +39 -0
  23. package/dist/docs-plugin/types.d.ts.map +1 -1
  24. package/dist/index.js +6166 -1642
  25. package/dist/index.js.map +4 -4
  26. package/dist/open-web-ui-knowledge/generate-knowledge.d.ts +2 -2
  27. package/dist/open-web-ui-knowledge/generate-knowledge.d.ts.map +1 -1
  28. package/dist/tsbuildinfo +1 -1
  29. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -3554,11 +3554,20 @@ var knowledgeExtraFileSchema = implement().with({
3554
3554
  id: z2.string(),
3555
3555
  title: z2.string()
3556
3556
  });
3557
+ var knowledgeExportsSchema = implement().with({
3558
+ enabled: z2.boolean().optional(),
3559
+ exclude: z2.array(z2.string()).optional(),
3560
+ extraFiles: z2.array(knowledgeExtraFileSchema).optional(),
3561
+ metadata: z2.record(z2.string(), z2.string()).optional(),
3562
+ pageTitlePrefix: z2.string().optional(),
3563
+ staticPath: z2.string().optional()
3564
+ });
3557
3565
  var knowledgeIntegrationSchema = implement().with(
3558
3566
  {
3559
3567
  baseUrl: z2.string().optional(),
3560
3568
  description: z2.string().optional(),
3561
3569
  exclude: z2.array(z2.string()).optional(),
3570
+ exports: knowledgeExportsSchema.optional(),
3562
3571
  extraFiles: z2.array(knowledgeExtraFileSchema).optional(),
3563
3572
  metadata: z2.record(z2.string(), z2.string()).optional(),
3564
3573
  name: z2.string().optional(),
@@ -3604,6 +3613,7 @@ function defined(value) {
3604
3613
  }
3605
3614
  var frontmatterSchema = implement().with({
3606
3615
  categories: z3.string().array().optional(),
3616
+ description: z3.string().optional(),
3607
3617
  group: z3.string().optional(),
3608
3618
  hidden: z3.boolean().optional(),
3609
3619
  hideBreadcrumbs: z3.boolean().optional(),
@@ -4353,6 +4363,36 @@ var alertToEmphasis = {
4353
4363
  warning: "warning"
4354
4364
  };
4355
4365
 
4366
+ // src/docs-plugin/remark/remark-frontmatter-interpolation.ts
4367
+ import { visit as visit4 } from "unist-util-visit";
4368
+ var FRONTMATTER_PATTERN = /^\s*frontmatter\.(\w+)\s*$/;
4369
+ function isMdxExpression(node) {
4370
+ const n = node;
4371
+ return (n.type === "mdxFlowExpression" || n.type === "mdxTextExpression") && typeof n.value === "string";
4372
+ }
4373
+ var remarkFrontmatterInterpolation = (frontmatter) => {
4374
+ return (tree) => {
4375
+ visit4(tree, (node, index, parent) => {
4376
+ if (!isMdxExpression(node) || index === void 0 || !parent) {
4377
+ return;
4378
+ }
4379
+ const match = node.value.match(FRONTMATTER_PATTERN);
4380
+ if (!match) {
4381
+ return;
4382
+ }
4383
+ const key = match[1];
4384
+ const value = frontmatter[key];
4385
+ if (typeof value === "string" || typeof value === "number") {
4386
+ const textNode = {
4387
+ type: "text",
4388
+ value: String(value)
4389
+ };
4390
+ parent.children[index] = textNode;
4391
+ }
4392
+ });
4393
+ };
4394
+ };
4395
+
4356
4396
  // src/docs-plugin/internal/services/markdown/remark-remove-code-blocks.ts
4357
4397
  import { remove } from "unist-util-remove";
4358
4398
  var remarkRemoveMermaidCodeBlocks = () => {
@@ -4450,14 +4490,9 @@ var MarkdownIndexer = class {
4450
4490
  }
4451
4491
  }
4452
4492
  parseMarkdown(fileContents, frontmatter) {
4453
- const file = unified3().use(remarkMdx2).use(remarkRemoveJsx).use(remarkRemoveMermaidCodeBlocks).use(remarkParse3).use(remarkGfm).use(remarkAlerts).use(remarkRehype).use(rehypeStringify).processSync(fileContents);
4493
+ const file = unified3().use(remarkMdx2).use(remarkRemoveJsx).use(remarkRemoveMermaidCodeBlocks).use(remarkParse3).use(remarkGfm).use(remarkAlerts).use(remarkFrontmatterInterpolation, frontmatter).use(remarkRehype).use(rehypeStringify).processSync(fileContents);
4454
4494
  let contents = file.toString();
4455
4495
  contents = contents.substring(contents.indexOf("<h1>"));
4456
- for (const [key, value] of Object.entries(frontmatter)) {
4457
- if (typeof value === "string" || typeof value === "number") {
4458
- contents = contents.replaceAll(`frontmatter.${key}`, `${value}`);
4459
- }
4460
- }
4461
4496
  const htmlAst = unified3().data("settings", { fragment: true }).use(rehypeParse).use(rehypeStringify).use(rehypeSlug).processSync(contents);
4462
4497
  contents = htmlAst.toString();
4463
4498
  return this.build(contents);
@@ -5036,6 +5071,7 @@ var SearchIndexer = class {
5036
5071
  this.metaJson,
5037
5072
  routeMeta?.title || frontmatter.title || ""
5038
5073
  ),
5074
+ description: frontmatter.description,
5039
5075
  hidden: defined(routeMeta.hidden) ? routeMeta.hidden : frontmatter.hidden,
5040
5076
  hideBreadcrumbs: defined(routeMeta.hideBreadcrumbs) ? routeMeta.hideBreadcrumbs : frontmatter.hideBreadcrumbs,
5041
5077
  hideFromSearch: defined(routeMeta.hideFromSearch) ? routeMeta.hideFromSearch : frontmatter.hideFromSearch,
@@ -5621,14 +5657,14 @@ import {
5621
5657
  stat,
5622
5658
  writeFile as writeFile3
5623
5659
  } from "node:fs/promises";
5624
- import { basename, dirname, extname, join as join3, relative as relative2, resolve as resolve5 } from "node:path";
5660
+ import { basename, dirname, extname, join as join4, relative as relative2, resolve as resolve5 } from "node:path";
5625
5661
  import remarkFrontmatter3 from "remark-frontmatter";
5626
5662
  import remarkMdx3 from "remark-mdx";
5627
5663
  import remarkParse4 from "remark-parse";
5628
5664
  import remarkParseFrontmatter2 from "remark-parse-frontmatter";
5629
5665
  import remarkStringify3 from "remark-stringify";
5630
5666
  import { unified as unified4 } from "unified";
5631
- import { visit as visit7 } from "unist-util-visit";
5667
+ import { visit as visit10 } from "unist-util-visit";
5632
5668
  import { kebabCase } from "@qualcomm-ui/utils/change-case";
5633
5669
 
5634
5670
  // src/docs-plugin/docs-plugin.ts
@@ -5636,24 +5672,31 @@ import chalk3 from "chalk";
5636
5672
  import chokidar from "chokidar";
5637
5673
  import { glob as glob2 } from "glob";
5638
5674
  import { readFileSync as readFileSync2 } from "node:fs";
5639
- import { resolve as resolve3 } from "node:path";
5675
+ import { join as join2, resolve as resolve3 } from "node:path";
5640
5676
  import prettyMilliseconds from "pretty-ms";
5641
5677
  var isDev = process.env.NODE_ENV === "development";
5642
5678
  var VIRTUAL_MODULE_ID = "\0@qualcomm-ui/mdx-vite-plugin";
5643
5679
  var PluginState = class {
5644
5680
  buildCount = 0;
5681
+ config = null;
5645
5682
  configFilePath = "";
5646
5683
  docPropsFilePath = "";
5684
+ exports = { basePath: "", enabled: false, pages: [] };
5647
5685
  indexer;
5648
5686
  configLoader = null;
5687
+ knowledgeConfig = void 0;
5649
5688
  routesDir;
5650
5689
  servers = [];
5651
5690
  timeout = void 0;
5691
+ exportsTimeout = void 0;
5652
5692
  watching = false;
5653
5693
  cwd;
5654
5694
  init(cwd2) {
5655
5695
  this.cwd = cwd2;
5656
5696
  }
5697
+ getCwd() {
5698
+ return this.cwd;
5699
+ }
5657
5700
  get docPropsDirectory() {
5658
5701
  if (!this.docPropsFilePath) {
5659
5702
  return "";
@@ -5664,7 +5707,10 @@ var PluginState = class {
5664
5707
  );
5665
5708
  }
5666
5709
  get siteData() {
5710
+ const { filePath: _filePath, ...config2 } = this.config ?? {};
5667
5711
  return {
5712
+ config: config2,
5713
+ exports: this.exports,
5668
5714
  navItems: state.indexer.navItems,
5669
5715
  pageDocProps: state.indexer.pageDocProps,
5670
5716
  pageMap: state.indexer.pageMap,
@@ -5685,14 +5731,24 @@ var PluginState = class {
5685
5731
  }
5686
5732
  }
5687
5733
  createIndexer(config2) {
5734
+ this.config = config2;
5688
5735
  this.configFilePath = config2.filePath;
5689
5736
  this.docPropsFilePath = config2.typeDocProps ? fixPath(resolve3(this.cwd, config2.typeDocProps)) : "";
5690
5737
  this.routesDir = fixPath(resolve3(config2.appDirectory, config2.pageDirectory));
5738
+ this.knowledgeConfig = config2.knowledge;
5691
5739
  this.indexer = new SearchIndexer({
5692
5740
  ...config2,
5693
5741
  srcDir: fixPath(resolve3(this.cwd, config2.appDirectory)),
5694
5742
  typeDocProps: this.resolveDocProps()
5695
5743
  });
5744
+ const exportsConfig = config2.knowledge?.global?.exports;
5745
+ const exportsEnabled = exportsConfig?.enabled ?? false;
5746
+ const exportsPath = exportsConfig?.staticPath ?? "exports/md";
5747
+ this.exports = {
5748
+ basePath: exportsEnabled ? `/${exportsPath}` : "",
5749
+ enabled: exportsEnabled,
5750
+ pages: []
5751
+ };
5696
5752
  }
5697
5753
  buildIndex(shouldLog) {
5698
5754
  const files = glob2.sync(
@@ -5765,6 +5821,41 @@ var PluginState = class {
5765
5821
  });
5766
5822
  });
5767
5823
  }
5824
+ async generateExports(publicDir) {
5825
+ if (!this.exports.enabled || !this.knowledgeConfig?.global) {
5826
+ return;
5827
+ }
5828
+ const globalConfig = this.knowledgeConfig.global;
5829
+ const exportsConfig = globalConfig.exports ?? {};
5830
+ const exportsPath = exportsConfig.staticPath ?? "exports/md";
5831
+ const outputPath = join2(publicDir, exportsPath);
5832
+ const startTime = Date.now();
5833
+ const pageIds = await generate({
5834
+ baseUrl: globalConfig.baseUrl,
5835
+ clean: true,
5836
+ docPropsPath: this.docPropsFilePath || void 0,
5837
+ exclude: exportsConfig.exclude ?? globalConfig.exclude,
5838
+ extraFiles: exportsConfig.extraFiles ?? globalConfig.extraFiles,
5839
+ metadata: exportsConfig.metadata ?? globalConfig.metadata,
5840
+ outputMode: "per-page",
5841
+ outputPath,
5842
+ pageTitlePrefix: exportsConfig.pageTitlePrefix ?? globalConfig.pageTitlePrefix,
5843
+ routeDir: this.routesDir
5844
+ });
5845
+ this.exports.pages = pageIds;
5846
+ console.debug(
5847
+ `${chalk3.magenta.bold(`@qualcomm-ui/mdx-vite/docs-plugin:`)} Generated Markdown exports in: ${chalk3.blueBright.bold(prettyMilliseconds(Date.now() - startTime))}`
5848
+ );
5849
+ }
5850
+ debouncedGenerateExports(publicDir) {
5851
+ if (!this.exports.enabled) {
5852
+ return;
5853
+ }
5854
+ clearTimeout(this.exportsTimeout);
5855
+ this.exportsTimeout = setTimeout(() => {
5856
+ void this.generateExports(publicDir);
5857
+ }, 500);
5858
+ }
5768
5859
  };
5769
5860
  var state = new PluginState();
5770
5861
 
@@ -5793,11 +5884,17 @@ import { heading } from "hast-util-heading";
5793
5884
  import { headingRank as headingRank2 } from "hast-util-heading-rank";
5794
5885
 
5795
5886
  // src/docs-plugin/remark/remark-code-tabs.ts
5796
- import { visit as visit4 } from "unist-util-visit";
5887
+ import { visit as visit5 } from "unist-util-visit";
5888
+
5889
+ // src/docs-plugin/remark/remark-frontmatter-description.ts
5890
+ import { visit as visit6 } from "unist-util-visit";
5891
+
5892
+ // src/docs-plugin/remark/remark-frontmatter-title.ts
5893
+ import { visit as visit7 } from "unist-util-visit";
5797
5894
 
5798
5895
  // src/docs-plugin/remark/remark-self-link-headings.ts
5799
5896
  import { toString as toString2 } from "mdast-util-to-string";
5800
- import { visit as visit5 } from "unist-util-visit";
5897
+ import { visit as visit8 } from "unist-util-visit";
5801
5898
  var emptyOptions2 = {};
5802
5899
  function remarkSelfLinkHeadings(baseUrl = "", options) {
5803
5900
  if (!baseUrl) {
@@ -5825,7 +5922,7 @@ function remarkSelfLinkHeadings(baseUrl = "", options) {
5825
5922
  }
5826
5923
  return (tree) => {
5827
5924
  seenIds.clear();
5828
- visit5(tree, "heading", (node) => {
5925
+ visit8(tree, "heading", (node) => {
5829
5926
  if (allowedLevels.has(node.depth)) {
5830
5927
  const text = toString2(node);
5831
5928
  const slug = prefix + createSlug(text);
@@ -5842,14 +5939,14 @@ function remarkSelfLinkHeadings(baseUrl = "", options) {
5842
5939
  }
5843
5940
 
5844
5941
  // src/docs-plugin/remark/remark-spoilers.ts
5845
- import { visit as visit6 } from "unist-util-visit";
5942
+ import { visit as visit9 } from "unist-util-visit";
5846
5943
 
5847
5944
  // src/docs-plugin/shiki/shiki-transformer-preview-block.ts
5848
5945
  import { dedent } from "@qualcomm-ui/utils/dedent";
5849
5946
 
5850
5947
  // src/open-web-ui-knowledge/load-config-from-env.ts
5851
5948
  import { existsSync } from "node:fs";
5852
- import { join as join2, resolve as resolve4 } from "node:path";
5949
+ import { join as join3, resolve as resolve4 } from "node:path";
5853
5950
  function parseCliMetadata(cliMetadata) {
5854
5951
  if (!cliMetadata?.length) {
5855
5952
  return void 0;
@@ -5865,7 +5962,7 @@ function loadKnowledgeConfigFromEnv(options) {
5865
5962
  if (!outputPath) {
5866
5963
  throw new Error("Missing required outputPath");
5867
5964
  }
5868
- const routeDir = join2(
5965
+ const routeDir = join3(
5869
5966
  resolvedConfig.appDirectory,
5870
5967
  resolvedConfig.pageDirectory
5871
5968
  );
@@ -5942,7 +6039,7 @@ async function resolveModulePath(importPath, fromFile) {
5942
6039
  }
5943
6040
  }
5944
6041
  if (await exists(baseResolved)) {
5945
- const indexPath = join3(baseResolved, "index.ts");
6042
+ const indexPath = join4(baseResolved, "index.ts");
5946
6043
  if (await exists(indexPath)) {
5947
6044
  return indexPath;
5948
6045
  }
@@ -5954,7 +6051,7 @@ function extractMetadata(metadata) {
5954
6051
  }
5955
6052
  var replaceNpmInstallTabs = () => {
5956
6053
  return (tree, _file, done) => {
5957
- visit7(tree, "mdxJsxFlowElement", (node) => {
6054
+ visit10(tree, "mdxJsxFlowElement", (node) => {
5958
6055
  if (node?.name === "NpmInstallTabs") {
5959
6056
  const packages = node.attributes?.find(
5960
6057
  (attr) => attr.type === "mdxJsxAttribute" && attr.name === "packages"
@@ -5998,7 +6095,7 @@ var KnowledgeGenerator = class {
5998
6095
  this.docProps = docProps;
5999
6096
  if (pages.length === 0) {
6000
6097
  console.log("No pages found.");
6001
- return;
6098
+ return [];
6002
6099
  }
6003
6100
  if (this.config.verbose) {
6004
6101
  console.log(`Found ${pages.length} page(s)`);
@@ -6031,9 +6128,10 @@ var KnowledgeGenerator = class {
6031
6128
  );
6032
6129
  await this.generateExtraFiles(extractedMetadata);
6033
6130
  }
6131
+ return pages.map((page) => page.id);
6034
6132
  }
6035
6133
  async loadDocProps() {
6036
- 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");
6134
+ const resolvedDocPropsPath = this.config.docPropsPath ? await exists(this.config.docPropsPath) ? this.config.docPropsPath : resolve5(process.cwd(), this.config.docPropsPath) : join4(dirname(this.config.routeDir), "doc-props.json");
6037
6135
  if (!await exists(resolvedDocPropsPath)) {
6038
6136
  if (this.config.verbose) {
6039
6137
  console.log(`Doc props file not found at: ${resolvedDocPropsPath}`);
@@ -6080,20 +6178,20 @@ var KnowledgeGenerator = class {
6080
6178
  }
6081
6179
  const entries = await readdir(dirPath, { withFileTypes: true });
6082
6180
  const mdxFiles = entries.filter(
6083
- (f) => f.name.endsWith(".mdx") && !shouldExclude(join3(dirPath, f.name))
6181
+ (f) => f.name.endsWith(".mdx") && !shouldExclude(join4(dirPath, f.name))
6084
6182
  ) ?? [];
6085
6183
  for (const mdxFile of mdxFiles) {
6086
6184
  const demosFolder = entries.find((f) => f.name === "demos");
6087
- const demosFolderPath = demosFolder ? join3(dirPath, demosFolder.name) : void 0;
6185
+ const demosFolderPath = demosFolder ? join4(dirPath, demosFolder.name) : void 0;
6088
6186
  const segments = getPathSegmentsFromFileName(
6089
- join3(dirPath, mdxFile.name),
6187
+ join4(dirPath, mdxFile.name),
6090
6188
  this.config.routeDir
6091
6189
  );
6092
6190
  const url = getPathnameFromPathSegments(segments);
6093
6191
  components.push({
6094
6192
  demosFolder: demosFolderPath,
6095
6193
  id: segments.join("-").trim(),
6096
- mdxFile: join3(dirPath, mdxFile.name),
6194
+ mdxFile: join4(dirPath, mdxFile.name),
6097
6195
  name: segments.at(-1),
6098
6196
  path: dirPath,
6099
6197
  url: this.config.baseUrl ? new URL(url, this.config.baseUrl).toString() : void 0
@@ -6104,7 +6202,7 @@ var KnowledgeGenerator = class {
6104
6202
  }
6105
6203
  }
6106
6204
  for (const entry of entries) {
6107
- const fullPath = join3(dirPath, entry.name);
6205
+ const fullPath = join4(dirPath, entry.name);
6108
6206
  const stats = await stat(fullPath);
6109
6207
  if (stats.isDirectory()) {
6110
6208
  await scanDirectory(fullPath);
@@ -6270,7 +6368,7 @@ ${codeText}
6270
6368
  }
6271
6369
  };
6272
6370
  return () => (tree, _file, done) => {
6273
- visit7(tree, "mdxJsxFlowElement", (node) => {
6371
+ visit10(tree, "mdxJsxFlowElement", (node) => {
6274
6372
  const handler = node.name && handlers[node.name];
6275
6373
  if (!handler) {
6276
6374
  return;
@@ -6310,7 +6408,7 @@ ${codeText}
6310
6408
  */
6311
6409
  replaceTypeDocProps() {
6312
6410
  return () => (tree, _file, done) => {
6313
- visit7(
6411
+ visit10(
6314
6412
  tree,
6315
6413
  "mdxJsxFlowElement",
6316
6414
  (node, index, parent) => {
@@ -6371,7 +6469,7 @@ ${codeText}
6371
6469
  replaceDemos(demosFolder, demoFiles) {
6372
6470
  return () => async (tree) => {
6373
6471
  const promises = [];
6374
- visit7(
6472
+ visit10(
6375
6473
  tree,
6376
6474
  "mdxJsxFlowElement",
6377
6475
  (node, index, parent) => {
@@ -6415,14 +6513,14 @@ ${codeText}
6415
6513
  }
6416
6514
  return;
6417
6515
  }
6418
- let demoFilePath = join3(demosFolder, filePath);
6516
+ let demoFilePath = join4(demosFolder, filePath);
6419
6517
  let isAngularDemo = false;
6420
6518
  if (!await exists(demoFilePath)) {
6421
- demoFilePath = join3(demosFolder, `${kebabName}.ts`);
6519
+ demoFilePath = join4(demosFolder, `${kebabName}.ts`);
6422
6520
  if (await exists(demoFilePath)) {
6423
6521
  isAngularDemo = true;
6424
6522
  filePath = `${kebabCase(demoName).replace("-component", ".component")}.ts`;
6425
- demoFilePath = join3(demosFolder, filePath);
6523
+ demoFilePath = join4(demosFolder, filePath);
6426
6524
  } else {
6427
6525
  console.log(` Demo not found ${demoName}`);
6428
6526
  if (parent && index !== void 0) {
@@ -6459,21 +6557,51 @@ ${codeText}
6459
6557
  await Promise.all(promises);
6460
6558
  };
6461
6559
  }
6560
+ replaceFrontmatterExpressions(frontmatter) {
6561
+ return () => (tree) => {
6562
+ visit10(
6563
+ tree,
6564
+ "mdxFlowExpression",
6565
+ (node, index, parent) => {
6566
+ if (node.value.trim() !== "frontmatter.description" || index === void 0 || !parent) {
6567
+ return;
6568
+ }
6569
+ if (frontmatter.description) {
6570
+ parent.children.splice(index, 1, {
6571
+ children: [{ type: "text", value: frontmatter.description }],
6572
+ type: "paragraph"
6573
+ });
6574
+ } else {
6575
+ parent.children.splice(index, 1);
6576
+ }
6577
+ }
6578
+ );
6579
+ const root = tree;
6580
+ const h1Index = root.children.findIndex((node) => {
6581
+ if (node.type !== "heading" || node.depth !== 1) {
6582
+ return false;
6583
+ }
6584
+ return node.children?.some(
6585
+ (child) => child.type === "mdxTextExpression" && child.value?.includes("frontmatter")
6586
+ );
6587
+ });
6588
+ if (h1Index >= 0) {
6589
+ root.children.splice(h1Index, 1);
6590
+ }
6591
+ };
6592
+ }
6462
6593
  /**
6463
6594
  * Processes MDX content by transforming JSX elements (TypeDocProps, demos)
6464
6595
  * into markdown, resolving relative links, and cleaning up formatting.
6465
6596
  */
6466
- async processMdxContent(mdxContent, pageUrl, demosFolder) {
6597
+ async processMdxContent(mdxContent, pageUrl, demosFolder, frontmatter) {
6467
6598
  const demoFiles = [];
6468
6599
  let processedContent = mdxContent;
6469
- const lines = processedContent.split("\n");
6470
- const titleLine = lines.findIndex((line) => line.startsWith("# "));
6471
- processedContent = titleLine >= 0 ? lines.slice(titleLine + 1).join("\n") : processedContent;
6472
6600
  processedContent = processedContent.replace(
6473
6601
  /\[([^\]]+)\]\(\.\/#([^)]+)\)/g,
6474
6602
  (_, text, anchor) => pageUrl && this.config.outputMode === "per-page" ? `[${text}](${pageUrl}#${anchor})` : text
6475
6603
  );
6476
- const processor = unified4().use(remarkParse4).use(remarkMdx3).use(this.replaceTypeDocProps()).use(await this.replaceThemeNodes()).use(this.replaceDemos(demosFolder, demoFiles)).use(remarkStringify3);
6604
+ const processor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkFrontmatter3, ["yaml"]).use(this.replaceTypeDocProps()).use(this.replaceFrontmatterExpressions(frontmatter)).use(await this.replaceThemeNodes()).use(this.replaceDemos(demosFolder, demoFiles)).use(remarkStringify3);
6477
6605
  const processed = await processor.process(processedContent);
6478
6606
  processedContent = String(processed);
6479
6607
  processedContent = processedContent.replace(/\n\s*\n\s*\n/g, "\n\n");
@@ -6495,9 +6623,10 @@ ${codeText}
6495
6623
  const { content: processedContent, demoFiles } = await this.processMdxContent(
6496
6624
  String(parsed),
6497
6625
  component.url,
6498
- component.demosFolder
6626
+ component.demosFolder,
6627
+ frontmatter
6499
6628
  );
6500
- const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkRemoveJsx).use(remarkStringify3);
6629
+ const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkFrontmatter3, ["yaml"]).use(remarkRemoveJsx).use(remarkStringify3);
6501
6630
  const removedJsx = String(
6502
6631
  await removeJsxProcessor.process(processedContent)
6503
6632
  );
@@ -6672,7 +6801,7 @@ ${codeText}
6672
6801
  };
6673
6802
  async function generate(config2) {
6674
6803
  const generator = new KnowledgeGenerator(config2);
6675
- await generator.run();
6804
+ return generator.run();
6676
6805
  }
6677
6806
  function addGenerateKnowledgeCommand() {
6678
6807
  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(
@@ -7020,7 +7149,7 @@ import { dedent as dedent2 } from "@qualcomm-ui/utils/dedent";
7020
7149
  // src/react-demo-plugin/demo-plugin-utils.ts
7021
7150
  import chalk4 from "chalk";
7022
7151
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
7023
- import { dirname as dirname2, join as join4, relative as relative3, resolve as resolve7, sep } from "node:path";
7152
+ import { dirname as dirname2, join as join5, relative as relative3, resolve as resolve7, sep } from "node:path";
7024
7153
  import * as ts from "typescript";
7025
7154
  import { pascalCase } from "@qualcomm-ui/utils/change-case";
7026
7155
  function extractPageId(filePath, routesDir) {