@qualcomm-ui/mdx-vite 2.3.0 → 2.4.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/README.md +1 -2
- package/dist/angular-demo-plugin/angular-demo-plugin.d.ts +7 -1
- package/dist/angular-demo-plugin/angular-demo-plugin.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/docs-plugin/shiki/internal/index.d.ts +2 -0
- package/dist/docs-plugin/shiki/internal/index.d.ts.map +1 -0
- package/dist/docs-plugin/shiki/internal/shiki-transformer-tailwind.d.ts +50 -0
- package/dist/docs-plugin/shiki/internal/shiki-transformer-tailwind.d.ts.map +1 -0
- package/dist/docs-plugin/shiki/internal/tests/shiki-transformer-tailwind.spec.d.ts +2 -0
- package/dist/docs-plugin/shiki/internal/tests/shiki-transformer-tailwind.spec.d.ts.map +1 -0
- package/dist/docs-plugin/shiki/shiki-transformer-preview-block.d.ts.map +1 -1
- package/dist/docs-plugin/shiki/utils.d.ts +1 -0
- package/dist/docs-plugin/shiki/utils.d.ts.map +1 -1
- package/dist/index.js +668 -185
- package/dist/index.js.map +4 -4
- package/dist/react-demo-plugin/demo-plugin-types.d.ts +7 -0
- package/dist/react-demo-plugin/demo-plugin-types.d.ts.map +1 -1
- package/dist/react-demo-plugin/react-demo-plugin.d.ts +1 -1
- package/dist/react-demo-plugin/react-demo-plugin.d.ts.map +1 -1
- package/dist/tsbuildinfo +1 -1
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import chalk4 from "chalk";
|
|
|
5
5
|
import { watch } from "chokidar";
|
|
6
6
|
import { glob as glob2 } from "glob";
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
|
-
import { readFile, stat } from "node:fs/promises";
|
|
8
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
9
9
|
import { basename, dirname, join as join2, relative, resolve as resolve2 } from "node:path";
|
|
10
10
|
import {
|
|
11
11
|
createHighlighter
|
|
@@ -14,6 +14,7 @@ import * as ts from "typescript";
|
|
|
14
14
|
import {
|
|
15
15
|
quiCustomDarkTheme as quiCustomDarkTheme2
|
|
16
16
|
} from "@qualcomm-ui/mdx-common";
|
|
17
|
+
import { dedent as dedent2 } from "@qualcomm-ui/utils/dedent";
|
|
17
18
|
|
|
18
19
|
// src/docs-plugin/docs-plugin.ts
|
|
19
20
|
import chalk3 from "chalk";
|
|
@@ -2240,6 +2241,55 @@ function removeCodeAnnotations(code) {
|
|
|
2240
2241
|
return true;
|
|
2241
2242
|
}).map(({ processed }) => processed).join("\n");
|
|
2242
2243
|
}
|
|
2244
|
+
function extractPreviewFromHighlightedHtml(highlightedHtml) {
|
|
2245
|
+
const preMatch = highlightedHtml.match(/<pre((?:\s+[\w-]+="[^"]*")*)>/);
|
|
2246
|
+
const codeMatch = highlightedHtml.match(/<code([^>]*)>(.*?)<\/code>/s);
|
|
2247
|
+
if (!preMatch || !codeMatch) {
|
|
2248
|
+
return null;
|
|
2249
|
+
}
|
|
2250
|
+
const codeContent = codeMatch[2];
|
|
2251
|
+
const parts = codeContent.split(/<span class="line/);
|
|
2252
|
+
const previewLineParts = parts.slice(1).filter((part) => part.includes('data-preview-line="true"'));
|
|
2253
|
+
const indents = previewLineParts.map((part) => {
|
|
2254
|
+
const indentMatches = part.match(/<span class="indent">(.+?)<\/span>/g) || [];
|
|
2255
|
+
let total = 0;
|
|
2256
|
+
for (const match of indentMatches) {
|
|
2257
|
+
const content = match.match(/<span class="indent">(.+?)<\/span>/);
|
|
2258
|
+
if (content) {
|
|
2259
|
+
total += content[1].length;
|
|
2260
|
+
} else {
|
|
2261
|
+
break;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
return total;
|
|
2265
|
+
});
|
|
2266
|
+
const minIndent = Math.min(...indents.filter((n) => n > 0));
|
|
2267
|
+
const previewLines = previewLineParts.map((part) => {
|
|
2268
|
+
let processed = `<span class="line${part}`;
|
|
2269
|
+
let remaining = minIndent;
|
|
2270
|
+
while (remaining > 0 && processed.includes('<span class="indent">')) {
|
|
2271
|
+
const before = processed;
|
|
2272
|
+
processed = processed.replace(
|
|
2273
|
+
/<span class="indent">(.+?)<\/span>/,
|
|
2274
|
+
(match, spaces) => {
|
|
2275
|
+
if (spaces.length <= remaining) {
|
|
2276
|
+
remaining -= spaces.length;
|
|
2277
|
+
return "";
|
|
2278
|
+
} else {
|
|
2279
|
+
const kept = spaces.substring(remaining);
|
|
2280
|
+
remaining = 0;
|
|
2281
|
+
return `<span class="indent">${kept}</span>`;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
);
|
|
2285
|
+
if (before === processed) {
|
|
2286
|
+
break;
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
return processed;
|
|
2290
|
+
});
|
|
2291
|
+
return `<pre${preMatch[1]}><code${codeMatch[1]}>${previewLines.join("")}</code></pre>`;
|
|
2292
|
+
}
|
|
2243
2293
|
|
|
2244
2294
|
// src/docs-plugin/shiki/shiki-transformer-code-attribute.ts
|
|
2245
2295
|
function transformerCodeAttribute(opts = { attributeName: "data-code" }) {
|
|
@@ -2315,10 +2365,11 @@ function transformerPreviewBlock(options = {
|
|
|
2315
2365
|
},
|
|
2316
2366
|
name: "transformer-preview-block",
|
|
2317
2367
|
pre(node) {
|
|
2318
|
-
|
|
2319
|
-
|
|
2368
|
+
const content = previewContent ? removeCodeAnnotations(previewContent) : null;
|
|
2369
|
+
if (content && options.attributeName != null) {
|
|
2370
|
+
node.properties[options.attributeName] = content;
|
|
2320
2371
|
}
|
|
2321
|
-
options.onComplete?.(
|
|
2372
|
+
options.onComplete?.(content || null);
|
|
2322
2373
|
},
|
|
2323
2374
|
preprocess(code) {
|
|
2324
2375
|
previewContent = null;
|
|
@@ -2412,6 +2463,406 @@ function getRemarkPlugins() {
|
|
|
2412
2463
|
];
|
|
2413
2464
|
}
|
|
2414
2465
|
|
|
2466
|
+
// src/docs-plugin/shiki/internal/shiki-transformer-tailwind.ts
|
|
2467
|
+
import { fromHtml as fromHtml2 } from "hast-util-from-html";
|
|
2468
|
+
import { toHtml } from "hast-util-to-html";
|
|
2469
|
+
import { readFile } from "node:fs/promises";
|
|
2470
|
+
import postcss from "postcss";
|
|
2471
|
+
import selectorParser from "postcss-selector-parser";
|
|
2472
|
+
import { compile } from "tailwindcss";
|
|
2473
|
+
import { visit as visit7 } from "unist-util-visit";
|
|
2474
|
+
import { camelCase } from "@qualcomm-ui/utils/change-case";
|
|
2475
|
+
async function loadStylesheetContent(id) {
|
|
2476
|
+
const resolveId = id === "tailwindcss" ? "tailwindcss/index.css" : id;
|
|
2477
|
+
let resolvedPath;
|
|
2478
|
+
if (typeof createRequire !== "undefined") {
|
|
2479
|
+
resolvedPath = createRequire(import.meta.url).resolve(resolveId);
|
|
2480
|
+
} else {
|
|
2481
|
+
const createRequire2 = await import("node:module").then(
|
|
2482
|
+
(module) => module.createRequire
|
|
2483
|
+
);
|
|
2484
|
+
resolvedPath = createRequire2(import.meta.url).resolve(resolveId);
|
|
2485
|
+
}
|
|
2486
|
+
return readFile(resolvedPath, "utf-8");
|
|
2487
|
+
}
|
|
2488
|
+
async function createCompiler(styles) {
|
|
2489
|
+
return compile(styles, {
|
|
2490
|
+
loadStylesheet: async (id, base) => {
|
|
2491
|
+
const content = await loadStylesheetContent(id);
|
|
2492
|
+
return {
|
|
2493
|
+
base,
|
|
2494
|
+
content,
|
|
2495
|
+
path: `virtual:${id}`
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
function extractCssVariables(css) {
|
|
2501
|
+
const variables = /* @__PURE__ */ new Map();
|
|
2502
|
+
const root = postcss.parse(css);
|
|
2503
|
+
root.walkAtRules("layer", (atRule) => {
|
|
2504
|
+
if (atRule.params !== "theme") {
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
atRule.walkRules(":root, :host", (rule) => {
|
|
2508
|
+
rule.walkDecls((decl) => {
|
|
2509
|
+
if (decl.prop.startsWith("--")) {
|
|
2510
|
+
variables.set(decl.prop, decl.value);
|
|
2511
|
+
}
|
|
2512
|
+
});
|
|
2513
|
+
});
|
|
2514
|
+
});
|
|
2515
|
+
return variables;
|
|
2516
|
+
}
|
|
2517
|
+
function evaluateCalc(expression) {
|
|
2518
|
+
const expr = expression.trim();
|
|
2519
|
+
const withUnitFirst = expr.match(
|
|
2520
|
+
/^([\d.]+)(rem|px|em|%|vh|vw)\s*([*/+-])\s*([\d.]+)$/
|
|
2521
|
+
);
|
|
2522
|
+
if (withUnitFirst) {
|
|
2523
|
+
const [, num1, unit, op, num2] = withUnitFirst;
|
|
2524
|
+
const result = evaluateOperation(parseFloat(num1), op, parseFloat(num2));
|
|
2525
|
+
if (!Number.isFinite(result)) {
|
|
2526
|
+
return null;
|
|
2527
|
+
}
|
|
2528
|
+
return formatNumber(result) + unit;
|
|
2529
|
+
}
|
|
2530
|
+
const withUnitSecond = expr.match(
|
|
2531
|
+
/^([\d.]+)\s*([*/+-])\s*([\d.]+)(rem|px|em|%|vh|vw)$/
|
|
2532
|
+
);
|
|
2533
|
+
if (withUnitSecond) {
|
|
2534
|
+
const [, num1, op, num2, unit] = withUnitSecond;
|
|
2535
|
+
const result = evaluateOperation(parseFloat(num1), op, parseFloat(num2));
|
|
2536
|
+
if (!Number.isFinite(result)) {
|
|
2537
|
+
return null;
|
|
2538
|
+
}
|
|
2539
|
+
return formatNumber(result) + unit;
|
|
2540
|
+
}
|
|
2541
|
+
const unitless = expr.match(/^([\d.]+)\s*([*/+-])\s*([\d.]+)$/);
|
|
2542
|
+
if (unitless) {
|
|
2543
|
+
const [, num1, op, num2] = unitless;
|
|
2544
|
+
const result = evaluateOperation(parseFloat(num1), op, parseFloat(num2));
|
|
2545
|
+
if (!Number.isFinite(result)) {
|
|
2546
|
+
return null;
|
|
2547
|
+
}
|
|
2548
|
+
return formatNumber(result);
|
|
2549
|
+
}
|
|
2550
|
+
return null;
|
|
2551
|
+
}
|
|
2552
|
+
function evaluateOperation(a, op, b) {
|
|
2553
|
+
switch (op) {
|
|
2554
|
+
case "*":
|
|
2555
|
+
return a * b;
|
|
2556
|
+
case "/":
|
|
2557
|
+
return a / b;
|
|
2558
|
+
case "+":
|
|
2559
|
+
return a + b;
|
|
2560
|
+
case "-":
|
|
2561
|
+
return a - b;
|
|
2562
|
+
default:
|
|
2563
|
+
return NaN;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function formatNumber(num) {
|
|
2567
|
+
const rounded = Math.round(num * 1e4) / 1e4;
|
|
2568
|
+
return String(rounded);
|
|
2569
|
+
}
|
|
2570
|
+
function remToPx(value) {
|
|
2571
|
+
return value.replace(/([\d.]+)rem/g, (_, num) => {
|
|
2572
|
+
const px = parseFloat(num) * 16;
|
|
2573
|
+
return `${formatNumber(px)}px`;
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
function findVarEnd(str, start) {
|
|
2577
|
+
let depth = 0;
|
|
2578
|
+
for (let i = start; i < str.length; i++) {
|
|
2579
|
+
if (str[i] === "(") {
|
|
2580
|
+
depth++;
|
|
2581
|
+
} else if (str[i] === ")") {
|
|
2582
|
+
depth--;
|
|
2583
|
+
if (depth === 0) {
|
|
2584
|
+
return i;
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
return -1;
|
|
2589
|
+
}
|
|
2590
|
+
function parseVar(str, startIndex) {
|
|
2591
|
+
const varStart = str.indexOf("var(", startIndex);
|
|
2592
|
+
if (varStart === -1) {
|
|
2593
|
+
return null;
|
|
2594
|
+
}
|
|
2595
|
+
const contentStart = varStart + 4;
|
|
2596
|
+
const end = findVarEnd(str, varStart);
|
|
2597
|
+
if (end === -1) {
|
|
2598
|
+
return null;
|
|
2599
|
+
}
|
|
2600
|
+
const content = str.slice(contentStart, end);
|
|
2601
|
+
let commaIndex = -1;
|
|
2602
|
+
let depth = 0;
|
|
2603
|
+
for (let i = 0; i < content.length; i++) {
|
|
2604
|
+
if (content[i] === "(") {
|
|
2605
|
+
depth++;
|
|
2606
|
+
} else if (content[i] === ")") {
|
|
2607
|
+
depth--;
|
|
2608
|
+
} else if (content[i] === "," && depth === 0) {
|
|
2609
|
+
commaIndex = i;
|
|
2610
|
+
break;
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
if (commaIndex === -1) {
|
|
2614
|
+
return {
|
|
2615
|
+
end,
|
|
2616
|
+
fallback: null,
|
|
2617
|
+
varName: content.trim()
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
return {
|
|
2621
|
+
end,
|
|
2622
|
+
fallback: content.slice(commaIndex + 1).trim(),
|
|
2623
|
+
varName: content.slice(0, commaIndex).trim()
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
function resolveCssValue(value, variables, depth = 0) {
|
|
2627
|
+
if (depth > 10) {
|
|
2628
|
+
return value;
|
|
2629
|
+
}
|
|
2630
|
+
let resolved = value;
|
|
2631
|
+
let searchStart = 0;
|
|
2632
|
+
while (true) {
|
|
2633
|
+
const parsed = parseVar(resolved, searchStart);
|
|
2634
|
+
if (!parsed) {
|
|
2635
|
+
break;
|
|
2636
|
+
}
|
|
2637
|
+
const { end, fallback, varName } = parsed;
|
|
2638
|
+
const varStart = resolved.indexOf("var(", searchStart);
|
|
2639
|
+
let replacement;
|
|
2640
|
+
const varValue = variables.get(varName);
|
|
2641
|
+
if (varValue !== void 0) {
|
|
2642
|
+
replacement = resolveCssValue(varValue, variables, depth + 1);
|
|
2643
|
+
} else if (fallback) {
|
|
2644
|
+
replacement = resolveCssValue(fallback, variables, depth + 1);
|
|
2645
|
+
} else {
|
|
2646
|
+
searchStart = end + 1;
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
resolved = resolved.slice(0, varStart) + replacement + resolved.slice(end + 1);
|
|
2650
|
+
}
|
|
2651
|
+
resolved = resolved.replace(
|
|
2652
|
+
/calc\(([^)]+)\)/g,
|
|
2653
|
+
(match, expression) => {
|
|
2654
|
+
const evaluated = evaluateCalc(expression);
|
|
2655
|
+
return evaluated ?? match;
|
|
2656
|
+
}
|
|
2657
|
+
);
|
|
2658
|
+
resolved = remToPx(resolved);
|
|
2659
|
+
return resolved;
|
|
2660
|
+
}
|
|
2661
|
+
function analyzeSelector(selector) {
|
|
2662
|
+
let inlineable = true;
|
|
2663
|
+
let className = null;
|
|
2664
|
+
const processor = selectorParser((selectors) => {
|
|
2665
|
+
if (selectors.nodes.length !== 1) {
|
|
2666
|
+
inlineable = false;
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
const selectorNode = selectors.nodes[0];
|
|
2670
|
+
if (selectorNode.nodes.length !== 1) {
|
|
2671
|
+
inlineable = false;
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
const node = selectorNode.nodes[0];
|
|
2675
|
+
if (node.type !== "class") {
|
|
2676
|
+
inlineable = false;
|
|
2677
|
+
return;
|
|
2678
|
+
}
|
|
2679
|
+
className = node.value;
|
|
2680
|
+
selectorNode.walk((n) => {
|
|
2681
|
+
if (n.type === "pseudo" || n.type === "combinator" || n.type === "nesting" || n.type === "attribute") {
|
|
2682
|
+
inlineable = false;
|
|
2683
|
+
}
|
|
2684
|
+
});
|
|
2685
|
+
});
|
|
2686
|
+
processor.processSync(selector);
|
|
2687
|
+
return { className, inlineable };
|
|
2688
|
+
}
|
|
2689
|
+
function parseCompiledCss(css) {
|
|
2690
|
+
const rules = [];
|
|
2691
|
+
const root = postcss.parse(css);
|
|
2692
|
+
const variables = extractCssVariables(css);
|
|
2693
|
+
function processRule(rule, insideAtRule) {
|
|
2694
|
+
const { className, inlineable } = analyzeSelector(rule.selector);
|
|
2695
|
+
if (!className) {
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
let hasNestedAtRule = false;
|
|
2699
|
+
rule.walkAtRules(() => {
|
|
2700
|
+
hasNestedAtRule = true;
|
|
2701
|
+
});
|
|
2702
|
+
const declarations = [];
|
|
2703
|
+
rule.each((node) => {
|
|
2704
|
+
if (node.type === "decl") {
|
|
2705
|
+
const resolvedValue = resolveCssValue(node.value, variables);
|
|
2706
|
+
declarations.push(`${node.prop}: ${resolvedValue}`);
|
|
2707
|
+
}
|
|
2708
|
+
});
|
|
2709
|
+
if (declarations.length === 0 && !hasNestedAtRule) {
|
|
2710
|
+
return;
|
|
2711
|
+
}
|
|
2712
|
+
rules.push({
|
|
2713
|
+
className,
|
|
2714
|
+
declarations: declarations.join("; "),
|
|
2715
|
+
inlineable: inlineable && !insideAtRule && !hasNestedAtRule,
|
|
2716
|
+
originalRule: rule.toString()
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
root.walkAtRules("layer", (atRule) => {
|
|
2720
|
+
atRule.walkRules((rule) => {
|
|
2721
|
+
const parent = rule.parent;
|
|
2722
|
+
const insideNestedAtRule = parent?.type === "atrule" && parent.name !== "layer";
|
|
2723
|
+
processRule(rule, insideNestedAtRule);
|
|
2724
|
+
});
|
|
2725
|
+
atRule.walkAtRules((nested) => {
|
|
2726
|
+
if (nested.name !== "layer") {
|
|
2727
|
+
nested.walkRules((rule) => {
|
|
2728
|
+
processRule(rule, true);
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
});
|
|
2732
|
+
});
|
|
2733
|
+
root.walkRules((rule) => {
|
|
2734
|
+
if (rule.parent?.type === "root") {
|
|
2735
|
+
processRule(rule, false);
|
|
2736
|
+
}
|
|
2737
|
+
});
|
|
2738
|
+
return rules;
|
|
2739
|
+
}
|
|
2740
|
+
function compileClasses(classes, compiler) {
|
|
2741
|
+
const compiledCss = compiler.build(classes);
|
|
2742
|
+
const parsedRules = parseCompiledCss(compiledCss);
|
|
2743
|
+
const inlineableStyles = /* @__PURE__ */ new Map();
|
|
2744
|
+
const residualRules = /* @__PURE__ */ new Map();
|
|
2745
|
+
for (const rule of parsedRules) {
|
|
2746
|
+
if (rule.inlineable) {
|
|
2747
|
+
inlineableStyles.set(rule.className, rule.declarations);
|
|
2748
|
+
} else {
|
|
2749
|
+
residualRules.set(rule.className, rule.originalRule);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
const inlineStyles = [];
|
|
2753
|
+
const remainingClasses = [];
|
|
2754
|
+
for (const cls of classes) {
|
|
2755
|
+
const style = inlineableStyles.get(cls);
|
|
2756
|
+
if (style) {
|
|
2757
|
+
inlineStyles.push(style);
|
|
2758
|
+
} else {
|
|
2759
|
+
remainingClasses.push(cls);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
return { inlineStyles, remainingClasses, residualRules };
|
|
2763
|
+
}
|
|
2764
|
+
function cssToJsxObject(cssDeclarations) {
|
|
2765
|
+
const props = cssDeclarations.flatMap((decl) => {
|
|
2766
|
+
return decl.split(";").map((d) => d.trim()).filter(Boolean);
|
|
2767
|
+
}).map((declaration) => {
|
|
2768
|
+
const colonIndex = declaration.indexOf(":");
|
|
2769
|
+
if (colonIndex === -1) {
|
|
2770
|
+
return null;
|
|
2771
|
+
}
|
|
2772
|
+
const prop = declaration.slice(0, colonIndex).trim();
|
|
2773
|
+
const value = declaration.slice(colonIndex + 1).trim();
|
|
2774
|
+
const camelProp = camelCase(prop);
|
|
2775
|
+
return `${camelProp}: '${value}'`;
|
|
2776
|
+
}).filter(Boolean);
|
|
2777
|
+
return `{ ${props.join(", ")} }`;
|
|
2778
|
+
}
|
|
2779
|
+
function computeLineReplacements(lineText, compiler, styleFormat = "html") {
|
|
2780
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
2781
|
+
const allResidualRules = /* @__PURE__ */ new Map();
|
|
2782
|
+
const classAttrPattern = /(className|class)=(["'`])([^"'`]*)\2/g;
|
|
2783
|
+
let match;
|
|
2784
|
+
while ((match = classAttrPattern.exec(lineText)) !== null) {
|
|
2785
|
+
const fullMatch = match[0];
|
|
2786
|
+
const attrName = match[1];
|
|
2787
|
+
const quote = match[2];
|
|
2788
|
+
const classValue = match[3];
|
|
2789
|
+
const classes = classValue.split(/\s+/).filter(Boolean);
|
|
2790
|
+
if (classes.length === 0) {
|
|
2791
|
+
continue;
|
|
2792
|
+
}
|
|
2793
|
+
const { inlineStyles, remainingClasses, residualRules } = compileClasses(
|
|
2794
|
+
classes,
|
|
2795
|
+
compiler
|
|
2796
|
+
);
|
|
2797
|
+
for (const [className, rule] of residualRules) {
|
|
2798
|
+
allResidualRules.set(className, rule);
|
|
2799
|
+
}
|
|
2800
|
+
if (inlineStyles.length === 0) {
|
|
2801
|
+
continue;
|
|
2802
|
+
}
|
|
2803
|
+
let replacement;
|
|
2804
|
+
if (styleFormat === "jsx") {
|
|
2805
|
+
const jsxStyleObj = cssToJsxObject(inlineStyles);
|
|
2806
|
+
replacement = `style={${jsxStyleObj}}`;
|
|
2807
|
+
} else {
|
|
2808
|
+
replacement = `style=${quote}${inlineStyles.join("; ")}${quote}`;
|
|
2809
|
+
}
|
|
2810
|
+
if (remainingClasses.length > 0) {
|
|
2811
|
+
replacement += ` ${attrName}=${quote}${remainingClasses.join(" ")}${quote}`;
|
|
2812
|
+
}
|
|
2813
|
+
replacements.set(fullMatch, replacement);
|
|
2814
|
+
}
|
|
2815
|
+
return { replacements, residualRules: allResidualRules };
|
|
2816
|
+
}
|
|
2817
|
+
function transformSourceCode(source, compiler, styleFormat = "html") {
|
|
2818
|
+
const allResidualRules = /* @__PURE__ */ new Map();
|
|
2819
|
+
let classesDetected = false;
|
|
2820
|
+
const { replacements, residualRules } = computeLineReplacements(
|
|
2821
|
+
source,
|
|
2822
|
+
compiler,
|
|
2823
|
+
styleFormat
|
|
2824
|
+
);
|
|
2825
|
+
if (replacements.size > 0 || residualRules.size > 0) {
|
|
2826
|
+
classesDetected = true;
|
|
2827
|
+
}
|
|
2828
|
+
for (const [cls, rule] of residualRules) {
|
|
2829
|
+
allResidualRules.set(cls, rule);
|
|
2830
|
+
}
|
|
2831
|
+
let transformed = source;
|
|
2832
|
+
for (const [original, replacement] of replacements) {
|
|
2833
|
+
transformed = transformed.replaceAll(original, replacement);
|
|
2834
|
+
}
|
|
2835
|
+
return {
|
|
2836
|
+
classesDetected,
|
|
2837
|
+
residualRules: allResidualRules,
|
|
2838
|
+
source: transformed
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2841
|
+
async function createShikiTailwindTransformer(options) {
|
|
2842
|
+
const {
|
|
2843
|
+
onClassesDetected,
|
|
2844
|
+
onResidualCss,
|
|
2845
|
+
styleFormat = "html",
|
|
2846
|
+
styles
|
|
2847
|
+
} = options;
|
|
2848
|
+
const compiler = await createCompiler(styles);
|
|
2849
|
+
return {
|
|
2850
|
+
name: "shiki-transformer-tailwind-to-inline",
|
|
2851
|
+
preprocess(code) {
|
|
2852
|
+
const { classesDetected, residualRules, source } = transformSourceCode(
|
|
2853
|
+
code,
|
|
2854
|
+
compiler,
|
|
2855
|
+
styleFormat
|
|
2856
|
+
);
|
|
2857
|
+
onClassesDetected?.(classesDetected);
|
|
2858
|
+
if (onResidualCss && residualRules.size > 0) {
|
|
2859
|
+
onResidualCss(residualRules);
|
|
2860
|
+
}
|
|
2861
|
+
return source;
|
|
2862
|
+
}
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2415
2866
|
// src/angular-demo-plugin/angular-demo-plugin.ts
|
|
2416
2867
|
var VIRTUAL_MODULE_ID2 = "\0virtual:angular-demo-registry";
|
|
2417
2868
|
var LOG_PREFIX = "[angular-demo]";
|
|
@@ -2434,7 +2885,8 @@ function angularDemoPlugin({
|
|
|
2434
2885
|
theme = {
|
|
2435
2886
|
dark: quiCustomDarkTheme2,
|
|
2436
2887
|
light: "github-light-high-contrast"
|
|
2437
|
-
}
|
|
2888
|
+
},
|
|
2889
|
+
transformTailwindStyles
|
|
2438
2890
|
} = {}) {
|
|
2439
2891
|
let watcher = null;
|
|
2440
2892
|
let devServer = null;
|
|
@@ -2461,7 +2913,7 @@ function angularDemoPlugin({
|
|
|
2461
2913
|
if (!highlighter) {
|
|
2462
2914
|
try {
|
|
2463
2915
|
highlighter = await createHighlighter({
|
|
2464
|
-
langs: ["angular-ts", "angular-html"],
|
|
2916
|
+
langs: ["angular-ts", "angular-html", "css"],
|
|
2465
2917
|
themes: [theme.dark, theme.light]
|
|
2466
2918
|
});
|
|
2467
2919
|
logDev(`${chalk4.blue.bold(LOG_PREFIX)} Shiki highlighter initialized`);
|
|
@@ -2539,7 +2991,7 @@ function angularDemoPlugin({
|
|
|
2539
2991
|
logDev(
|
|
2540
2992
|
`${chalk4.blue.bold(LOG_PREFIX)} Processing Angular demo change: ${chalk4.cyan(file)}`
|
|
2541
2993
|
);
|
|
2542
|
-
const code = await
|
|
2994
|
+
const code = await readFile2(file, "utf-8");
|
|
2543
2995
|
const demoInfo = await parseAngularDemo(file, code);
|
|
2544
2996
|
if (!demoInfo || !isAngularDemoEntrypoint(file)) {
|
|
2545
2997
|
const affectedDemos = await scanDemosForFileImport(file);
|
|
@@ -2605,7 +3057,7 @@ function angularDemoPlugin({
|
|
|
2605
3057
|
const demoFiles = await glob2(demoPattern);
|
|
2606
3058
|
demoRegistry.clear();
|
|
2607
3059
|
for (const filePath of demoFiles) {
|
|
2608
|
-
const code = await
|
|
3060
|
+
const code = await readFile2(filePath, "utf-8");
|
|
2609
3061
|
const demoInfo = await parseAngularDemo(filePath, code);
|
|
2610
3062
|
if (demoInfo) {
|
|
2611
3063
|
demoRegistry.set(demoInfo.id, demoInfo);
|
|
@@ -2619,7 +3071,7 @@ function angularDemoPlugin({
|
|
|
2619
3071
|
logDev(
|
|
2620
3072
|
`${chalk4.blue.bold(LOG_PREFIX)} Reloading demo ${chalk4.cyan(demoId)} due to imported file change: ${chalk4.yellow(file)}`
|
|
2621
3073
|
);
|
|
2622
|
-
const code = await
|
|
3074
|
+
const code = await readFile2(demo.filePath, "utf-8");
|
|
2623
3075
|
const updatedDemo = await parseAngularDemo(demo.filePath, code);
|
|
2624
3076
|
if (updatedDemo) {
|
|
2625
3077
|
delete demoDimensionsCache[updatedDemo.id];
|
|
@@ -2631,29 +3083,44 @@ function angularDemoPlugin({
|
|
|
2631
3083
|
}
|
|
2632
3084
|
return affectedDemos;
|
|
2633
3085
|
}
|
|
2634
|
-
async function highlightCode(code, language = "angular-ts") {
|
|
3086
|
+
async function highlightCode(code, language = "angular-ts", options = {}) {
|
|
3087
|
+
const { onClassesDetected, onResidualCss } = options;
|
|
2635
3088
|
if (!highlighter) {
|
|
2636
|
-
return {
|
|
3089
|
+
return { full: code };
|
|
2637
3090
|
}
|
|
2638
3091
|
let previewCode = null;
|
|
2639
|
-
|
|
3092
|
+
const tailwindTransformers = [];
|
|
3093
|
+
if (transformTailwindStyles && onResidualCss) {
|
|
3094
|
+
const transformer = await createShikiTailwindTransformer({
|
|
3095
|
+
onClassesDetected: (detected) => {
|
|
3096
|
+
onClassesDetected?.(detected);
|
|
3097
|
+
},
|
|
3098
|
+
onResidualCss,
|
|
3099
|
+
styleFormat: "html",
|
|
3100
|
+
styles: dedent2`
|
|
3101
|
+
@layer theme, base, components, utilities;
|
|
3102
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
3103
|
+
@import "tailwindcss/utilities.css" layer(utilities);
|
|
3104
|
+
@import "@qualcomm-ui/tailwind-plugin/qui-strict.css";
|
|
3105
|
+
`
|
|
3106
|
+
});
|
|
3107
|
+
tailwindTransformers.push(transformer);
|
|
3108
|
+
}
|
|
2640
3109
|
try {
|
|
2641
3110
|
const highlightedCode = highlighter.codeToHtml(code, {
|
|
2642
3111
|
...defaultShikiOptions,
|
|
2643
3112
|
lang: language,
|
|
2644
3113
|
transformers: [
|
|
2645
3114
|
...getShikiTransformers(),
|
|
3115
|
+
...tailwindTransformers,
|
|
2646
3116
|
transformerPreviewBlock({
|
|
2647
|
-
attributeName:
|
|
3117
|
+
attributeName: "data-preview",
|
|
2648
3118
|
onComplete: (extractedPreview) => {
|
|
2649
|
-
previewCode = extractedPreview
|
|
3119
|
+
previewCode = extractedPreview;
|
|
2650
3120
|
}
|
|
2651
3121
|
}),
|
|
2652
3122
|
transformerCodeAttribute({
|
|
2653
|
-
attributeName:
|
|
2654
|
-
onComplete: (formattedSource) => {
|
|
2655
|
-
codeWithoutSnippets = formattedSource;
|
|
2656
|
-
}
|
|
3123
|
+
attributeName: "data-code"
|
|
2657
3124
|
}),
|
|
2658
3125
|
{
|
|
2659
3126
|
enforce: "post",
|
|
@@ -2665,22 +3132,20 @@ function angularDemoPlugin({
|
|
|
2665
3132
|
]
|
|
2666
3133
|
});
|
|
2667
3134
|
return {
|
|
2668
|
-
|
|
2669
|
-
highlightedCode
|
|
2670
|
-
highlightedPreview: previewCode ? extractPreviewFromHighlightedHtml(highlightedCode) : null,
|
|
2671
|
-
previewCodeWithoutSnippets: previewCode
|
|
3135
|
+
full: highlightedCode,
|
|
3136
|
+
preview: previewCode ? extractPreviewFromHighlightedHtml(highlightedCode) : null
|
|
2672
3137
|
};
|
|
2673
3138
|
} catch (error) {
|
|
2674
3139
|
console.warn(
|
|
2675
3140
|
`${chalk4.blue.bold(LOG_PREFIX)} Failed to highlight code with ${language} language:`,
|
|
2676
3141
|
error
|
|
2677
3142
|
);
|
|
2678
|
-
return {
|
|
3143
|
+
return { full: code };
|
|
2679
3144
|
}
|
|
2680
3145
|
}
|
|
2681
3146
|
async function extractRelativeImports(filePath) {
|
|
2682
3147
|
try {
|
|
2683
|
-
let
|
|
3148
|
+
let visit9 = function(node) {
|
|
2684
3149
|
if (ts.isImportDeclaration(node)) {
|
|
2685
3150
|
const moduleSpecifier = node.moduleSpecifier;
|
|
2686
3151
|
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
@@ -2699,10 +3164,10 @@ function angularDemoPlugin({
|
|
|
2699
3164
|
}
|
|
2700
3165
|
}
|
|
2701
3166
|
}
|
|
2702
|
-
ts.forEachChild(node,
|
|
3167
|
+
ts.forEachChild(node, visit9);
|
|
2703
3168
|
};
|
|
2704
|
-
var
|
|
2705
|
-
const content = await
|
|
3169
|
+
var visit8 = visit9;
|
|
3170
|
+
const content = await readFile2(filePath, "utf-8");
|
|
2706
3171
|
const sourceFile = ts.createSourceFile(
|
|
2707
3172
|
filePath,
|
|
2708
3173
|
content,
|
|
@@ -2711,7 +3176,7 @@ function angularDemoPlugin({
|
|
|
2711
3176
|
ts.ScriptKind.TS
|
|
2712
3177
|
);
|
|
2713
3178
|
const relativeImports = [];
|
|
2714
|
-
|
|
3179
|
+
visit9(sourceFile);
|
|
2715
3180
|
return relativeImports;
|
|
2716
3181
|
} catch (error) {
|
|
2717
3182
|
logDev(
|
|
@@ -2734,16 +3199,16 @@ function angularDemoPlugin({
|
|
|
2734
3199
|
}
|
|
2735
3200
|
function stripImports(code, fileName) {
|
|
2736
3201
|
try {
|
|
2737
|
-
let
|
|
3202
|
+
let visit9 = function(node) {
|
|
2738
3203
|
if (ts.isImportDeclaration(node)) {
|
|
2739
3204
|
importRanges.push({
|
|
2740
3205
|
end: node.getEnd(),
|
|
2741
3206
|
start: node.getFullStart()
|
|
2742
3207
|
});
|
|
2743
3208
|
}
|
|
2744
|
-
ts.forEachChild(node,
|
|
3209
|
+
ts.forEachChild(node, visit9);
|
|
2745
3210
|
};
|
|
2746
|
-
var
|
|
3211
|
+
var visit8 = visit9;
|
|
2747
3212
|
const sourceFile = ts.createSourceFile(
|
|
2748
3213
|
fileName,
|
|
2749
3214
|
code,
|
|
@@ -2752,7 +3217,7 @@ function angularDemoPlugin({
|
|
|
2752
3217
|
ts.ScriptKind.TS
|
|
2753
3218
|
);
|
|
2754
3219
|
const importRanges = [];
|
|
2755
|
-
|
|
3220
|
+
visit9(sourceFile);
|
|
2756
3221
|
return importRanges.map((range) => {
|
|
2757
3222
|
let endPos = range.end;
|
|
2758
3223
|
if (code[endPos] === "\n") {
|
|
@@ -2785,24 +3250,51 @@ function angularDemoPlugin({
|
|
|
2785
3250
|
const fileName = basename(filePath);
|
|
2786
3251
|
const importsWithoutStrip = stripImports(code, filePath);
|
|
2787
3252
|
const sourceCode = [];
|
|
3253
|
+
const aggregatedRules = /* @__PURE__ */ new Map();
|
|
2788
3254
|
const mainSourceEntry = await buildAngularSourceEntry({
|
|
2789
3255
|
code,
|
|
2790
3256
|
fileName,
|
|
2791
3257
|
filePath,
|
|
2792
3258
|
language: "angular-ts"
|
|
2793
3259
|
});
|
|
2794
|
-
sourceCode.push(mainSourceEntry);
|
|
3260
|
+
sourceCode.push(mainSourceEntry.sourceCodeData);
|
|
3261
|
+
if (mainSourceEntry.residualRules) {
|
|
3262
|
+
for (const [className, rule] of mainSourceEntry.residualRules) {
|
|
3263
|
+
aggregatedRules.set(className, rule);
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
2795
3266
|
if (templateUrl) {
|
|
2796
3267
|
const templateEntry = await maybeBuildTemplateSourceEntry(
|
|
2797
3268
|
templateUrl,
|
|
2798
3269
|
filePath
|
|
2799
3270
|
);
|
|
2800
3271
|
if (templateEntry) {
|
|
2801
|
-
sourceCode.push(templateEntry);
|
|
3272
|
+
sourceCode.push(templateEntry.sourceCodeData);
|
|
3273
|
+
if (templateEntry.residualRules) {
|
|
3274
|
+
for (const [className, rule] of templateEntry.residualRules) {
|
|
3275
|
+
aggregatedRules.set(className, rule);
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
2802
3278
|
}
|
|
2803
3279
|
}
|
|
2804
3280
|
const importedEntries = await buildImportedSourceEntries(filePath);
|
|
2805
|
-
|
|
3281
|
+
for (const entry of importedEntries) {
|
|
3282
|
+
sourceCode.push(entry.sourceCodeData);
|
|
3283
|
+
if (entry.residualRules) {
|
|
3284
|
+
for (const [className, rule] of entry.residualRules) {
|
|
3285
|
+
aggregatedRules.set(className, rule);
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
const aggregatedResidualCss = aggregatedRules.size > 0 ? [...aggregatedRules.values()].join("\n\n") : void 0;
|
|
3290
|
+
if (aggregatedResidualCss) {
|
|
3291
|
+
const cssHighlighted = await highlightCode(aggregatedResidualCss, "css");
|
|
3292
|
+
sourceCode.push({
|
|
3293
|
+
fileName: "styles.css",
|
|
3294
|
+
highlighted: cssHighlighted,
|
|
3295
|
+
type: "residual-css"
|
|
3296
|
+
});
|
|
3297
|
+
}
|
|
2806
3298
|
return {
|
|
2807
3299
|
componentClass,
|
|
2808
3300
|
filePath: importPath.startsWith(".") ? importPath : `./${importPath}`,
|
|
@@ -2837,7 +3329,7 @@ function angularDemoPlugin({
|
|
|
2837
3329
|
let templateUrl = null;
|
|
2838
3330
|
let hasDefaultExport = false;
|
|
2839
3331
|
const importsFromAst = [];
|
|
2840
|
-
function
|
|
3332
|
+
function visit8(node) {
|
|
2841
3333
|
if (ts.isImportDeclaration(node)) {
|
|
2842
3334
|
importsFromAst.push(node.getFullText(sourceFile).trim());
|
|
2843
3335
|
}
|
|
@@ -2885,9 +3377,9 @@ function angularDemoPlugin({
|
|
|
2885
3377
|
if (ts.isExportAssignment(node) && !node.isExportEquals) {
|
|
2886
3378
|
hasDefaultExport = true;
|
|
2887
3379
|
}
|
|
2888
|
-
ts.forEachChild(node,
|
|
3380
|
+
ts.forEachChild(node, visit8);
|
|
2889
3381
|
}
|
|
2890
|
-
|
|
3382
|
+
visit8(sourceFile);
|
|
2891
3383
|
return {
|
|
2892
3384
|
componentClass,
|
|
2893
3385
|
hasDefaultExport,
|
|
@@ -2899,24 +3391,34 @@ function angularDemoPlugin({
|
|
|
2899
3391
|
}
|
|
2900
3392
|
async function buildAngularSourceEntry(params) {
|
|
2901
3393
|
const { code, fileName, filePath, language } = params;
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3394
|
+
const baseResult = await highlightCode(code, language);
|
|
3395
|
+
let inlineResult;
|
|
3396
|
+
let classesDetected = false;
|
|
3397
|
+
let residualRules;
|
|
3398
|
+
if (transformTailwindStyles) {
|
|
3399
|
+
inlineResult = await highlightCode(code, language, {
|
|
3400
|
+
onClassesDetected: (detected) => {
|
|
3401
|
+
classesDetected = detected;
|
|
3402
|
+
},
|
|
3403
|
+
onResidualCss: (rules) => {
|
|
3404
|
+
residualRules = rules;
|
|
3405
|
+
}
|
|
3406
|
+
});
|
|
3407
|
+
}
|
|
2910
3408
|
return {
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
3409
|
+
residualRules,
|
|
3410
|
+
sourceCodeData: {
|
|
3411
|
+
fileName,
|
|
3412
|
+
filePath,
|
|
3413
|
+
highlighted: {
|
|
3414
|
+
full: baseResult.full,
|
|
3415
|
+
preview: baseResult.preview
|
|
3416
|
+
},
|
|
3417
|
+
highlightedInline: classesDetected && inlineResult ? {
|
|
3418
|
+
full: inlineResult.full,
|
|
3419
|
+
preview: inlineResult.preview
|
|
3420
|
+
} : void 0,
|
|
3421
|
+
type: "file"
|
|
2920
3422
|
}
|
|
2921
3423
|
};
|
|
2922
3424
|
}
|
|
@@ -2926,7 +3428,7 @@ function angularDemoPlugin({
|
|
|
2926
3428
|
return null;
|
|
2927
3429
|
}
|
|
2928
3430
|
try {
|
|
2929
|
-
const templateCode = await
|
|
3431
|
+
const templateCode = await readFile2(templatePath, "utf-8");
|
|
2930
3432
|
return buildAngularSourceEntry({
|
|
2931
3433
|
code: templateCode,
|
|
2932
3434
|
fileName: basename(templatePath),
|
|
@@ -2942,25 +3444,25 @@ function angularDemoPlugin({
|
|
|
2942
3444
|
}
|
|
2943
3445
|
}
|
|
2944
3446
|
async function buildImportedSourceEntries(fromFilePath) {
|
|
2945
|
-
const
|
|
3447
|
+
const entries = [];
|
|
2946
3448
|
const relativeImports = await collectAllImports(fromFilePath);
|
|
2947
3449
|
for (const resolvedPath of relativeImports) {
|
|
2948
3450
|
try {
|
|
2949
|
-
const importedCode = await
|
|
3451
|
+
const importedCode = await readFile2(resolvedPath, "utf-8");
|
|
2950
3452
|
const entry = await buildAngularSourceEntry({
|
|
2951
3453
|
code: importedCode,
|
|
2952
3454
|
fileName: basename(resolvedPath),
|
|
2953
3455
|
filePath: resolvedPath,
|
|
2954
3456
|
language: "angular-ts"
|
|
2955
3457
|
});
|
|
2956
|
-
|
|
3458
|
+
entries.push(entry);
|
|
2957
3459
|
} catch (error) {
|
|
2958
3460
|
logDev(
|
|
2959
3461
|
`${chalk4.blue.bold(LOG_PREFIX)} ${chalk4.yellowBright("Failed to process relative import:")} ${chalk4.cyan(resolvedPath)}`
|
|
2960
3462
|
);
|
|
2961
3463
|
}
|
|
2962
3464
|
}
|
|
2963
|
-
return
|
|
3465
|
+
return entries;
|
|
2964
3466
|
}
|
|
2965
3467
|
function generateRegistryModule() {
|
|
2966
3468
|
const demos = Array.from(demoRegistry.values());
|
|
@@ -3039,7 +3541,7 @@ export function getAngularDemoInfo(demoId) {
|
|
|
3039
3541
|
function resolveRelativeImport2(source, fromFile) {
|
|
3040
3542
|
const fromDir = dirname(fromFile);
|
|
3041
3543
|
const resolved = resolve2(fromDir, source);
|
|
3042
|
-
const extensions = [".ts", ".
|
|
3544
|
+
const extensions = [".ts", ".js"];
|
|
3043
3545
|
for (const ext of extensions) {
|
|
3044
3546
|
const withExt = resolved + ext;
|
|
3045
3547
|
if (existsSync(withExt)) {
|
|
@@ -3149,7 +3651,7 @@ export function getAngularDemoInfo(demoId) {
|
|
|
3149
3651
|
});
|
|
3150
3652
|
}
|
|
3151
3653
|
async function handleAngularDemoUpdate(filePath) {
|
|
3152
|
-
const code = await
|
|
3654
|
+
const code = await readFile2(filePath, "utf-8");
|
|
3153
3655
|
const demoInfo = await parseAngularDemo(filePath, code);
|
|
3154
3656
|
if (demoInfo) {
|
|
3155
3657
|
demoRegistry.set(demoInfo.id, demoInfo);
|
|
@@ -3223,7 +3725,7 @@ function resolvePathAlias(source, pathAliases) {
|
|
|
3223
3725
|
for (const alias of pathAliases) {
|
|
3224
3726
|
if (alias.pattern.test(source)) {
|
|
3225
3727
|
const resolvedPath = source.replace(alias.pattern, alias.replacement);
|
|
3226
|
-
const extensions = [".ts", ".
|
|
3728
|
+
const extensions = [".ts", ".js"];
|
|
3227
3729
|
for (const ext of extensions) {
|
|
3228
3730
|
const withExt = resolvedPath + ext;
|
|
3229
3731
|
if (existsSync(withExt)) {
|
|
@@ -3255,55 +3757,6 @@ function resolveTemplateFile(templateUrl, fromFile) {
|
|
|
3255
3757
|
}
|
|
3256
3758
|
return resolved;
|
|
3257
3759
|
}
|
|
3258
|
-
function extractPreviewFromHighlightedHtml(highlightedHtml) {
|
|
3259
|
-
const preMatch = highlightedHtml.match(/<pre([^>]*)>/);
|
|
3260
|
-
const codeMatch = highlightedHtml.match(/<code([^>]*)>(.*?)<\/code>/s);
|
|
3261
|
-
if (!preMatch || !codeMatch) {
|
|
3262
|
-
return null;
|
|
3263
|
-
}
|
|
3264
|
-
const codeContent = codeMatch[2];
|
|
3265
|
-
const parts = codeContent.split(/<span class="line/);
|
|
3266
|
-
const previewLineParts = parts.slice(1).filter((part) => part.includes('data-preview-line="true"'));
|
|
3267
|
-
const indents = previewLineParts.map((part) => {
|
|
3268
|
-
const indentMatches = part.match(/<span class="indent">(.+?)<\/span>/g) || [];
|
|
3269
|
-
let total = 0;
|
|
3270
|
-
for (const match of indentMatches) {
|
|
3271
|
-
const content = match.match(/<span class="indent">(.+?)<\/span>/);
|
|
3272
|
-
if (content) {
|
|
3273
|
-
total += content[1].length;
|
|
3274
|
-
} else {
|
|
3275
|
-
break;
|
|
3276
|
-
}
|
|
3277
|
-
}
|
|
3278
|
-
return total;
|
|
3279
|
-
});
|
|
3280
|
-
const minIndent = Math.min(...indents.filter((n) => n > 0));
|
|
3281
|
-
const previewLines = previewLineParts.map((part) => {
|
|
3282
|
-
let processed = `<span class="line${part}`;
|
|
3283
|
-
let remaining = minIndent;
|
|
3284
|
-
while (remaining > 0 && processed.includes('<span class="indent">')) {
|
|
3285
|
-
const before = processed;
|
|
3286
|
-
processed = processed.replace(
|
|
3287
|
-
/<span class="indent">(.+?)<\/span>/,
|
|
3288
|
-
(match, spaces) => {
|
|
3289
|
-
if (spaces.length <= remaining) {
|
|
3290
|
-
remaining -= spaces.length;
|
|
3291
|
-
return "";
|
|
3292
|
-
} else {
|
|
3293
|
-
const kept = spaces.substring(remaining);
|
|
3294
|
-
remaining = 0;
|
|
3295
|
-
return `<span class="indent">${kept}</span>`;
|
|
3296
|
-
}
|
|
3297
|
-
}
|
|
3298
|
-
);
|
|
3299
|
-
if (before === processed) {
|
|
3300
|
-
break;
|
|
3301
|
-
}
|
|
3302
|
-
}
|
|
3303
|
-
return processed;
|
|
3304
|
-
});
|
|
3305
|
-
return `<pre${preMatch[1]}><code${codeMatch[1]}>${previewLines.join("")}</code></pre>`;
|
|
3306
|
-
}
|
|
3307
3760
|
|
|
3308
3761
|
// src/react-demo-plugin/demo-plugin-constants.ts
|
|
3309
3762
|
var VIRTUAL_MODULE_IDS = {
|
|
@@ -3341,7 +3794,7 @@ var NODE_BUILTINS = [
|
|
|
3341
3794
|
// src/react-demo-plugin/demo-plugin-utils.ts
|
|
3342
3795
|
import chalk5 from "chalk";
|
|
3343
3796
|
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
3344
|
-
import { readFile as
|
|
3797
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
3345
3798
|
import { dirname as dirname2, join as join3, relative as relative2, resolve as resolve3, sep } from "node:path";
|
|
3346
3799
|
import * as ts2 from "typescript";
|
|
3347
3800
|
import { pascalCase } from "@qualcomm-ui/utils/change-case";
|
|
@@ -3358,7 +3811,7 @@ function createDemoName(filePath) {
|
|
|
3358
3811
|
}
|
|
3359
3812
|
async function extractFileImports(filePath) {
|
|
3360
3813
|
try {
|
|
3361
|
-
const content = await
|
|
3814
|
+
const content = await readFile3(filePath, "utf-8");
|
|
3362
3815
|
return extractImports(content, filePath);
|
|
3363
3816
|
} catch (error) {
|
|
3364
3817
|
console.log(
|
|
@@ -3378,7 +3831,7 @@ function extractImports(code, fileName) {
|
|
|
3378
3831
|
);
|
|
3379
3832
|
const thirdPartyImports = [];
|
|
3380
3833
|
const relativeImports = [];
|
|
3381
|
-
function
|
|
3834
|
+
function visit8(node) {
|
|
3382
3835
|
if (ts2.isImportDeclaration(node)) {
|
|
3383
3836
|
const importSpec = parseImportDeclaration(node, fileName);
|
|
3384
3837
|
if (importSpec) {
|
|
@@ -3389,9 +3842,9 @@ function extractImports(code, fileName) {
|
|
|
3389
3842
|
}
|
|
3390
3843
|
}
|
|
3391
3844
|
}
|
|
3392
|
-
ts2.forEachChild(node,
|
|
3845
|
+
ts2.forEachChild(node, visit8);
|
|
3393
3846
|
}
|
|
3394
|
-
|
|
3847
|
+
visit8(sourceFile);
|
|
3395
3848
|
return { relativeImports, thirdPartyImports };
|
|
3396
3849
|
}
|
|
3397
3850
|
function getScriptKind(fileName) {
|
|
@@ -3638,14 +4091,14 @@ function isDemoFile(filePath) {
|
|
|
3638
4091
|
// src/react-demo-plugin/react-demo-plugin.ts
|
|
3639
4092
|
import chalk6 from "chalk";
|
|
3640
4093
|
import { glob as glob3 } from "glob";
|
|
3641
|
-
import { readFile as
|
|
4094
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
3642
4095
|
import { basename as basename2, resolve as resolve4 } from "node:path";
|
|
3643
4096
|
import { createHighlighter as createHighlighter2 } from "shiki";
|
|
3644
4097
|
import * as ts3 from "typescript";
|
|
3645
4098
|
import {
|
|
3646
4099
|
quiCustomDarkTheme as quiCustomDarkTheme3
|
|
3647
4100
|
} from "@qualcomm-ui/mdx-common";
|
|
3648
|
-
import { dedent as
|
|
4101
|
+
import { dedent as dedent3 } from "@qualcomm-ui/utils/dedent";
|
|
3649
4102
|
var highlighter2 = null;
|
|
3650
4103
|
var initializingHighlighter = false;
|
|
3651
4104
|
var demoRegistry2 = /* @__PURE__ */ new Map();
|
|
@@ -3659,7 +4112,8 @@ function reactDemoPlugin({
|
|
|
3659
4112
|
light: "github-light-high-contrast"
|
|
3660
4113
|
},
|
|
3661
4114
|
transformers = [],
|
|
3662
|
-
transformLine
|
|
4115
|
+
transformLine,
|
|
4116
|
+
transformTailwindStyles
|
|
3663
4117
|
} = {}) {
|
|
3664
4118
|
const defaultShikiOptions = {
|
|
3665
4119
|
defaultColor: "light-dark()",
|
|
@@ -3678,10 +4132,8 @@ function reactDemoPlugin({
|
|
|
3678
4132
|
initializingHighlighter = true;
|
|
3679
4133
|
try {
|
|
3680
4134
|
highlighter2 = await createHighlighter2({
|
|
3681
|
-
langs: ["tsx", "typescript"],
|
|
4135
|
+
langs: ["tsx", "typescript", "css"],
|
|
3682
4136
|
themes: [theme.dark, theme.light]
|
|
3683
|
-
}).finally(() => {
|
|
3684
|
-
initializingHighlighter = false;
|
|
3685
4137
|
});
|
|
3686
4138
|
console.log(
|
|
3687
4139
|
`${chalk6.magenta.bold(LOG_PREFIX2)} Shiki highlighter initialized`
|
|
@@ -3691,6 +4143,8 @@ function reactDemoPlugin({
|
|
|
3691
4143
|
`${chalk6.magenta.bold(LOG_PREFIX2)} Failed to initialize highlighter:`,
|
|
3692
4144
|
error
|
|
3693
4145
|
);
|
|
4146
|
+
} finally {
|
|
4147
|
+
initializingHighlighter = false;
|
|
3694
4148
|
}
|
|
3695
4149
|
}
|
|
3696
4150
|
await collectReactDemos();
|
|
@@ -3772,26 +4226,46 @@ function reactDemoPlugin({
|
|
|
3772
4226
|
}
|
|
3773
4227
|
}
|
|
3774
4228
|
}
|
|
3775
|
-
async function highlightCode(code) {
|
|
4229
|
+
async function highlightCode(code, options = {}) {
|
|
4230
|
+
const { extraTransformers = [], onResidualCss } = options;
|
|
3776
4231
|
if (!highlighter2) {
|
|
3777
|
-
return {
|
|
4232
|
+
return { full: code };
|
|
3778
4233
|
}
|
|
3779
4234
|
let previewCode = null;
|
|
3780
|
-
|
|
4235
|
+
const tailwindTransformers = [];
|
|
4236
|
+
if (transformTailwindStyles && onResidualCss) {
|
|
4237
|
+
const transformer = await createShikiTailwindTransformer({
|
|
4238
|
+
onClassesDetected: (detected) => {
|
|
4239
|
+
options.onClassesDetected?.(detected);
|
|
4240
|
+
},
|
|
4241
|
+
onResidualCss,
|
|
4242
|
+
styleFormat: "jsx",
|
|
4243
|
+
styles: dedent3`
|
|
4244
|
+
@layer theme, base, components, utilities;
|
|
4245
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
4246
|
+
@import "tailwindcss/utilities.css" layer(utilities);
|
|
4247
|
+
@import "@qualcomm-ui/tailwind-plugin/qui-strict.css";
|
|
4248
|
+
`
|
|
4249
|
+
});
|
|
4250
|
+
tailwindTransformers.push(transformer);
|
|
4251
|
+
} else if (extraTransformers.length > 0) {
|
|
4252
|
+
tailwindTransformers.push(...extraTransformers);
|
|
4253
|
+
}
|
|
3781
4254
|
try {
|
|
3782
|
-
const
|
|
4255
|
+
const highlightedCode = highlighter2.codeToHtml(code, {
|
|
3783
4256
|
...defaultShikiOptions,
|
|
3784
4257
|
transformers: [
|
|
3785
4258
|
...getShikiTransformers(),
|
|
4259
|
+
...transformers,
|
|
4260
|
+
...tailwindTransformers,
|
|
3786
4261
|
transformerPreviewBlock({
|
|
4262
|
+
attributeName: "data-preview",
|
|
3787
4263
|
onComplete: (extractedPreview) => {
|
|
3788
|
-
previewCode = extractedPreview
|
|
4264
|
+
previewCode = extractedPreview;
|
|
3789
4265
|
}
|
|
3790
4266
|
}),
|
|
3791
4267
|
transformerCodeAttribute({
|
|
3792
|
-
|
|
3793
|
-
codeWithoutSnippets = formattedSource;
|
|
3794
|
-
}
|
|
4268
|
+
attributeName: "data-code"
|
|
3795
4269
|
}),
|
|
3796
4270
|
{
|
|
3797
4271
|
enforce: "post",
|
|
@@ -3803,38 +4277,16 @@ function reactDemoPlugin({
|
|
|
3803
4277
|
...transformers
|
|
3804
4278
|
]
|
|
3805
4279
|
});
|
|
3806
|
-
let highlightedPreview = null;
|
|
3807
|
-
if (previewCode) {
|
|
3808
|
-
highlightedPreview = highlighter2.codeToHtml(code, {
|
|
3809
|
-
...defaultShikiOptions,
|
|
3810
|
-
transformers: [
|
|
3811
|
-
...getShikiTransformers(),
|
|
3812
|
-
transformerPreviewBlock({
|
|
3813
|
-
displayMode: "only-preview"
|
|
3814
|
-
}),
|
|
3815
|
-
{
|
|
3816
|
-
enforce: "post",
|
|
3817
|
-
name: "shiki-transformer-trim",
|
|
3818
|
-
preprocess(code2) {
|
|
3819
|
-
return code2.trim();
|
|
3820
|
-
}
|
|
3821
|
-
},
|
|
3822
|
-
...transformers
|
|
3823
|
-
]
|
|
3824
|
-
});
|
|
3825
|
-
}
|
|
3826
4280
|
return {
|
|
3827
|
-
|
|
3828
|
-
highlightedCode:
|
|
3829
|
-
highlightedPreview,
|
|
3830
|
-
previewCodeWithoutSnippets: previewCode
|
|
4281
|
+
full: highlightedCode,
|
|
4282
|
+
preview: previewCode ? extractPreviewFromHighlightedHtml(highlightedCode) : null
|
|
3831
4283
|
};
|
|
3832
4284
|
} catch (error) {
|
|
3833
4285
|
console.warn(
|
|
3834
4286
|
`${chalk6.magenta.bold(LOG_PREFIX2)} Failed to highlight code:`,
|
|
3835
4287
|
error
|
|
3836
4288
|
);
|
|
3837
|
-
return {
|
|
4289
|
+
return { full: code };
|
|
3838
4290
|
}
|
|
3839
4291
|
}
|
|
3840
4292
|
async function collectReactDemos() {
|
|
@@ -3894,22 +4346,34 @@ function reactDemoPlugin({
|
|
|
3894
4346
|
async function extractHighlightedCode(filePath, code) {
|
|
3895
4347
|
try {
|
|
3896
4348
|
const fileName = basename2(filePath);
|
|
3897
|
-
const
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
4349
|
+
const baseResult = await highlightCode(code);
|
|
4350
|
+
let inlineResult;
|
|
4351
|
+
let classesDetected = false;
|
|
4352
|
+
let residualRules;
|
|
4353
|
+
if (transformTailwindStyles) {
|
|
4354
|
+
inlineResult = await highlightCode(code, {
|
|
4355
|
+
onClassesDetected: (detected) => {
|
|
4356
|
+
classesDetected = detected;
|
|
4357
|
+
},
|
|
4358
|
+
onResidualCss: (rules) => {
|
|
4359
|
+
residualRules = rules;
|
|
4360
|
+
}
|
|
4361
|
+
});
|
|
4362
|
+
}
|
|
3903
4363
|
return {
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
4364
|
+
residualRules,
|
|
4365
|
+
sourceCodeData: {
|
|
4366
|
+
fileName,
|
|
4367
|
+
filePath,
|
|
4368
|
+
highlighted: {
|
|
4369
|
+
full: baseResult.full,
|
|
4370
|
+
preview: baseResult.preview
|
|
4371
|
+
},
|
|
4372
|
+
highlightedInline: classesDetected && inlineResult ? {
|
|
4373
|
+
full: inlineResult.full,
|
|
4374
|
+
preview: inlineResult.preview
|
|
4375
|
+
} : void 0,
|
|
4376
|
+
type: "file"
|
|
3913
4377
|
}
|
|
3914
4378
|
};
|
|
3915
4379
|
} catch {
|
|
@@ -3918,36 +4382,55 @@ function reactDemoPlugin({
|
|
|
3918
4382
|
}
|
|
3919
4383
|
async function extractFileData(filePath) {
|
|
3920
4384
|
try {
|
|
3921
|
-
const code = await
|
|
4385
|
+
const code = await readFile4(filePath, "utf-8").then(transformLines);
|
|
3922
4386
|
const imports = stripImports(code, filePath);
|
|
3923
4387
|
const sourceCode = [];
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
4388
|
+
const aggregatedRules = /* @__PURE__ */ new Map();
|
|
4389
|
+
const extractedMain = await extractHighlightedCode(filePath, code);
|
|
4390
|
+
if (extractedMain) {
|
|
4391
|
+
sourceCode.push(extractedMain.sourceCodeData);
|
|
4392
|
+
if (extractedMain.residualRules) {
|
|
4393
|
+
for (const [className, rule] of extractedMain.residualRules) {
|
|
4394
|
+
aggregatedRules.set(className, rule);
|
|
4395
|
+
}
|
|
4396
|
+
}
|
|
3927
4397
|
}
|
|
3928
4398
|
const fileImports = await extractFileImports(filePath);
|
|
3929
4399
|
if (fileImports) {
|
|
3930
4400
|
for (const relativeImport of fileImports.relativeImports) {
|
|
3931
4401
|
try {
|
|
3932
|
-
const importedCode = await
|
|
4402
|
+
const importedCode = await readFile4(
|
|
3933
4403
|
relativeImport.resolvedPath,
|
|
3934
4404
|
"utf-8"
|
|
3935
4405
|
).then(transformLines);
|
|
3936
|
-
const
|
|
4406
|
+
const extracted = await extractHighlightedCode(
|
|
3937
4407
|
relativeImport.resolvedPath,
|
|
3938
4408
|
importedCode
|
|
3939
4409
|
);
|
|
3940
|
-
if (
|
|
3941
|
-
sourceCode.push(
|
|
4410
|
+
if (extracted) {
|
|
4411
|
+
sourceCode.push(extracted.sourceCodeData);
|
|
4412
|
+
if (extracted.residualRules) {
|
|
4413
|
+
for (const [className, rule] of extracted.residualRules) {
|
|
4414
|
+
aggregatedRules.set(className, rule);
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
3942
4417
|
}
|
|
3943
4418
|
} catch {
|
|
3944
4419
|
console.debug("Failed to process file", relativeImport.resolvedPath);
|
|
3945
4420
|
}
|
|
3946
4421
|
}
|
|
3947
4422
|
}
|
|
4423
|
+
const aggregatedResidualCss = aggregatedRules.size > 0 ? [...aggregatedRules.values()].join("\n\n") : void 0;
|
|
4424
|
+
if (aggregatedResidualCss) {
|
|
4425
|
+
sourceCode.push({
|
|
4426
|
+
fileName: "styles.css",
|
|
4427
|
+
highlighted: await highlightCode(aggregatedResidualCss),
|
|
4428
|
+
type: "residual-css"
|
|
4429
|
+
});
|
|
4430
|
+
}
|
|
3948
4431
|
return {
|
|
3949
4432
|
demoName: createDemoName(filePath),
|
|
3950
|
-
fileName: sourceCodeData
|
|
4433
|
+
fileName: extractedMain?.sourceCodeData.fileName || basename2(filePath),
|
|
3951
4434
|
filePath,
|
|
3952
4435
|
imports,
|
|
3953
4436
|
sourceCode
|
|
@@ -3958,16 +4441,16 @@ function reactDemoPlugin({
|
|
|
3958
4441
|
}
|
|
3959
4442
|
function stripImports(code, fileName) {
|
|
3960
4443
|
try {
|
|
3961
|
-
let
|
|
4444
|
+
let visit9 = function(node) {
|
|
3962
4445
|
if (ts3.isImportDeclaration(node)) {
|
|
3963
4446
|
importRanges.push({
|
|
3964
4447
|
end: node.getEnd(),
|
|
3965
4448
|
start: node.getFullStart()
|
|
3966
4449
|
});
|
|
3967
4450
|
}
|
|
3968
|
-
ts3.forEachChild(node,
|
|
4451
|
+
ts3.forEachChild(node, visit9);
|
|
3969
4452
|
};
|
|
3970
|
-
var
|
|
4453
|
+
var visit8 = visit9;
|
|
3971
4454
|
const sourceFile = ts3.createSourceFile(
|
|
3972
4455
|
fileName,
|
|
3973
4456
|
code,
|
|
@@ -3976,7 +4459,7 @@ function reactDemoPlugin({
|
|
|
3976
4459
|
getScriptKind(fileName)
|
|
3977
4460
|
);
|
|
3978
4461
|
const importRanges = [];
|
|
3979
|
-
|
|
4462
|
+
visit9(sourceFile);
|
|
3980
4463
|
return importRanges.map((range) => {
|
|
3981
4464
|
let endPos = range.end;
|
|
3982
4465
|
if (code[endPos] === "\n") {
|
|
@@ -3997,7 +4480,7 @@ ${entries}
|
|
|
3997
4480
|
])`;
|
|
3998
4481
|
}
|
|
3999
4482
|
function generateExportedFunctions() {
|
|
4000
|
-
return
|
|
4483
|
+
return dedent3`
|
|
4001
4484
|
export function getDemo(demoName) {
|
|
4002
4485
|
const demo = demoRegistry.get(demoName)
|
|
4003
4486
|
if (!demo) {
|