@qualcomm-ui/mdx-vite 2.6.4 → 2.8.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
@@ -3549,6 +3549,27 @@ var routeMetaSchema = implement().with({
3549
3549
  var typeDocPropsSchema = implement().with({
3550
3550
  includeInSearchIndex: z2.boolean().optional()
3551
3551
  });
3552
+ var knowledgeExtraFileSchema = implement().with({
3553
+ contents: z2.string(),
3554
+ id: z2.string(),
3555
+ title: z2.string()
3556
+ });
3557
+ var knowledgeIntegrationSchema = implement().with(
3558
+ {
3559
+ baseUrl: z2.string().optional(),
3560
+ description: z2.string().optional(),
3561
+ exclude: z2.array(z2.string()).optional(),
3562
+ extraFiles: z2.array(knowledgeExtraFileSchema).optional(),
3563
+ metadata: z2.record(z2.string(), z2.string()).optional(),
3564
+ name: z2.string().optional(),
3565
+ outputMode: z2.union([z2.literal("per-page"), z2.literal("aggregated")]).optional(),
3566
+ outputPath: z2.string().optional(),
3567
+ pageTitlePrefix: z2.string().optional()
3568
+ }
3569
+ );
3570
+ var knowledgeConfigSchema = implement().with({
3571
+ global: knowledgeIntegrationSchema.optional()
3572
+ });
3552
3573
  var configSchema = implement().with({
3553
3574
  appDirectory: z2.string().optional(),
3554
3575
  disableCache: z2.boolean().optional(),
@@ -3563,6 +3584,7 @@ var configSchema = implement().with({
3563
3584
  ])
3564
3585
  ).optional(),
3565
3586
  hotUpdateIgnore: z2.instanceof(RegExp).optional(),
3587
+ knowledge: knowledgeConfigSchema.optional(),
3566
3588
  navConfig: z2.array(z2.union([routeMetaSchema, navMetaSchema])).optional(),
3567
3589
  pageDirectory: z2.string().optional(),
3568
3590
  pageTimestampMetadata: z2.union([
@@ -3570,10 +3592,7 @@ var configSchema = implement().with({
3570
3592
  z2.literal("timestamp"),
3571
3593
  z2.literal("user-and-timestamp")
3572
3594
  ]).optional(),
3573
- routingStrategy: z2.union([
3574
- z2.literal("vite-generouted"),
3575
- z2.function(z2.tuple([z2.string()]), z2.array(z2.string()))
3576
- ]).optional(),
3595
+ routingStrategy: z2.union([z2.literal("vite-generouted"), z2.any()]).optional(),
3577
3596
  typeDocProps: z2.string().optional(),
3578
3597
  typeDocPropsOptions: typeDocPropsSchema.optional()
3579
3598
  });
@@ -3585,6 +3604,7 @@ function defined(value) {
3585
3604
  }
3586
3605
  var frontmatterSchema = implement().with({
3587
3606
  categories: z3.string().array().optional(),
3607
+ description: z3.string().optional(),
3588
3608
  group: z3.string().optional(),
3589
3609
  hidden: z3.boolean().optional(),
3590
3610
  hideBreadcrumbs: z3.boolean().optional(),
@@ -5017,6 +5037,7 @@ var SearchIndexer = class {
5017
5037
  this.metaJson,
5018
5038
  routeMeta?.title || frontmatter.title || ""
5019
5039
  ),
5040
+ description: frontmatter.description,
5020
5041
  hidden: defined(routeMeta.hidden) ? routeMeta.hidden : frontmatter.hidden,
5021
5042
  hideBreadcrumbs: defined(routeMeta.hideBreadcrumbs) ? routeMeta.hideBreadcrumbs : frontmatter.hideBreadcrumbs,
5022
5043
  hideFromSearch: defined(routeMeta.hideFromSearch) ? routeMeta.hideFromSearch : frontmatter.hideFromSearch,
@@ -5592,6 +5613,7 @@ function addDownloadKnowledgeCommand() {
5592
5613
  }
5593
5614
 
5594
5615
  // src/open-web-ui-knowledge/generate-knowledge.ts
5616
+ import { minimatch } from "minimatch";
5595
5617
  import {
5596
5618
  access,
5597
5619
  mkdir as mkdir2,
@@ -5601,14 +5623,14 @@ import {
5601
5623
  stat,
5602
5624
  writeFile as writeFile3
5603
5625
  } from "node:fs/promises";
5604
- import { basename, dirname, extname, join as join3, resolve as resolve5 } from "node:path";
5626
+ import { basename, dirname, extname, join as join3, relative as relative2, resolve as resolve5 } from "node:path";
5605
5627
  import remarkFrontmatter3 from "remark-frontmatter";
5606
5628
  import remarkMdx3 from "remark-mdx";
5607
5629
  import remarkParse4 from "remark-parse";
5608
5630
  import remarkParseFrontmatter2 from "remark-parse-frontmatter";
5609
5631
  import remarkStringify3 from "remark-stringify";
5610
5632
  import { unified as unified4 } from "unified";
5611
- import { visit as visit7 } from "unist-util-visit";
5633
+ import { visit as visit8 } from "unist-util-visit";
5612
5634
  import { kebabCase } from "@qualcomm-ui/utils/change-case";
5613
5635
 
5614
5636
  // src/docs-plugin/docs-plugin.ts
@@ -5775,9 +5797,12 @@ import { headingRank as headingRank2 } from "hast-util-heading-rank";
5775
5797
  // src/docs-plugin/remark/remark-code-tabs.ts
5776
5798
  import { visit as visit4 } from "unist-util-visit";
5777
5799
 
5800
+ // src/docs-plugin/remark/remark-frontmatter-description.ts
5801
+ import { visit as visit5 } from "unist-util-visit";
5802
+
5778
5803
  // src/docs-plugin/remark/remark-self-link-headings.ts
5779
5804
  import { toString as toString2 } from "mdast-util-to-string";
5780
- import { visit as visit5 } from "unist-util-visit";
5805
+ import { visit as visit6 } from "unist-util-visit";
5781
5806
  var emptyOptions2 = {};
5782
5807
  function remarkSelfLinkHeadings(baseUrl = "", options) {
5783
5808
  if (!baseUrl) {
@@ -5805,7 +5830,7 @@ function remarkSelfLinkHeadings(baseUrl = "", options) {
5805
5830
  }
5806
5831
  return (tree) => {
5807
5832
  seenIds.clear();
5808
- visit5(tree, "heading", (node) => {
5833
+ visit6(tree, "heading", (node) => {
5809
5834
  if (allowedLevels.has(node.depth)) {
5810
5835
  const text = toString2(node);
5811
5836
  const slug = prefix + createSlug(text);
@@ -5822,7 +5847,7 @@ function remarkSelfLinkHeadings(baseUrl = "", options) {
5822
5847
  }
5823
5848
 
5824
5849
  // src/docs-plugin/remark/remark-spoilers.ts
5825
- import { visit as visit6 } from "unist-util-visit";
5850
+ import { visit as visit7 } from "unist-util-visit";
5826
5851
 
5827
5852
  // src/docs-plugin/shiki/shiki-transformer-preview-block.ts
5828
5853
  import { dedent } from "@qualcomm-ui/utils/dedent";
@@ -5830,15 +5855,21 @@ import { dedent } from "@qualcomm-ui/utils/dedent";
5830
5855
  // src/open-web-ui-knowledge/load-config-from-env.ts
5831
5856
  import { existsSync } from "node:fs";
5832
5857
  import { join as join2, resolve as resolve4 } from "node:path";
5858
+ function parseCliMetadata(cliMetadata) {
5859
+ if (!cliMetadata?.length) {
5860
+ return void 0;
5861
+ }
5862
+ return Object.fromEntries(cliMetadata.map((entry) => entry.split("=")));
5863
+ }
5833
5864
  function loadKnowledgeConfigFromEnv(options) {
5834
- const exclude = options.exclude || (process.env.FILE_EXCLUDE_PATTERN ?? "").split(",");
5835
- const outputPath = options.outputPath || process.env.KNOWLEDGE_OUTPUT_PATH;
5836
- const prefix = process.env.PAGE_TITLE_PREFIX;
5865
+ const configLoader = new ConfigLoader({});
5866
+ const resolvedConfig = configLoader.loadConfig();
5867
+ const fileConfig = resolvedConfig.knowledge?.global;
5868
+ const exclude = (options.exclude?.length ? options.exclude : void 0) ?? fileConfig?.exclude ?? (process.env.FILE_EXCLUDE_PATTERN ?? "").split(",").filter(Boolean);
5869
+ const outputPath = options.outputPath ?? fileConfig?.outputPath ?? process.env.KNOWLEDGE_OUTPUT_PATH;
5837
5870
  if (!outputPath) {
5838
5871
  throw new Error("Missing required outputPath");
5839
5872
  }
5840
- const configLoader = new ConfigLoader({});
5841
- const resolvedConfig = configLoader.loadConfig();
5842
5873
  const routeDir = join2(
5843
5874
  resolvedConfig.appDirectory,
5844
5875
  resolvedConfig.pageDirectory
@@ -5846,13 +5877,18 @@ function loadKnowledgeConfigFromEnv(options) {
5846
5877
  if (!existsSync(resolve4(routeDir))) {
5847
5878
  throw new Error(`Route directory ${routeDir} does not exist`);
5848
5879
  }
5880
+ const cliMetadata = parseCliMetadata(options.metadata);
5881
+ const mergedMetadata = fileConfig?.metadata || cliMetadata ? { ...fileConfig?.metadata, ...cliMetadata } : void 0;
5849
5882
  return {
5883
+ ...fileConfig,
5850
5884
  ...options,
5851
- baseUrl: options.baseUrl || process.env.DOCS_SITE_BASE_URL,
5885
+ baseUrl: options.baseUrl ?? fileConfig?.baseUrl ?? process.env.DOCS_SITE_BASE_URL,
5852
5886
  docPropsPath: resolvedConfig.typeDocProps,
5853
5887
  exclude,
5888
+ extraFiles: fileConfig?.extraFiles,
5889
+ metadata: mergedMetadata,
5854
5890
  outputPath,
5855
- pageTitlePrefix: prefix,
5891
+ pageTitlePrefix: options.pageTitlePrefix ?? fileConfig?.pageTitlePrefix ?? process.env.PAGE_TITLE_PREFIX,
5856
5892
  routeDir
5857
5893
  };
5858
5894
  }
@@ -5919,14 +5955,11 @@ async function resolveModulePath(importPath, fromFile) {
5919
5955
  return null;
5920
5956
  }
5921
5957
  function extractMetadata(metadata) {
5922
- return (metadata ?? []).map((current) => {
5923
- const [key, value] = current.split("=");
5924
- return [key, value];
5925
- });
5958
+ return Object.entries(metadata ?? {});
5926
5959
  }
5927
5960
  var replaceNpmInstallTabs = () => {
5928
5961
  return (tree, _file, done) => {
5929
- visit7(tree, "mdxJsxFlowElement", (node) => {
5962
+ visit8(tree, "mdxJsxFlowElement", (node) => {
5930
5963
  if (node?.name === "NpmInstallTabs") {
5931
5964
  const packages = node.attributes?.find(
5932
5965
  (attr) => attr.type === "mdxJsxAttribute" && attr.name === "packages"
@@ -6001,6 +6034,7 @@ var KnowledgeGenerator = class {
6001
6034
  processedPages,
6002
6035
  extractedMetadata
6003
6036
  );
6037
+ await this.generateExtraFiles(extractedMetadata);
6004
6038
  }
6005
6039
  }
6006
6040
  async loadDocProps() {
@@ -6031,26 +6065,27 @@ var KnowledgeGenerator = class {
6031
6065
  async scanPages() {
6032
6066
  const components = [];
6033
6067
  const excludePatterns = this.config.exclude ?? [];
6034
- const shouldExclude = (fileOrDir) => {
6035
- const dirName = basename(fileOrDir);
6036
- return excludePatterns.some((pattern) => {
6037
- if (pattern.includes("*")) {
6038
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
6039
- return regex.test(dirName);
6040
- }
6041
- return dirName === pattern;
6042
- });
6068
+ const shouldExclude = (absolutePath) => {
6069
+ if (excludePatterns.length === 0) {
6070
+ return false;
6071
+ }
6072
+ const relativePath = relative2(this.config.routeDir, absolutePath);
6073
+ return excludePatterns.some(
6074
+ (pattern) => minimatch(relativePath, pattern, { matchBase: true })
6075
+ );
6043
6076
  };
6044
6077
  const scanDirectory = async (dirPath) => {
6045
6078
  if (shouldExclude(dirPath)) {
6046
6079
  if (this.config.verbose) {
6047
- console.log(`Excluding directory: ${basename(dirPath)}`);
6080
+ console.log(
6081
+ `Excluding directory: ${relative2(this.config.routeDir, dirPath)}`
6082
+ );
6048
6083
  }
6049
6084
  return;
6050
6085
  }
6051
6086
  const entries = await readdir(dirPath, { withFileTypes: true });
6052
6087
  const mdxFiles = entries.filter(
6053
- (f) => f.name.endsWith(".mdx") && !shouldExclude(f.name)
6088
+ (f) => f.name.endsWith(".mdx") && !shouldExclude(join3(dirPath, f.name))
6054
6089
  ) ?? [];
6055
6090
  for (const mdxFile of mdxFiles) {
6056
6091
  const demosFolder = entries.find((f) => f.name === "demos");
@@ -6069,7 +6104,7 @@ var KnowledgeGenerator = class {
6069
6104
  url: this.config.baseUrl ? new URL(url, this.config.baseUrl).toString() : void 0
6070
6105
  });
6071
6106
  if (this.config.verbose) {
6072
- console.log(`Found component: ${basename(dirPath)}`);
6107
+ console.log(`Found file: ${basename(dirPath)}`);
6073
6108
  console.log(` Demos folder: ${demosFolderPath || "NOT FOUND"}`);
6074
6109
  }
6075
6110
  }
@@ -6240,7 +6275,7 @@ ${codeText}
6240
6275
  }
6241
6276
  };
6242
6277
  return () => (tree, _file, done) => {
6243
- visit7(tree, "mdxJsxFlowElement", (node) => {
6278
+ visit8(tree, "mdxJsxFlowElement", (node) => {
6244
6279
  const handler = node.name && handlers[node.name];
6245
6280
  if (!handler) {
6246
6281
  return;
@@ -6280,7 +6315,7 @@ ${codeText}
6280
6315
  */
6281
6316
  replaceTypeDocProps() {
6282
6317
  return () => (tree, _file, done) => {
6283
- visit7(
6318
+ visit8(
6284
6319
  tree,
6285
6320
  "mdxJsxFlowElement",
6286
6321
  (node, index, parent) => {
@@ -6341,7 +6376,7 @@ ${codeText}
6341
6376
  replaceDemos(demosFolder, demoFiles) {
6342
6377
  return () => async (tree) => {
6343
6378
  const promises = [];
6344
- visit7(
6379
+ visit8(
6345
6380
  tree,
6346
6381
  "mdxJsxFlowElement",
6347
6382
  (node, index, parent) => {
@@ -6429,11 +6464,32 @@ ${codeText}
6429
6464
  await Promise.all(promises);
6430
6465
  };
6431
6466
  }
6467
+ replaceFrontmatterDescription(frontmatter) {
6468
+ return () => (tree) => {
6469
+ visit8(
6470
+ tree,
6471
+ "mdxFlowExpression",
6472
+ (node, index, parent) => {
6473
+ if (node.value.trim() !== "frontmatter.description" || index === void 0 || !parent) {
6474
+ return;
6475
+ }
6476
+ if (frontmatter.description) {
6477
+ parent.children.splice(index, 1, {
6478
+ children: [{ type: "text", value: frontmatter.description }],
6479
+ type: "paragraph"
6480
+ });
6481
+ } else {
6482
+ parent.children.splice(index, 1);
6483
+ }
6484
+ }
6485
+ );
6486
+ };
6487
+ }
6432
6488
  /**
6433
6489
  * Processes MDX content by transforming JSX elements (TypeDocProps, demos)
6434
6490
  * into markdown, resolving relative links, and cleaning up formatting.
6435
6491
  */
6436
- async processMdxContent(mdxContent, pageUrl, demosFolder) {
6492
+ async processMdxContent(mdxContent, pageUrl, demosFolder, frontmatter) {
6437
6493
  const demoFiles = [];
6438
6494
  let processedContent = mdxContent;
6439
6495
  const lines = processedContent.split("\n");
@@ -6443,7 +6499,7 @@ ${codeText}
6443
6499
  /\[([^\]]+)\]\(\.\/#([^)]+)\)/g,
6444
6500
  (_, text, anchor) => pageUrl && this.config.outputMode === "per-page" ? `[${text}](${pageUrl}#${anchor})` : text
6445
6501
  );
6446
- const processor = unified4().use(remarkParse4).use(remarkMdx3).use(this.replaceTypeDocProps()).use(await this.replaceThemeNodes()).use(this.replaceDemos(demosFolder, demoFiles)).use(remarkStringify3);
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);
6447
6503
  const processed = await processor.process(processedContent);
6448
6504
  processedContent = String(processed);
6449
6505
  processedContent = processedContent.replace(/\n\s*\n\s*\n/g, "\n\n");
@@ -6465,7 +6521,8 @@ ${codeText}
6465
6521
  const { content: processedContent, demoFiles } = await this.processMdxContent(
6466
6522
  String(parsed),
6467
6523
  component.url,
6468
- component.demosFolder
6524
+ component.demosFolder,
6525
+ frontmatter
6469
6526
  );
6470
6527
  const removeJsxProcessor = unified4().use(remarkParse4).use(remarkMdx3).use(remarkRemoveJsx).use(remarkStringify3);
6471
6528
  const removedJsx = String(
@@ -6520,10 +6577,41 @@ ${codeText}
6520
6577
  const outputStats = await stat(this.config.outputPath);
6521
6578
  const outputSizeKb = (outputStats.size / 1024).toFixed(1);
6522
6579
  console.log(
6523
- `Generated ${this.config.outputPath} with ${pages.length} component(s) at: ${this.config.outputPath}`
6580
+ `Generated ${this.config.outputPath} with ${pages.length} files(s) at: ${this.config.outputPath}`
6524
6581
  );
6525
6582
  console.log(`File size: ${outputSizeKb} KB`);
6526
6583
  }
6584
+ async generateExtraFiles(metadata) {
6585
+ const extraFiles = this.config.extraFiles ?? [];
6586
+ if (extraFiles.length === 0) {
6587
+ return;
6588
+ }
6589
+ let totalSize = 0;
6590
+ await Promise.all(
6591
+ extraFiles.map(async (extraFile) => {
6592
+ const lines = [];
6593
+ if (metadata.length) {
6594
+ lines.push("---");
6595
+ for (const [key, value] of metadata) {
6596
+ lines.push(`${key}: ${value}`);
6597
+ }
6598
+ lines.push("---");
6599
+ lines.push("");
6600
+ }
6601
+ lines.push(`# ${extraFile.title}`);
6602
+ lines.push("");
6603
+ lines.push(extraFile.contents);
6604
+ lines.push("");
6605
+ const outfile = `${resolve5(this.config.outputPath)}/${kebabCase(extraFile.id)}.md`;
6606
+ await writeFile3(outfile, lines.join("\n"), "utf-8");
6607
+ const stats = await stat(outfile);
6608
+ totalSize += stats.size / 1024;
6609
+ })
6610
+ );
6611
+ console.log(
6612
+ `Generated ${extraFiles.length} extra file(s) (${totalSize.toFixed(1)} KB)`
6613
+ );
6614
+ }
6527
6615
  async generatePerPageExports(pages, processedPages, metadata) {
6528
6616
  await mkdir2(dirname(this.config.outputPath), { recursive: true }).catch(
6529
6617
  () => {
@@ -6563,7 +6651,7 @@ ${codeText}
6563
6651
  }
6564
6652
  lines.push(content);
6565
6653
  lines.push("");
6566
- if (this.config.includeImports && processedPage.demoFiles.length > 0) {
6654
+ if (processedPage.demoFiles.length > 0) {
6567
6655
  if (this.config.verbose) {
6568
6656
  console.log(
6569
6657
  `Collecting imports for ${page.name} from ${processedPage.demoFiles.length} demo files`
@@ -6605,7 +6693,7 @@ ${codeText}
6605
6693
  totalSize += stats.size / 1024;
6606
6694
  })
6607
6695
  );
6608
- console.log(`Generated ${count} component(s) in ${this.config.outputPath}`);
6696
+ console.log(`Generated ${count} files(s) in ${this.config.outputPath}`);
6609
6697
  console.log(`Folder size: ${totalSize.toFixed(1)} KB`);
6610
6698
  }
6611
6699
  };
@@ -6619,7 +6707,7 @@ function addGenerateKnowledgeCommand() {
6619
6707
  "Project description for llms.txt"
6620
6708
  ).option("-v, --verbose", "Enable verbose logging", false).option(
6621
6709
  "--exclude <patterns...>",
6622
- "Exclude file or folder patterns (supports * wildcards)",
6710
+ "Glob patterns to exclude (e.g., **/internal/**, guide/drafts/*)",
6623
6711
  []
6624
6712
  ).option("--base-url <url>", "Base URL for component documentation links").option("--metadata <pairs...>", "metadata key-value pairs").option("--clean", "Clean the output path before generating").option("--include-imports", "Include relative import source files", true).action(async (options) => {
6625
6713
  loadEnv();
@@ -6959,11 +7047,11 @@ import { dedent as dedent2 } from "@qualcomm-ui/utils/dedent";
6959
7047
  // src/react-demo-plugin/demo-plugin-utils.ts
6960
7048
  import chalk4 from "chalk";
6961
7049
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
6962
- import { dirname as dirname2, join as join4, relative as relative2, resolve as resolve7, sep } from "node:path";
7050
+ import { dirname as dirname2, join as join4, relative as relative3, resolve as resolve7, sep } from "node:path";
6963
7051
  import * as ts from "typescript";
6964
7052
  import { pascalCase } from "@qualcomm-ui/utils/change-case";
6965
7053
  function extractPageId(filePath, routesDir) {
6966
- const relativePath = relative2(routesDir, filePath);
7054
+ const relativePath = relative3(routesDir, filePath);
6967
7055
  const pathParts = relativePath.split(sep);
6968
7056
  if (pathParts.includes("demos")) {
6969
7057
  const demosIndex = pathParts.indexOf("demos");