pattern-dump 0.1.0-alpha.3 → 0.1.0-alpha.4
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/CHANGELOG.md +37 -0
- package/README.md +1 -1
- package/dist/chunks/{chunk-3WZHFYHZ.js → chunk-NXGPZL5L.js} +3 -3
- package/dist/index.js +1 -1
- package/dist/pd.js +353 -212
- package/dist/types/config/index.d.ts +12 -4
- package/dist/types/contracts/dev-protocol.d.ts +2 -2
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.4
|
|
4
|
+
|
|
5
|
+
Fixes found while moving a third PatternLab styleguide (CTS) to Pattern Dump with hTWOo consumed only as
|
|
6
|
+
pattern packages: its templates, data, scripts and CSS all come from `@n8d/htwoo-patterns` and
|
|
7
|
+
`@n8d/htwoo-core`, and the project compiles only its own SCSS.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `styles: false` on a package reference leaves that package's stylesheets out, for a project that
|
|
12
|
+
compiles them itself; its templates, data, themes, scripts and assets are still used. It also works
|
|
13
|
+
for a package that another brings in as a peer: name the peer with the option.
|
|
14
|
+
- `themes.dir` is optional: `themes: { default: "<name>" }` alone makes one of your packages' themes the
|
|
15
|
+
one previews start with. `pd dev` warns when the default matches no theme.
|
|
16
|
+
- A component or variant `.json` that does not parse is reported as a `DATA_INVALID` diagnostic, with
|
|
17
|
+
the file and, where the parser gives one, the line and column, instead of being dropped silently. An
|
|
18
|
+
invalid variant file no longer fails the whole render.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- A class belongs to the rule that defines it (the class on its own, such as `.card` or `.card:hover`),
|
|
23
|
+
not to every rule that mentions it. A project rule that restyles a package class in context
|
|
24
|
+
(`.tile .hoo-radio`) took the class over, so the package component's CSS was never linked where the
|
|
25
|
+
class was used.
|
|
26
|
+
- A rule repeated after a different one (A, B, A) keeps its last position in the base layer and in
|
|
27
|
+
component CSS, as the browser applies it. The first copy was kept, so B won.
|
|
28
|
+
- Included partials keep the caller's data frame, as in stock Handlebars: `@root` is the page's data,
|
|
29
|
+
and `{{#if @partial-block}}` sees the block of a block call.
|
|
30
|
+
- A configured `styles.entry` list compiles in the order given. It was sorted, which could change the
|
|
31
|
+
cascade.
|
|
32
|
+
- SCSS can load an installed package by its bare name (`@use '@scope/pkg/…'`) or a `pkg:` URL, without
|
|
33
|
+
`SASS_PATH`.
|
|
34
|
+
- A data variant reached by its own id (`/preview/atoms/chip~danger`) or included by its handle
|
|
35
|
+
(`{{> "atoms-chip~danger"}}`) renders on top of its base component's data, as `?variant=` already did.
|
|
36
|
+
- `pd build` copies assets as `pd dev` serves them: where two asset folders share a name, the first one
|
|
37
|
+
(the project's) wins and the other is left out and reported. A package's `images/` used to overwrite
|
|
38
|
+
the project's in the snapshot. `pd dev` warns about such folders at startup.
|
|
39
|
+
|
|
3
40
|
## 0.1.0-alpha.3
|
|
4
41
|
|
|
5
42
|
Fixes found while moving a second PatternLab styleguide (n8d) to Pattern Dump.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A workbench for HTML and CSS design systems, and a successor to PatternLab. Writ
|
|
|
4
4
|
Handlebars templates with SCSS, data and Markdown docs; Pattern Dump shows them live, checks them, maps
|
|
5
5
|
how they relate, and publishes the result as a static site.
|
|
6
6
|
|
|
7
|
-
> **Alpha (0.1.0-alpha.
|
|
7
|
+
> **Alpha (0.1.0-alpha.4).** Published under the `alpha` tag. Options and file conventions can still change
|
|
8
8
|
> between releases.
|
|
9
9
|
|
|
10
10
|
## Requirements
|
|
@@ -19,7 +19,7 @@ var SHAPE = {
|
|
|
19
19
|
switch: { values: ["attribute", "stylesheet"] },
|
|
20
20
|
swatch: { keys: { slots: "strings" }, required: ["slots"] }
|
|
21
21
|
},
|
|
22
|
-
required: ["
|
|
22
|
+
required: ["default"]
|
|
23
23
|
},
|
|
24
24
|
assets: {
|
|
25
25
|
keys: {
|
|
@@ -107,8 +107,8 @@ function checkValue(value, rule, at, problems) {
|
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
109
|
if (rule === "packages") {
|
|
110
|
-
const ok = Array.isArray(value) && value.every((p) => typeof p === "string" || isObject(p) && typeof p.name === "string" && (p.exclude === void 0 || isStrings(p.exclude)));
|
|
111
|
-
if (!ok) fail(`a list of package names or { name, exclude } objects`);
|
|
110
|
+
const ok = Array.isArray(value) && value.every((p) => typeof p === "string" || isObject(p) && typeof p.name === "string" && (p.exclude === void 0 || isStrings(p.exclude)) && (p.styles === void 0 || typeof p.styles === "boolean"));
|
|
111
|
+
if (!ok) fail(`a list of package names or { name, exclude, styles } objects`);
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
if (rule === "logo") {
|
package/dist/index.js
CHANGED
package/dist/pd.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ConfigError,
|
|
4
4
|
validateConfig
|
|
5
|
-
} from "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-NXGPZL5L.js";
|
|
6
6
|
|
|
7
7
|
// packages/discovery/src/index.ts
|
|
8
8
|
import { readdir } from "node:fs/promises";
|
|
@@ -420,6 +420,7 @@ function _plainPre(code) {
|
|
|
420
420
|
import { HtmlValidate } from "html-validate";
|
|
421
421
|
import Handlebars from "handlebars";
|
|
422
422
|
import { readFile } from "node:fs/promises";
|
|
423
|
+
import { basename as basename2 } from "node:path";
|
|
423
424
|
var htmlValidator = new HtmlValidate({
|
|
424
425
|
rules: {
|
|
425
426
|
"element-permitted-content": "error",
|
|
@@ -441,6 +442,36 @@ function deepMerge(target, ...sources) {
|
|
|
441
442
|
return target;
|
|
442
443
|
}
|
|
443
444
|
var safePart = (n) => n.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
445
|
+
function jsonErrorPosition(reason, text) {
|
|
446
|
+
const lineColumn = /line (\d+) column (\d+)/.exec(reason);
|
|
447
|
+
if (lineColumn) return { line: Number(lineColumn[1]), column: Number(lineColumn[2]) };
|
|
448
|
+
const position = /position (\d+)/.exec(reason);
|
|
449
|
+
if (!position) return {};
|
|
450
|
+
const lines = text.slice(0, Number(position[1])).split("\n");
|
|
451
|
+
return { line: lines.length, column: lines[lines.length - 1].length + 1 };
|
|
452
|
+
}
|
|
453
|
+
async function readDataFile(path) {
|
|
454
|
+
let text;
|
|
455
|
+
try {
|
|
456
|
+
text = await readFile(path, "utf-8");
|
|
457
|
+
} catch {
|
|
458
|
+
return {};
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
return { data: JSON.parse(text) };
|
|
462
|
+
} catch (e) {
|
|
463
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
464
|
+
return {
|
|
465
|
+
diagnostic: {
|
|
466
|
+
kind: "DATA_INVALID",
|
|
467
|
+
source: "render",
|
|
468
|
+
severity: "error",
|
|
469
|
+
message: `${basename2(path)} is not valid JSON (${reason}); its data was not used`,
|
|
470
|
+
location: { file: path, ...jsonErrorPosition(reason, text) }
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
}
|
|
444
475
|
function registerHelpers(env, mintId, getLastId, projectHelpers, helperRegistrars) {
|
|
445
476
|
env.registerHelper("id", (name) => mintId(name));
|
|
446
477
|
env.registerHelper("getId", (name) => mintId(name));
|
|
@@ -521,30 +552,34 @@ var createRenderer = (options) => {
|
|
|
521
552
|
discoveryMap ??= maps.discoveryMap;
|
|
522
553
|
handleMap ??= maps.handleMap;
|
|
523
554
|
}
|
|
524
|
-
|
|
525
|
-
|
|
555
|
+
let componentId = input.component;
|
|
556
|
+
let variant = input.variant;
|
|
557
|
+
const tilde = componentId.indexOf("~");
|
|
558
|
+
if (tilde > 0 && !variant && discoveryMap.has(componentId.slice(0, tilde))) {
|
|
559
|
+
variant = componentId.slice(tilde + 1);
|
|
560
|
+
componentId = componentId.slice(0, tilde);
|
|
561
|
+
}
|
|
562
|
+
const entry = discoveryMap.get(componentId);
|
|
563
|
+
if (!entry) throw new Error(`[renderer] Component not found: "${componentId}"`);
|
|
526
564
|
let templateHbsPath = entry.hbsPath;
|
|
527
565
|
let variantJsonPath;
|
|
528
|
-
if (
|
|
529
|
-
const variantEntry = discoveryMap.get(`${
|
|
530
|
-
if (!variantEntry) throw new Error(`[renderer] Variant not found: "${
|
|
566
|
+
if (variant) {
|
|
567
|
+
const variantEntry = discoveryMap.get(`${componentId}~${variant}`);
|
|
568
|
+
if (!variantEntry) throw new Error(`[renderer] Variant not found: "${componentId}~${variant}"`);
|
|
531
569
|
if (variantEntry.ownMarkup && variantEntry.hbsPath) {
|
|
532
570
|
templateHbsPath = variantEntry.hbsPath;
|
|
533
571
|
}
|
|
534
572
|
variantJsonPath = variantEntry.jsonPath;
|
|
535
573
|
}
|
|
536
574
|
const templateSrc = templateHbsPath ? await readFile(templateHbsPath, "utf-8") : "";
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (variantJsonPath) {
|
|
546
|
-
variantData = JSON.parse(await readFile(variantJsonPath, "utf-8"));
|
|
547
|
-
}
|
|
575
|
+
const dataDiagnostics = /* @__PURE__ */ new Map();
|
|
576
|
+
const readData = async (path) => {
|
|
577
|
+
const { data: data2, diagnostic } = await readDataFile(path);
|
|
578
|
+
if (diagnostic) dataDiagnostics.set(path, diagnostic);
|
|
579
|
+
return data2;
|
|
580
|
+
};
|
|
581
|
+
const defaultData = (entry.jsonPath ? await readData(entry.jsonPath) : void 0) ?? {};
|
|
582
|
+
const variantData = variantJsonPath ? await readData(variantJsonPath) : void 0;
|
|
548
583
|
const data = deepMerge(
|
|
549
584
|
structuredClone(options.globalData ?? {}),
|
|
550
585
|
defaultData,
|
|
@@ -552,7 +587,7 @@ var createRenderer = (options) => {
|
|
|
552
587
|
input.data
|
|
553
588
|
);
|
|
554
589
|
const env = Handlebars.create();
|
|
555
|
-
const componentSlug = safePart(
|
|
590
|
+
const componentSlug = safePart(componentId.replace(/[\\/]/g, "-"));
|
|
556
591
|
let currentBase = `pd-${componentSlug}`;
|
|
557
592
|
const idCache = /* @__PURE__ */ new Map();
|
|
558
593
|
let lastMintedId = "";
|
|
@@ -572,13 +607,12 @@ var createRenderer = (options) => {
|
|
|
572
607
|
if (!compEntry?.hbsPath) continue;
|
|
573
608
|
try {
|
|
574
609
|
const partialSrc = await readFile(compEntry.hbsPath, "utf-8");
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
610
|
+
const childData = compEntry.jsonPath ? await readDataFile(compEntry.jsonPath) : {};
|
|
611
|
+
const childDataPath = compEntry.jsonPath;
|
|
612
|
+
const variantTilde = compId.indexOf("~");
|
|
613
|
+
const baseJsonPath = variantTilde > 0 ? discoveryMap.get(compId.slice(0, variantTilde))?.jsonPath : void 0;
|
|
614
|
+
const baseData = baseJsonPath ? await readDataFile(baseJsonPath) : {};
|
|
615
|
+
const childDefaults = deepMerge(structuredClone(baseData.data ?? {}), childData.data);
|
|
582
616
|
const childTemplate = env.compile(partialSrc);
|
|
583
617
|
const capturedDefaults = childDefaults;
|
|
584
618
|
const partialSlug = safePart(compId.replace(/[\\/]/g, "-"));
|
|
@@ -595,13 +629,16 @@ var createRenderer = (options) => {
|
|
|
595
629
|
invocationCounters.set(counterKey, n + 1);
|
|
596
630
|
thisBase = n === 0 ? currentBase : `pd-${partialSlug}-${n}`;
|
|
597
631
|
}
|
|
632
|
+
if (childData.diagnostic && childDataPath) dataDiagnostics.set(childDataPath, childData.diagnostic);
|
|
633
|
+
if (baseData.diagnostic && baseJsonPath) dataDiagnostics.set(baseJsonPath, baseData.diagnostic);
|
|
598
634
|
const savedBase = currentBase;
|
|
599
635
|
currentBase = thisBase;
|
|
600
636
|
const merged = deepMerge(
|
|
601
637
|
structuredClone(capturedDefaults),
|
|
602
638
|
context != null && typeof context === "object" && !Array.isArray(context) ? context : {}
|
|
603
639
|
);
|
|
604
|
-
const
|
|
640
|
+
const data2 = { ...opts?.data, ...opts?.fn ? { "partial-block": opts.fn } : {} };
|
|
641
|
+
const runtime = opts?.fn ? { data: data2, partials: { ...env.partials, "@partial-block": opts.fn } } : { data: data2 };
|
|
605
642
|
const result = childTemplate(merged, runtime);
|
|
606
643
|
currentBase = savedBase;
|
|
607
644
|
return result;
|
|
@@ -613,7 +650,7 @@ var createRenderer = (options) => {
|
|
|
613
650
|
const html = env.compile(templateSrc)(data, {
|
|
614
651
|
partials: { ...env.partials, "@partial-block": () => "" }
|
|
615
652
|
});
|
|
616
|
-
const diagnostics = [];
|
|
653
|
+
const diagnostics = [...dataDiagnostics.values()];
|
|
617
654
|
const htmlReport = htmlValidator.validateStringSync(html);
|
|
618
655
|
for (const result of htmlReport.results) {
|
|
619
656
|
for (const msg of result.messages) {
|
|
@@ -662,7 +699,7 @@ var createRenderer = (options) => {
|
|
|
662
699
|
}
|
|
663
700
|
} catch {
|
|
664
701
|
}
|
|
665
|
-
const meta = diagnostics.length > 0 ? { componentId
|
|
702
|
+
const meta = diagnostics.length > 0 ? { componentId, variant, diagnostics } : void 0;
|
|
666
703
|
return { html, document: buildDocument(html, options), ...meta ? { meta } : {} };
|
|
667
704
|
};
|
|
668
705
|
};
|
|
@@ -685,9 +722,26 @@ import * as sass from "sass";
|
|
|
685
722
|
import postcss from "postcss";
|
|
686
723
|
import autoprefixer from "autoprefixer";
|
|
687
724
|
import { build as esbuildBuild } from "esbuild";
|
|
725
|
+
import { existsSync } from "node:fs";
|
|
688
726
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
689
|
-
import { join as join2, extname, resolve } from "node:path";
|
|
727
|
+
import { dirname as dirname2, join as join2, extname, resolve } from "node:path";
|
|
690
728
|
import { fileURLToPath } from "node:url";
|
|
729
|
+
var packageOptionsCache = /* @__PURE__ */ new Map();
|
|
730
|
+
function sassPackageOptions(entryFile) {
|
|
731
|
+
const start = dirname2(resolve(entryFile));
|
|
732
|
+
let options = packageOptionsCache.get(start);
|
|
733
|
+
if (!options) {
|
|
734
|
+
const loadPaths = [];
|
|
735
|
+
for (let dir = start; ; dir = dirname2(dir)) {
|
|
736
|
+
const modules = join2(dir, "node_modules");
|
|
737
|
+
if (existsSync(modules)) loadPaths.push(modules);
|
|
738
|
+
if (dirname2(dir) === dir) break;
|
|
739
|
+
}
|
|
740
|
+
options = { loadPaths, importers: [new sass.NodePackageImporter(start)] };
|
|
741
|
+
packageOptionsCache.set(start, options);
|
|
742
|
+
}
|
|
743
|
+
return options;
|
|
744
|
+
}
|
|
691
745
|
async function collectScssFiles(dir) {
|
|
692
746
|
const files = [];
|
|
693
747
|
async function walk(current) {
|
|
@@ -710,7 +764,7 @@ async function collectScssFiles(dir) {
|
|
|
710
764
|
return files;
|
|
711
765
|
}
|
|
712
766
|
async function compileSassFileWithDeps(filePath) {
|
|
713
|
-
const result = sass.compile(filePath);
|
|
767
|
+
const result = sass.compile(filePath, sassPackageOptions(filePath));
|
|
714
768
|
const processed = await postcss([autoprefixer]).process(result.css, { from: void 0 });
|
|
715
769
|
const deps = result.loadedUrls.filter((u) => u.protocol === "file:").map((u) => fileURLToPath(u)).filter((p) => resolve(p) !== resolve(filePath));
|
|
716
770
|
return { css: processed.css, deps };
|
|
@@ -1182,7 +1236,7 @@ async function loadGlobalData(dataDirs) {
|
|
|
1182
1236
|
|
|
1183
1237
|
// packages/dev-server/src/surfacing.ts
|
|
1184
1238
|
import { mkdir, readFile as readFile5, writeFile } from "node:fs/promises";
|
|
1185
|
-
import { join as
|
|
1239
|
+
import { join as join8, relative as relative3 } from "node:path";
|
|
1186
1240
|
|
|
1187
1241
|
// packages/dev-server/src/flattening.ts
|
|
1188
1242
|
import { parse as parseHtml } from "node-html-parser";
|
|
@@ -1428,11 +1482,108 @@ function pdScratchDir(root) {
|
|
|
1428
1482
|
return join5(tmpdir(), "pattern-dump", key);
|
|
1429
1483
|
}
|
|
1430
1484
|
|
|
1485
|
+
// packages/dev-server/src/server-config.ts
|
|
1486
|
+
import { basename as basename3, join as join6, resolve as resolve4 } from "node:path";
|
|
1487
|
+
function shadowedAssetRoots(assetRoots) {
|
|
1488
|
+
const first = /* @__PURE__ */ new Map();
|
|
1489
|
+
const shadowed = [];
|
|
1490
|
+
for (const root of assetRoots) {
|
|
1491
|
+
const by = first.get(basename3(root));
|
|
1492
|
+
if (by === void 0) first.set(basename3(root), root);
|
|
1493
|
+
else if (by !== root) shadowed.push({ root, by });
|
|
1494
|
+
}
|
|
1495
|
+
return shadowed;
|
|
1496
|
+
}
|
|
1497
|
+
var DEFAULT_SWATCH_SLOTS = ["--bodyBackground", "--themePrimary", "--accent"];
|
|
1498
|
+
function resolveServerConfig(config, cwd, opts = {}, packages = []) {
|
|
1499
|
+
const port2 = opts.port ?? Number(process.env["PD_PORT"] ?? 4e3);
|
|
1500
|
+
const wsPort = opts.wsPort ?? Number(process.env["PD_WS_PORT"] ?? port2 + 1);
|
|
1501
|
+
const patternsDir = resolve4(cwd, config.patternsDir);
|
|
1502
|
+
const stylesDir = resolve4(cwd, config.styles.dir);
|
|
1503
|
+
const stylesEntries = config.styles.entry ? (Array.isArray(config.styles.entry) ? config.styles.entry : [config.styles.entry]).map((e) => resolve4(stylesDir, e)) : void 0;
|
|
1504
|
+
const inPackage = (p, rel) => join6(p.dir, rel);
|
|
1505
|
+
const asList = (v) => v === void 0 ? [] : Array.isArray(v) ? v : [v];
|
|
1506
|
+
const patternRoots = [
|
|
1507
|
+
{ dir: patternsDir, ...config.exclude?.length ? { exclude: config.exclude } : {} },
|
|
1508
|
+
...packages.filter((p) => p.manifest.patterns).map((p) => ({
|
|
1509
|
+
dir: inPackage(p, p.manifest.patterns),
|
|
1510
|
+
source: p.name,
|
|
1511
|
+
...p.exclude.length ? { exclude: p.exclude } : {}
|
|
1512
|
+
}))
|
|
1513
|
+
];
|
|
1514
|
+
const styleRoots = [
|
|
1515
|
+
{ dir: stylesDir, entries: stylesEntries, base: config.documentBase },
|
|
1516
|
+
...packages.filter((p) => p.manifest.styles && p.styles).map((p) => {
|
|
1517
|
+
const dir = inPackage(p, p.manifest.styles.dir);
|
|
1518
|
+
const entries = asList(p.manifest.styles.entry).map((e) => resolve4(dir, e));
|
|
1519
|
+
return { dir, entries: entries.length ? entries : void 0, source: p.name, base: p.manifest.styles.documentBase };
|
|
1520
|
+
})
|
|
1521
|
+
];
|
|
1522
|
+
const themePackages = packages.filter((p) => p.manifest.themes);
|
|
1523
|
+
const themeDirs = [
|
|
1524
|
+
...config.themes?.dir ? [resolve4(cwd, config.themes.dir)] : [],
|
|
1525
|
+
...themePackages.map((p) => inPackage(p, p.manifest.themes.dir))
|
|
1526
|
+
];
|
|
1527
|
+
const switches = [config.themes?.switch, ...themePackages.map((p) => p.manifest.themes.switch)];
|
|
1528
|
+
const themeSwitch = switches.includes("stylesheet") ? "stylesheet" : "attribute";
|
|
1529
|
+
const assetRoots = [
|
|
1530
|
+
...asList(config.assets?.dir).map((d) => resolve4(cwd, d)),
|
|
1531
|
+
...packages.flatMap((p) => (p.manifest.assets ?? []).map((a) => inPackage(p, a)))
|
|
1532
|
+
];
|
|
1533
|
+
const globalScripts = [.../* @__PURE__ */ new Set([
|
|
1534
|
+
...packages.flatMap((p) => p.manifest.globalScripts ?? []),
|
|
1535
|
+
...config.globalScripts ?? []
|
|
1536
|
+
])];
|
|
1537
|
+
const scriptsDirs = [
|
|
1538
|
+
...config.scriptsDir ? [resolve4(cwd, config.scriptsDir)] : [],
|
|
1539
|
+
...packages.filter((p) => p.manifest.scripts).map((p) => inPackage(p, p.manifest.scripts))
|
|
1540
|
+
];
|
|
1541
|
+
const documentBaseEnabled = Array.isArray(config.documentBase) && config.documentBase.length > 0 || packages.some((p) => p.styles && (p.manifest.styles?.documentBase?.length ?? 0) > 0);
|
|
1542
|
+
return {
|
|
1543
|
+
port: port2,
|
|
1544
|
+
wsPort,
|
|
1545
|
+
cwd,
|
|
1546
|
+
config,
|
|
1547
|
+
packages,
|
|
1548
|
+
patternRoots,
|
|
1549
|
+
patternDirs: patternRoots.map((r) => r.dir),
|
|
1550
|
+
styleRoots,
|
|
1551
|
+
dataDirs: [
|
|
1552
|
+
...packages.filter((p) => p.manifest.data).map((p) => inPackage(p, p.manifest.data)),
|
|
1553
|
+
...config.dataDir ? [resolve4(cwd, config.dataDir)] : []
|
|
1554
|
+
],
|
|
1555
|
+
helperPaths: [
|
|
1556
|
+
...packages.filter((p) => p.manifest.helpers).map((p) => inPackage(p, p.manifest.helpers)),
|
|
1557
|
+
...config.helpers ? [resolve4(cwd, config.helpers)] : []
|
|
1558
|
+
],
|
|
1559
|
+
scriptsDirs,
|
|
1560
|
+
patternsDir,
|
|
1561
|
+
stylesDir,
|
|
1562
|
+
stylesEntries,
|
|
1563
|
+
themeDirs,
|
|
1564
|
+
themesDir: themeDirs[0] ?? null,
|
|
1565
|
+
defaultTheme: config.themes?.default ?? themePackages[0]?.manifest.themes?.default,
|
|
1566
|
+
assetRoots,
|
|
1567
|
+
assetRootNames: assetRoots.map((r) => basename3(r)),
|
|
1568
|
+
assetsDir: assetRoots[0] ?? null,
|
|
1569
|
+
assetsCss: config.assets?.css ?? [],
|
|
1570
|
+
scriptsDir: scriptsDirs[0] ?? null,
|
|
1571
|
+
globalScripts,
|
|
1572
|
+
withGlobalScripts: (own) => [.../* @__PURE__ */ new Set([...globalScripts, ...own ?? []])],
|
|
1573
|
+
overviewsEnabled: config.overviews !== false,
|
|
1574
|
+
documentBaseEnabled,
|
|
1575
|
+
themeSwitch,
|
|
1576
|
+
swatchSlots: config.themes?.swatch?.slots ?? DEFAULT_SWATCH_SLOTS,
|
|
1577
|
+
packageSwatchSlots: DEFAULT_SWATCH_SLOTS
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1431
1581
|
// packages/dev-server/src/style-index.ts
|
|
1432
|
-
import { dirname as
|
|
1433
|
-
import { existsSync } from "node:fs";
|
|
1582
|
+
import { dirname as dirname3, join as join7, relative as relative2, resolve as resolve5 } from "node:path";
|
|
1583
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1434
1584
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1435
1585
|
import postcss3 from "postcss";
|
|
1586
|
+
import selectorParser from "postcss-selector-parser";
|
|
1436
1587
|
import { SourceMapConsumer } from "source-map";
|
|
1437
1588
|
import * as sass2 from "sass";
|
|
1438
1589
|
|
|
@@ -1444,6 +1595,10 @@ function cssNodeText(node) {
|
|
|
1444
1595
|
const text = node.toString();
|
|
1445
1596
|
return node.type === "atrule" && !node.nodes ? `${text};` : text;
|
|
1446
1597
|
}
|
|
1598
|
+
function addLastOccurrence(bucket, chunk) {
|
|
1599
|
+
bucket.delete(chunk);
|
|
1600
|
+
bucket.add(chunk);
|
|
1601
|
+
}
|
|
1447
1602
|
function joinCssChunks(chunks) {
|
|
1448
1603
|
const charset = [];
|
|
1449
1604
|
const imports = [];
|
|
@@ -1455,6 +1610,33 @@ function joinCssChunks(chunks) {
|
|
|
1455
1610
|
}
|
|
1456
1611
|
return [...charset.slice(0, 1), ...imports, ...rest].join("\n");
|
|
1457
1612
|
}
|
|
1613
|
+
var selectorClassCache = /* @__PURE__ */ new Map();
|
|
1614
|
+
function selectorClasses(selector) {
|
|
1615
|
+
const cached = selectorClassCache.get(selector);
|
|
1616
|
+
if (cached) return cached;
|
|
1617
|
+
const defines = /* @__PURE__ */ new Set();
|
|
1618
|
+
const mentions = /* @__PURE__ */ new Set();
|
|
1619
|
+
try {
|
|
1620
|
+
selectorParser((list) => {
|
|
1621
|
+
list.each((complex) => {
|
|
1622
|
+
const contextFree = !complex.some((node) => node.type === "combinator");
|
|
1623
|
+
complex.walkClasses((cls) => {
|
|
1624
|
+
(contextFree && cls.parent === complex ? defines : mentions).add(cls.value);
|
|
1625
|
+
});
|
|
1626
|
+
});
|
|
1627
|
+
}).processSync(selector);
|
|
1628
|
+
} catch {
|
|
1629
|
+
for (const m of selector.matchAll(/\.([\w-]+)/g)) defines.add(m[1]);
|
|
1630
|
+
}
|
|
1631
|
+
for (const name of defines) mentions.delete(name);
|
|
1632
|
+
const result = { defines: [...defines], mentions: [...mentions] };
|
|
1633
|
+
selectorClassCache.set(selector, result);
|
|
1634
|
+
return result;
|
|
1635
|
+
}
|
|
1636
|
+
function claimRank(owner, defines) {
|
|
1637
|
+
return (defines ? 2 : 0) + (owner === "__base__" ? 0 : 1);
|
|
1638
|
+
}
|
|
1639
|
+
var indexRanks = /* @__PURE__ */ new WeakMap();
|
|
1458
1640
|
var strippedIdCache = /* @__PURE__ */ new WeakMap();
|
|
1459
1641
|
function strippedIds(componentIds) {
|
|
1460
1642
|
let map = strippedIdCache.get(componentIds);
|
|
@@ -1507,55 +1689,72 @@ function missingDocumentBase(stylesDir, base2) {
|
|
|
1507
1689
|
return (base2 ?? []).filter((entry) => {
|
|
1508
1690
|
const e = normalizeBaseEntry(entry);
|
|
1509
1691
|
if (e === "") return false;
|
|
1510
|
-
const dir =
|
|
1692
|
+
const dir = dirname3(join7(stylesDir, e));
|
|
1511
1693
|
const name = e.split("/").pop();
|
|
1512
|
-
return ![
|
|
1694
|
+
return ![join7(stylesDir, e), join7(dir, `${name}.scss`), join7(dir, `_${name}.scss`)].some(existsSync2);
|
|
1513
1695
|
});
|
|
1514
1696
|
}
|
|
1515
1697
|
function extractClassesFromCompiled(consumer, root, entryFile, stylesDir, componentIds) {
|
|
1516
1698
|
const classMap = /* @__PURE__ */ new Map();
|
|
1517
1699
|
const baseModules = /* @__PURE__ */ new Map();
|
|
1700
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
1518
1701
|
root.walkRules((rule) => {
|
|
1519
|
-
const
|
|
1520
|
-
if (
|
|
1702
|
+
const { defines, mentions } = selectorClasses(rule.selector);
|
|
1703
|
+
if (defines.length === 0 && mentions.length === 0) return;
|
|
1521
1704
|
const pos = rule.source?.start;
|
|
1522
1705
|
if (!pos) return;
|
|
1523
1706
|
const original = consumer.originalPositionFor({ line: pos.line, column: pos.column - 1 });
|
|
1524
1707
|
if (!original.source) return;
|
|
1525
|
-
const originPath = original.source.startsWith("file://") ? fileURLToPath2(original.source) :
|
|
1708
|
+
const originPath = original.source.startsWith("file://") ? fileURLToPath2(original.source) : resolve5(dirname3(entryFile), original.source);
|
|
1526
1709
|
const resolved = resolveScssToComponent(originPath, stylesDir, componentIds);
|
|
1527
1710
|
const owner = resolved ?? "__base__";
|
|
1528
1711
|
const modulePath = resolved === null ? resolveSharedModulePath(originPath, stylesDir, true) : null;
|
|
1529
|
-
|
|
1530
|
-
const
|
|
1531
|
-
if (
|
|
1532
|
-
|
|
1712
|
+
const claim = (name, rank) => {
|
|
1713
|
+
const prev = ranks.get(name);
|
|
1714
|
+
if (prev === void 0 || rank > prev) {
|
|
1715
|
+
classMap.set(name, owner);
|
|
1716
|
+
ranks.set(name, rank);
|
|
1717
|
+
if (modulePath && owner === "__base__") baseModules.set(name, modulePath);
|
|
1718
|
+
else baseModules.delete(name);
|
|
1719
|
+
} else if (modulePath && owner === "__base__" && classMap.get(name) === "__base__" && !baseModules.has(name)) {
|
|
1533
1720
|
baseModules.set(name, modulePath);
|
|
1534
1721
|
}
|
|
1535
|
-
}
|
|
1722
|
+
};
|
|
1723
|
+
for (const name of defines) claim(name, claimRank(owner, true));
|
|
1724
|
+
for (const name of mentions) claim(name, claimRank(owner, false));
|
|
1536
1725
|
});
|
|
1537
|
-
return { classMap, baseModules };
|
|
1726
|
+
return { classMap, baseModules, ranks };
|
|
1538
1727
|
}
|
|
1539
1728
|
async function attributeClassesFromFile(entryFile, stylesDir, componentIds) {
|
|
1540
1729
|
try {
|
|
1541
|
-
const compiled = sass2.compile(entryFile, { sourceMap: true });
|
|
1730
|
+
const compiled = sass2.compile(entryFile, { sourceMap: true, ...sassPackageOptions(entryFile) });
|
|
1542
1731
|
if (!compiled.sourceMap) return null;
|
|
1543
1732
|
const consumer = new SourceMapConsumer(compiled.sourceMap);
|
|
1544
1733
|
const root = postcss3.parse(compiled.css);
|
|
1545
|
-
const { classMap } = extractClassesFromCompiled(consumer, root, entryFile, stylesDir, componentIds);
|
|
1546
|
-
return classMap;
|
|
1734
|
+
const { classMap, ranks } = extractClassesFromCompiled(consumer, root, entryFile, stylesDir, componentIds);
|
|
1735
|
+
return { classMap, ranks };
|
|
1547
1736
|
} catch {
|
|
1548
1737
|
return null;
|
|
1549
1738
|
}
|
|
1550
1739
|
}
|
|
1551
1740
|
async function patchClassOwnerIndex(entryFile, changedCompId, stylesDir, componentIds, index) {
|
|
1741
|
+
const ranks = indexRanks.get(index);
|
|
1552
1742
|
for (const [cls, owner] of index) {
|
|
1553
|
-
if (owner === changedCompId)
|
|
1743
|
+
if (owner === changedCompId) {
|
|
1744
|
+
index.delete(cls);
|
|
1745
|
+
ranks?.delete(cls);
|
|
1746
|
+
}
|
|
1554
1747
|
}
|
|
1555
1748
|
const fresh = await attributeClassesFromFile(entryFile, stylesDir, componentIds);
|
|
1556
1749
|
if (!fresh) return false;
|
|
1557
|
-
for (const [name, owner] of fresh) {
|
|
1558
|
-
if (owner
|
|
1750
|
+
for (const [name, owner] of fresh.classMap) {
|
|
1751
|
+
if (owner !== changedCompId) continue;
|
|
1752
|
+
const rank = fresh.ranks.get(name) ?? 0;
|
|
1753
|
+
const prev = ranks?.get(name);
|
|
1754
|
+
if (!index.has(name) || prev !== void 0 && rank > prev) {
|
|
1755
|
+
index.set(name, owner);
|
|
1756
|
+
ranks?.set(name, rank);
|
|
1757
|
+
}
|
|
1559
1758
|
}
|
|
1560
1759
|
return true;
|
|
1561
1760
|
}
|
|
@@ -1563,6 +1762,8 @@ async function buildAllStyleData(roots, componentIds, entryOverride) {
|
|
|
1563
1762
|
if (verboseTiming) console.time("[dev-server:timing] full classOwnerIndex build");
|
|
1564
1763
|
const styleUsesModules = /* @__PURE__ */ new Map();
|
|
1565
1764
|
const classIndex = /* @__PURE__ */ new Map();
|
|
1765
|
+
const classRanks = /* @__PURE__ */ new Map();
|
|
1766
|
+
indexRanks.set(classIndex, classRanks);
|
|
1566
1767
|
const baseProvenance = /* @__PURE__ */ new Map();
|
|
1567
1768
|
const componentCssBuckets = /* @__PURE__ */ new Map();
|
|
1568
1769
|
const baseCssByRoot = [];
|
|
@@ -1580,12 +1781,11 @@ async function buildAllStyleData(roots, componentIds, entryOverride) {
|
|
|
1580
1781
|
entryFiles = [...styleRoot.entries];
|
|
1581
1782
|
} else {
|
|
1582
1783
|
try {
|
|
1583
|
-
entryFiles = await collectScssFiles(stylesDir);
|
|
1784
|
+
entryFiles = (await collectScssFiles(stylesDir)).sort();
|
|
1584
1785
|
} catch {
|
|
1585
1786
|
entryFiles = [];
|
|
1586
1787
|
}
|
|
1587
1788
|
}
|
|
1588
|
-
entryFiles.sort();
|
|
1589
1789
|
for (const entryFile of entryFiles) {
|
|
1590
1790
|
let originPathFor2 = function(node) {
|
|
1591
1791
|
const pos = node.source?.start;
|
|
@@ -1595,18 +1795,18 @@ async function buildAllStyleData(roots, componentIds, entryOverride) {
|
|
|
1595
1795
|
column: pos.column - 1
|
|
1596
1796
|
});
|
|
1597
1797
|
if (!original.source) return null;
|
|
1598
|
-
return original.source.startsWith("file://") ? fileURLToPath2(original.source) :
|
|
1798
|
+
return original.source.startsWith("file://") ? fileURLToPath2(original.source) : resolve5(dirname3(entryFile), original.source);
|
|
1599
1799
|
};
|
|
1600
1800
|
var originPathFor = originPathFor2;
|
|
1601
1801
|
const compOwner = resolveScssToComponent(entryFile, stylesDir, componentIds);
|
|
1602
1802
|
let compiled;
|
|
1603
1803
|
try {
|
|
1604
|
-
compiled = sass2.compile(entryFile, { sourceMap: true });
|
|
1804
|
+
compiled = sass2.compile(entryFile, { sourceMap: true, ...sassPackageOptions(entryFile) });
|
|
1605
1805
|
} catch {
|
|
1606
1806
|
continue;
|
|
1607
1807
|
}
|
|
1608
1808
|
if (compOwner) {
|
|
1609
|
-
const deps = compiled.loadedUrls.filter((u) => u.protocol === "file:").map((u) => fileURLToPath2(u)).filter((p) =>
|
|
1809
|
+
const deps = compiled.loadedUrls.filter((u) => u.protocol === "file:").map((u) => fileURLToPath2(u)).filter((p) => resolve5(p) !== resolve5(entryFile));
|
|
1610
1810
|
for (const dep of deps) {
|
|
1611
1811
|
const depComp = resolveScssToComponent(dep, stylesDir, componentIds);
|
|
1612
1812
|
if (depComp !== null && depComp !== compOwner) {
|
|
@@ -1641,7 +1841,7 @@ async function buildAllStyleData(roots, componentIds, entryOverride) {
|
|
|
1641
1841
|
const nodeText = cssNodeText(node);
|
|
1642
1842
|
const owner = inBase(originPath) ? "__base__" : resolveScssToComponent(originPath, stylesDir, componentIds) ?? "__base__";
|
|
1643
1843
|
if (owner === "__base__") {
|
|
1644
|
-
baseCssBucket
|
|
1844
|
+
addLastOccurrence(baseCssBucket, nodeText);
|
|
1645
1845
|
if (reportOutside && !inBase(originPath)) {
|
|
1646
1846
|
const seen = outsideRules.get(originPath) ?? /* @__PURE__ */ new Set();
|
|
1647
1847
|
seen.add(nodeText);
|
|
@@ -1649,16 +1849,23 @@ async function buildAllStyleData(roots, componentIds, entryOverride) {
|
|
|
1649
1849
|
}
|
|
1650
1850
|
} else {
|
|
1651
1851
|
const bucket = componentCssBuckets.get(owner) ?? /* @__PURE__ */ new Set();
|
|
1652
|
-
bucket
|
|
1852
|
+
addLastOccurrence(bucket, nodeText);
|
|
1653
1853
|
componentCssBuckets.set(owner, bucket);
|
|
1654
1854
|
}
|
|
1655
1855
|
});
|
|
1656
|
-
const { classMap: perFileClasses, baseModules: perFileBaseModules } = extractClassesFromCompiled(consumer, root, entryFile, stylesDir, componentIds);
|
|
1856
|
+
const { classMap: perFileClasses, baseModules: perFileBaseModules, ranks: perFileRanks } = extractClassesFromCompiled(consumer, root, entryFile, stylesDir, componentIds);
|
|
1657
1857
|
for (const [name, owner] of perFileClasses) {
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
if (
|
|
1858
|
+
const rank = perFileRanks.get(name) ?? 0;
|
|
1859
|
+
const prev = classRanks.get(name);
|
|
1860
|
+
const mod = perFileBaseModules.get(name);
|
|
1861
|
+
if (prev === void 0 || rank > prev) {
|
|
1862
|
+
classIndex.set(name, owner);
|
|
1863
|
+
classRanks.set(name, rank);
|
|
1864
|
+
if (mod) baseProvenance.set(name, mod);
|
|
1865
|
+
else baseProvenance.delete(name);
|
|
1866
|
+
} else if (mod && classIndex.get(name) === "__base__" && !baseProvenance.has(name)) {
|
|
1867
|
+
baseProvenance.set(name, mod);
|
|
1868
|
+
}
|
|
1662
1869
|
}
|
|
1663
1870
|
}
|
|
1664
1871
|
baseCssByRoot[baseCssByRoot.length - 1] = [...baseCssBucket];
|
|
@@ -1688,7 +1895,7 @@ async function surfaceCollisions(collisions, cwd, hotreloader) {
|
|
|
1688
1895
|
hotreloader.push(messages[i]);
|
|
1689
1896
|
console.warn(`[dev-server] HANDLE_COLLISION: "${col.handle}" \u2014 incumbent: ${col.incumbentPath} \u2014 quarantined: ${col.quarantinedPath}`);
|
|
1690
1897
|
}
|
|
1691
|
-
if (collisions.length > 0) console.warn(`[dev-server] collisions listed in ${
|
|
1898
|
+
if (collisions.length > 0) console.warn(`[dev-server] collisions listed in ${join8(pdScratchDir(cwd), "CONFLICTS.generated.md")}`);
|
|
1692
1899
|
const md = collisions.length === 0 ? "# Conflicts\n\nNo handle collisions detected.\n" : [
|
|
1693
1900
|
"# Conflicts",
|
|
1694
1901
|
"",
|
|
@@ -1704,7 +1911,7 @@ async function surfaceCollisions(collisions, cwd, hotreloader) {
|
|
|
1704
1911
|
try {
|
|
1705
1912
|
const dir = pdScratchDir(cwd);
|
|
1706
1913
|
await mkdir(dir, { recursive: true });
|
|
1707
|
-
await writeFile(
|
|
1914
|
+
await writeFile(join8(dir, "CONFLICTS.generated.md"), md, "utf-8");
|
|
1708
1915
|
} catch (e) {
|
|
1709
1916
|
console.warn("[dev-server] Could not write CONFLICTS.generated.md to scratch dir:", e);
|
|
1710
1917
|
}
|
|
@@ -1725,12 +1932,12 @@ async function surfaceFlattening(discoveryMap, registry, cwd) {
|
|
|
1725
1932
|
const md = renderFlatteningReport(clusters);
|
|
1726
1933
|
if (clusters.length) {
|
|
1727
1934
|
const members = clusters.reduce((n, c3) => n + c3.members.length, 0);
|
|
1728
|
-
console.warn(`[dev-server] FLATTENED: ${clusters.length} cluster(s) across ${members} components \u2014 see ${
|
|
1935
|
+
console.warn(`[dev-server] FLATTENED: ${clusters.length} cluster(s) across ${members} components \u2014 see ${join8(pdScratchDir(cwd), "FLATTENED.generated.md")}`);
|
|
1729
1936
|
}
|
|
1730
1937
|
try {
|
|
1731
1938
|
const dir = pdScratchDir(cwd);
|
|
1732
1939
|
await mkdir(dir, { recursive: true });
|
|
1733
|
-
await writeFile(
|
|
1940
|
+
await writeFile(join8(dir, "FLATTENED.generated.md"), md, "utf-8");
|
|
1734
1941
|
} catch (e) {
|
|
1735
1942
|
console.warn("[dev-server] Could not write FLATTENED.generated.md to scratch dir:", e);
|
|
1736
1943
|
}
|
|
@@ -1747,11 +1954,21 @@ function surfaceDocumentBase(roots, outsideList, cwd) {
|
|
|
1747
1954
|
const examples = files.slice(0, 3).map(([path]) => relative3(cwd, path)).join(", ");
|
|
1748
1955
|
console.log(`[dev-server] base layer: ${rules} rule(s) from ${files.length} file(s) that no component owns and documentBase does not list, e.g. ${examples}`);
|
|
1749
1956
|
}
|
|
1957
|
+
function surfaceAssetRoots(assetRoots, cwd) {
|
|
1958
|
+
for (const { root, by } of shadowedAssetRoots(assetRoots)) {
|
|
1959
|
+
console.warn(`[dev-server] assets: ${relative3(cwd, root)} is hidden by ${relative3(cwd, by) || "."}, which has the same folder name; its files are not served`);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
function surfaceDefaultTheme(defaultTheme, themeNames) {
|
|
1963
|
+
if (!defaultTheme || themeNames.includes(defaultTheme)) return;
|
|
1964
|
+
const available = themeNames.length ? `available: ${[...themeNames].sort().join(", ")}` : "no theme folder is configured or provided by a package";
|
|
1965
|
+
console.warn(`[dev-server] themes.default "${defaultTheme}" matches no theme; ${available}`);
|
|
1966
|
+
}
|
|
1750
1967
|
|
|
1751
1968
|
// packages/dev-server/src/diagnostics.ts
|
|
1752
1969
|
import { createHash as createHash2 } from "node:crypto";
|
|
1753
1970
|
import { readFile as readFile6, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
1754
|
-
import { join as
|
|
1971
|
+
import { join as join9 } from "node:path";
|
|
1755
1972
|
|
|
1756
1973
|
// packages/a11y/src/producer.ts
|
|
1757
1974
|
import { createRequire } from "node:module";
|
|
@@ -1905,7 +2122,7 @@ function assembleGraph(audits) {
|
|
|
1905
2122
|
}
|
|
1906
2123
|
var GRAPH_ARTIFACT_VERSION = 1;
|
|
1907
2124
|
function graphArtifactPath(root) {
|
|
1908
|
-
return
|
|
2125
|
+
return join9(pdScratchDir(root), "diagnostics-graph.json");
|
|
1909
2126
|
}
|
|
1910
2127
|
async function readDiagnosticsArtifact(root) {
|
|
1911
2128
|
try {
|
|
@@ -1960,101 +2177,15 @@ async function persistSlices(root, slices, discoveryMap, globalData) {
|
|
|
1960
2177
|
await writeDiagnosticsArtifact(root, { version: GRAPH_ARTIFACT_VERSION, hashes, graph: assembleGraph([...slices.values()]) });
|
|
1961
2178
|
}
|
|
1962
2179
|
|
|
1963
|
-
// packages/dev-server/src/server-config.ts
|
|
1964
|
-
import { basename as basename2, join as join9, resolve as resolve5 } from "node:path";
|
|
1965
|
-
var DEFAULT_SWATCH_SLOTS = ["--bodyBackground", "--themePrimary", "--accent"];
|
|
1966
|
-
function resolveServerConfig(config, cwd, opts = {}, packages = []) {
|
|
1967
|
-
const port2 = opts.port ?? Number(process.env["PD_PORT"] ?? 4e3);
|
|
1968
|
-
const wsPort = opts.wsPort ?? Number(process.env["PD_WS_PORT"] ?? port2 + 1);
|
|
1969
|
-
const patternsDir = resolve5(cwd, config.patternsDir);
|
|
1970
|
-
const stylesDir = resolve5(cwd, config.styles.dir);
|
|
1971
|
-
const stylesEntries = config.styles.entry ? (Array.isArray(config.styles.entry) ? config.styles.entry : [config.styles.entry]).map((e) => resolve5(stylesDir, e)) : void 0;
|
|
1972
|
-
const inPackage = (p, rel) => join9(p.dir, rel);
|
|
1973
|
-
const asList = (v) => v === void 0 ? [] : Array.isArray(v) ? v : [v];
|
|
1974
|
-
const patternRoots = [
|
|
1975
|
-
{ dir: patternsDir, ...config.exclude?.length ? { exclude: config.exclude } : {} },
|
|
1976
|
-
...packages.filter((p) => p.manifest.patterns).map((p) => ({
|
|
1977
|
-
dir: inPackage(p, p.manifest.patterns),
|
|
1978
|
-
source: p.name,
|
|
1979
|
-
...p.exclude.length ? { exclude: p.exclude } : {}
|
|
1980
|
-
}))
|
|
1981
|
-
];
|
|
1982
|
-
const styleRoots = [
|
|
1983
|
-
{ dir: stylesDir, entries: stylesEntries, base: config.documentBase },
|
|
1984
|
-
...packages.filter((p) => p.manifest.styles).map((p) => {
|
|
1985
|
-
const dir = inPackage(p, p.manifest.styles.dir);
|
|
1986
|
-
const entries = asList(p.manifest.styles.entry).map((e) => resolve5(dir, e));
|
|
1987
|
-
return { dir, entries: entries.length ? entries : void 0, source: p.name, base: p.manifest.styles.documentBase };
|
|
1988
|
-
})
|
|
1989
|
-
];
|
|
1990
|
-
const themePackages = packages.filter((p) => p.manifest.themes);
|
|
1991
|
-
const themeDirs = [
|
|
1992
|
-
...config.themes ? [resolve5(cwd, config.themes.dir)] : [],
|
|
1993
|
-
...themePackages.map((p) => inPackage(p, p.manifest.themes.dir))
|
|
1994
|
-
];
|
|
1995
|
-
const switches = [config.themes?.switch, ...themePackages.map((p) => p.manifest.themes.switch)];
|
|
1996
|
-
const themeSwitch = switches.includes("stylesheet") ? "stylesheet" : "attribute";
|
|
1997
|
-
const assetRoots = [
|
|
1998
|
-
...asList(config.assets?.dir).map((d) => resolve5(cwd, d)),
|
|
1999
|
-
...packages.flatMap((p) => (p.manifest.assets ?? []).map((a) => inPackage(p, a)))
|
|
2000
|
-
];
|
|
2001
|
-
const globalScripts = [.../* @__PURE__ */ new Set([
|
|
2002
|
-
...packages.flatMap((p) => p.manifest.globalScripts ?? []),
|
|
2003
|
-
...config.globalScripts ?? []
|
|
2004
|
-
])];
|
|
2005
|
-
const scriptsDirs = [
|
|
2006
|
-
...config.scriptsDir ? [resolve5(cwd, config.scriptsDir)] : [],
|
|
2007
|
-
...packages.filter((p) => p.manifest.scripts).map((p) => inPackage(p, p.manifest.scripts))
|
|
2008
|
-
];
|
|
2009
|
-
const documentBaseEnabled = Array.isArray(config.documentBase) && config.documentBase.length > 0 || packages.some((p) => (p.manifest.styles?.documentBase?.length ?? 0) > 0);
|
|
2010
|
-
return {
|
|
2011
|
-
port: port2,
|
|
2012
|
-
wsPort,
|
|
2013
|
-
cwd,
|
|
2014
|
-
config,
|
|
2015
|
-
packages,
|
|
2016
|
-
patternRoots,
|
|
2017
|
-
patternDirs: patternRoots.map((r) => r.dir),
|
|
2018
|
-
styleRoots,
|
|
2019
|
-
dataDirs: [
|
|
2020
|
-
...packages.filter((p) => p.manifest.data).map((p) => inPackage(p, p.manifest.data)),
|
|
2021
|
-
...config.dataDir ? [resolve5(cwd, config.dataDir)] : []
|
|
2022
|
-
],
|
|
2023
|
-
helperPaths: [
|
|
2024
|
-
...packages.filter((p) => p.manifest.helpers).map((p) => inPackage(p, p.manifest.helpers)),
|
|
2025
|
-
...config.helpers ? [resolve5(cwd, config.helpers)] : []
|
|
2026
|
-
],
|
|
2027
|
-
scriptsDirs,
|
|
2028
|
-
patternsDir,
|
|
2029
|
-
stylesDir,
|
|
2030
|
-
stylesEntries,
|
|
2031
|
-
themeDirs,
|
|
2032
|
-
themesDir: themeDirs[0] ?? null,
|
|
2033
|
-
defaultTheme: config.themes?.default ?? themePackages[0]?.manifest.themes?.default,
|
|
2034
|
-
assetRoots,
|
|
2035
|
-
assetRootNames: assetRoots.map((r) => basename2(r)),
|
|
2036
|
-
assetsDir: assetRoots[0] ?? null,
|
|
2037
|
-
assetsCss: config.assets?.css ?? [],
|
|
2038
|
-
scriptsDir: scriptsDirs[0] ?? null,
|
|
2039
|
-
globalScripts,
|
|
2040
|
-
withGlobalScripts: (own) => [.../* @__PURE__ */ new Set([...globalScripts, ...own ?? []])],
|
|
2041
|
-
overviewsEnabled: config.overviews !== false,
|
|
2042
|
-
documentBaseEnabled,
|
|
2043
|
-
themeSwitch,
|
|
2044
|
-
swatchSlots: config.themes?.swatch?.slots ?? DEFAULT_SWATCH_SLOTS,
|
|
2045
|
-
packageSwatchSlots: DEFAULT_SWATCH_SLOTS
|
|
2046
|
-
};
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
2180
|
// packages/dev-server/src/packages.ts
|
|
2050
|
-
import { existsSync as
|
|
2051
|
-
import { dirname as
|
|
2181
|
+
import { existsSync as existsSync3, readFileSync } from "node:fs";
|
|
2182
|
+
import { dirname as dirname4, join as join10 } from "node:path";
|
|
2052
2183
|
function findPackageDir(name, root) {
|
|
2053
2184
|
let dir = root;
|
|
2054
2185
|
for (; ; ) {
|
|
2055
2186
|
const candidate = join10(dir, "node_modules", name);
|
|
2056
|
-
if (
|
|
2057
|
-
const parent =
|
|
2187
|
+
if (existsSync3(join10(candidate, "package.json"))) return candidate;
|
|
2188
|
+
const parent = dirname4(dir);
|
|
2058
2189
|
if (parent === dir) return null;
|
|
2059
2190
|
dir = parent;
|
|
2060
2191
|
}
|
|
@@ -2062,7 +2193,7 @@ function findPackageDir(name, root) {
|
|
|
2062
2193
|
function loadPatternPackages(references, root) {
|
|
2063
2194
|
const out = [];
|
|
2064
2195
|
const seen = /* @__PURE__ */ new Set();
|
|
2065
|
-
const visit = (name,
|
|
2196
|
+
const visit = (name, direct, from) => {
|
|
2066
2197
|
if (seen.has(name)) return;
|
|
2067
2198
|
const dir = findPackageDir(name, from);
|
|
2068
2199
|
if (!dir) {
|
|
@@ -2082,14 +2213,16 @@ function loadPatternPackages(references, root) {
|
|
|
2082
2213
|
version: pkg.version ?? "0.0.0",
|
|
2083
2214
|
dir,
|
|
2084
2215
|
manifest: pkg.patternDump,
|
|
2085
|
-
exclude: [...pkg.patternDump.exclude ?? [], ...
|
|
2086
|
-
direct
|
|
2216
|
+
exclude: [...pkg.patternDump.exclude ?? [], ...options.get(name)?.exclude ?? []],
|
|
2217
|
+
direct,
|
|
2218
|
+
styles: options.get(name)?.styles ?? true
|
|
2087
2219
|
});
|
|
2088
|
-
for (const peer of Object.keys(pkg.peerDependencies ?? {})) visit(peer,
|
|
2220
|
+
for (const peer of Object.keys(pkg.peerDependencies ?? {})) visit(peer, false, dir);
|
|
2089
2221
|
};
|
|
2222
|
+
const options = /* @__PURE__ */ new Map();
|
|
2223
|
+
for (const ref of references ?? []) if (typeof ref !== "string") options.set(ref.name, ref);
|
|
2090
2224
|
for (const ref of references ?? []) {
|
|
2091
|
-
|
|
2092
|
-
visit(name, exclude, true, root);
|
|
2225
|
+
visit(typeof ref === "string" ? ref : ref.name, true, root);
|
|
2093
2226
|
}
|
|
2094
2227
|
return out;
|
|
2095
2228
|
}
|
|
@@ -2125,7 +2258,7 @@ async function runDiagnosticsAudit(config, cwd) {
|
|
|
2125
2258
|
|
|
2126
2259
|
// packages/dev-server/src/static-build.ts
|
|
2127
2260
|
import { cp, mkdir as mkdir3, rm, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
|
|
2128
|
-
import { dirname as
|
|
2261
|
+
import { dirname as dirname5, join as join11, relative as relative4, resolve as resolve6, sep } from "node:path";
|
|
2129
2262
|
|
|
2130
2263
|
// packages/dev-server/src/http-utils.ts
|
|
2131
2264
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
@@ -2246,7 +2379,7 @@ async function buildStaticSite(config, root, opts) {
|
|
|
2246
2379
|
}
|
|
2247
2380
|
const type = res.headers.get("content-type") ?? "";
|
|
2248
2381
|
const target = diskPath(outDir, file);
|
|
2249
|
-
await mkdir3(
|
|
2382
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
2250
2383
|
if (isText(type)) {
|
|
2251
2384
|
const body = await res.text();
|
|
2252
2385
|
const out = withBasePath(body, basePath);
|
|
@@ -2266,7 +2399,7 @@ async function buildStaticSite(config, root, opts) {
|
|
|
2266
2399
|
if (done.has(file)) return;
|
|
2267
2400
|
done.add(file);
|
|
2268
2401
|
const target = diskPath(outDir, file);
|
|
2269
|
-
await mkdir3(
|
|
2402
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
2270
2403
|
const out = withBasePath(body, basePath);
|
|
2271
2404
|
await writeFile3(target, out);
|
|
2272
2405
|
report.bytes += Buffer.byteLength(out);
|
|
@@ -2329,7 +2462,13 @@ async function buildStaticSite(config, root, opts) {
|
|
|
2329
2462
|
} else {
|
|
2330
2463
|
log("\u2026 corpus audit left out (build.audit: false / --no-audit)");
|
|
2331
2464
|
}
|
|
2465
|
+
const shadowed = new Map(shadowedAssetRoots(cfg.assetRoots).map((s) => [s.root, s.by]));
|
|
2332
2466
|
for (const [i, rootDir] of cfg.assetRoots.entries()) {
|
|
2467
|
+
const by = shadowed.get(rootDir);
|
|
2468
|
+
if (by !== void 0) {
|
|
2469
|
+
report.warnings.push(`assets: ${relative4(root, rootDir)} is hidden by ${relative4(root, by) || "."}, which has the same folder name; left out`);
|
|
2470
|
+
continue;
|
|
2471
|
+
}
|
|
2333
2472
|
const exists = await stat2(rootDir).then((s) => s.isDirectory(), () => false);
|
|
2334
2473
|
if (!exists) continue;
|
|
2335
2474
|
await cp(rootDir, join11(outDir, "assets", cfg.assetRootNames[i]), { recursive: true });
|
|
@@ -2345,7 +2484,7 @@ async function buildStaticSite(config, root, opts) {
|
|
|
2345
2484
|
const shell = withBasePath(buildShellHtml(runtime), basePath);
|
|
2346
2485
|
for (const route of routes) {
|
|
2347
2486
|
const target = diskPath(outDir, staticPathFor(route));
|
|
2348
|
-
await mkdir3(
|
|
2487
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
2349
2488
|
await writeFile3(target, shell);
|
|
2350
2489
|
report.files++;
|
|
2351
2490
|
report.bytes += Buffer.byteLength(shell);
|
|
@@ -2361,11 +2500,11 @@ async function buildStaticSite(config, root, opts) {
|
|
|
2361
2500
|
|
|
2362
2501
|
// packages/dev-server/src/requires.ts
|
|
2363
2502
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
2364
|
-
import { existsSync as
|
|
2365
|
-
import { basename as
|
|
2503
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2504
|
+
import { basename as basename4, join as join12, relative as relative5 } from "node:path";
|
|
2366
2505
|
function normalizeScriptId(raw) {
|
|
2367
2506
|
let s = raw.trim().replace(/^\[(.+)\]$/, "$1").trim();
|
|
2368
|
-
s =
|
|
2507
|
+
s = basename4(s);
|
|
2369
2508
|
s = s.replace(/\.(ts|js)$/, "");
|
|
2370
2509
|
return s;
|
|
2371
2510
|
}
|
|
@@ -2430,7 +2569,7 @@ function hideSvg(svg) {
|
|
|
2430
2569
|
return svg.replace(/<svg(\s|>)/, '<svg$1style="display:none;position:absolute" aria-hidden="true" ');
|
|
2431
2570
|
}
|
|
2432
2571
|
async function reportUnresolvableScripts(discoveryMap, scriptsDirs, globalScripts, cwd) {
|
|
2433
|
-
const resolves = (id) => scriptsDirs.some((d) =>
|
|
2572
|
+
const resolves = (id) => scriptsDirs.some((d) => existsSync4(join12(d, `${id}.ts`)));
|
|
2434
2573
|
const where = scriptsDirs.length ? scriptsDirs.map((d) => relative5(cwd, d) || d).join(" or ") : "no scriptsDir configured";
|
|
2435
2574
|
for (const id of globalScripts) {
|
|
2436
2575
|
if (id.includes("://") || resolves(normalizeScriptId(id))) continue;
|
|
@@ -2493,9 +2632,9 @@ function applyStyleData(state, data) {
|
|
|
2493
2632
|
}
|
|
2494
2633
|
|
|
2495
2634
|
// packages/dev-server/src/routes.ts
|
|
2496
|
-
import { basename as
|
|
2635
|
+
import { basename as basename5, extname as extname2, join as join18, relative as relative6 } from "node:path";
|
|
2497
2636
|
import { readFile as readFile15, stat as stat4 } from "node:fs/promises";
|
|
2498
|
-
import { existsSync as
|
|
2637
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
2499
2638
|
|
|
2500
2639
|
// packages/dev-server/src/component-tree.ts
|
|
2501
2640
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
@@ -2880,7 +3019,7 @@ async function _resolveFence(info, content, idx, renderComponent, out, discovery
|
|
|
2880
3019
|
|
|
2881
3020
|
// packages/dev-server/src/css-closure.ts
|
|
2882
3021
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
2883
|
-
import { dirname as
|
|
3022
|
+
import { dirname as dirname6, resolve as resolve7 } from "node:path";
|
|
2884
3023
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
2885
3024
|
import postcss4 from "postcss";
|
|
2886
3025
|
import * as sass3 from "sass";
|
|
@@ -2888,7 +3027,7 @@ import { SourceMapConsumer as SourceMapConsumer2 } from "source-map";
|
|
|
2888
3027
|
import { parse as parseHtml2 } from "node-html-parser";
|
|
2889
3028
|
async function recomputeComponentCss(entryFile, compId, stylesDir, componentIds, inBase = () => false) {
|
|
2890
3029
|
try {
|
|
2891
|
-
const compiled = sass3.compile(entryFile, { sourceMap: true });
|
|
3030
|
+
const compiled = sass3.compile(entryFile, { sourceMap: true, ...sassPackageOptions(entryFile) });
|
|
2892
3031
|
const rawMap = compiled.sourceMap;
|
|
2893
3032
|
if (!rawMap) return null;
|
|
2894
3033
|
const consumer = new SourceMapConsumer2(rawMap);
|
|
@@ -2899,10 +3038,10 @@ async function recomputeComponentCss(entryFile, compId, stylesDir, componentIds,
|
|
|
2899
3038
|
if (!pos) return;
|
|
2900
3039
|
const original = consumer.originalPositionFor({ line: pos.line, column: pos.column - 1 });
|
|
2901
3040
|
if (!original.source) return;
|
|
2902
|
-
const originPath = original.source.startsWith("file://") ? fileURLToPath3(original.source) : resolve7(
|
|
3041
|
+
const originPath = original.source.startsWith("file://") ? fileURLToPath3(original.source) : resolve7(dirname6(entryFile), original.source);
|
|
2903
3042
|
if (inBase(originPath)) return;
|
|
2904
3043
|
const originComp = resolveScssToComponent(originPath, stylesDir, componentIds);
|
|
2905
|
-
if (originComp === compId) bucket
|
|
3044
|
+
if (originComp === compId) addLastOccurrence(bucket, cssNodeText(node));
|
|
2906
3045
|
});
|
|
2907
3046
|
return joinCssChunks(bucket);
|
|
2908
3047
|
} catch {
|
|
@@ -3238,10 +3377,10 @@ function normalizeAssetRefs(text, rootNames) {
|
|
|
3238
3377
|
}
|
|
3239
3378
|
|
|
3240
3379
|
// packages/dev-server/src/assets.ts
|
|
3241
|
-
import { existsSync as
|
|
3380
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
3242
3381
|
import { createRequire as createRequire2 } from "node:module";
|
|
3243
3382
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
3244
|
-
function resolveDevUiDist(moduleUrl, exists =
|
|
3383
|
+
function resolveDevUiDist(moduleUrl, exists = existsSync5) {
|
|
3245
3384
|
const packaged = fileURLToPath4(new URL("./dev-ui/", moduleUrl));
|
|
3246
3385
|
if (exists(`${packaged}main.js`)) return packaged;
|
|
3247
3386
|
return fileURLToPath4(new URL("../../../apps/dev-ui/dist/", moduleUrl));
|
|
@@ -3314,7 +3453,7 @@ async function handleRequest(req, res, ctx) {
|
|
|
3314
3453
|
return;
|
|
3315
3454
|
}
|
|
3316
3455
|
const themeName = decodeURIComponent(
|
|
3317
|
-
|
|
3456
|
+
basename5(pathname, ".css")
|
|
3318
3457
|
);
|
|
3319
3458
|
if (state.themeCss.has(themeName)) {
|
|
3320
3459
|
res.writeHead(200, { "Content-Type": "text/css" });
|
|
@@ -3331,10 +3470,10 @@ async function handleRequest(req, res, ctx) {
|
|
|
3331
3470
|
res.end("No scriptsDir configured");
|
|
3332
3471
|
return;
|
|
3333
3472
|
}
|
|
3334
|
-
const scriptId = normalizeScriptId(decodeURIComponent(
|
|
3473
|
+
const scriptId = normalizeScriptId(decodeURIComponent(basename5(pathname, ".js")));
|
|
3335
3474
|
try {
|
|
3336
3475
|
if (!state.scriptCache.has(scriptId)) {
|
|
3337
|
-
const entryPoint = scriptsDirs.map((d) => join18(d, `${scriptId}.ts`)).find((f) =>
|
|
3476
|
+
const entryPoint = scriptsDirs.map((d) => join18(d, `${scriptId}.ts`)).find((f) => existsSync6(f));
|
|
3338
3477
|
if (entryPoint === void 0) {
|
|
3339
3478
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
3340
3479
|
res.end(`No script "${scriptId}": scripts are TypeScript, so ${scriptId}.ts is expected in ` + scriptsDirs.map((d) => relative6(cwd, d) || d).join(" or "));
|
|
@@ -3623,12 +3762,12 @@ function describeBindError(e, port2, role, ports) {
|
|
|
3623
3762
|
}
|
|
3624
3763
|
|
|
3625
3764
|
// packages/dev-server/src/watch.ts
|
|
3626
|
-
import { basename as
|
|
3765
|
+
import { basename as basename6, extname as extname3, relative as relative7, resolve as resolve8 } from "node:path";
|
|
3627
3766
|
import chokidar from "chokidar";
|
|
3628
3767
|
function startWatching(ctx) {
|
|
3629
3768
|
const { cfg, state, render, tracker, hotreloader } = ctx;
|
|
3630
3769
|
const { patternsDir, stylesDir, styleRoots, patternRoots, patternDirs, swatchSlots, cwd } = cfg;
|
|
3631
|
-
const themesDir = cfg.config.themes ? cfg.themesDir : null;
|
|
3770
|
+
const themesDir = cfg.config.themes?.dir ? cfg.themesDir : null;
|
|
3632
3771
|
const scriptsDir = cfg.config.scriptsDir ? cfg.scriptsDirs[0] ?? null : null;
|
|
3633
3772
|
const inProjectBase = documentBaseMatcher(stylesDir, cfg.config.documentBase);
|
|
3634
3773
|
const watchDirs = [patternsDir, stylesDir, ...themesDir ? [themesDir] : [], ...scriptsDir ? [scriptsDir] : []];
|
|
@@ -3647,7 +3786,7 @@ function startWatching(ctx) {
|
|
|
3647
3786
|
hotreloader.push({
|
|
3648
3787
|
type: "error",
|
|
3649
3788
|
scope: "build",
|
|
3650
|
-
message: `SCSS ${
|
|
3789
|
+
message: `SCSS ${basename6(file)} \u2014 ${message.split("\n")[0]}`
|
|
3651
3790
|
});
|
|
3652
3791
|
}
|
|
3653
3792
|
state.scssGraphDirty = true;
|
|
@@ -3692,10 +3831,10 @@ function startWatching(ctx) {
|
|
|
3692
3831
|
}
|
|
3693
3832
|
const orderedHrefs = await closureHrefs(timestamp);
|
|
3694
3833
|
for (const m of pending) hotreloader.push({ ...m, orderedHrefs });
|
|
3695
|
-
console.log(`[dev-server] CSS updated (recompiled: ${effectiveFiles.map((f) =>
|
|
3834
|
+
console.log(`[dev-server] CSS updated (recompiled: ${effectiveFiles.map((f) => basename6(f)).join(", ")})`);
|
|
3696
3835
|
}
|
|
3697
3836
|
async function restyleAll(allIds, timestamp, files, hadCompileErrors) {
|
|
3698
|
-
const names = files.map((f) =>
|
|
3837
|
+
const names = files.map((f) => basename6(f)).join(", ");
|
|
3699
3838
|
if (hadCompileErrors) {
|
|
3700
3839
|
console.warn(`[dev-server] CSS not updated \u2014 compile errors (recompiled: ${names})`);
|
|
3701
3840
|
return;
|
|
@@ -3757,7 +3896,7 @@ function startWatching(ctx) {
|
|
|
3757
3896
|
}
|
|
3758
3897
|
if (ext === ".scss") {
|
|
3759
3898
|
if (themesDir && filePath.startsWith(themesDir)) {
|
|
3760
|
-
const themeName =
|
|
3899
|
+
const themeName = basename6(filePath, ".theme.scss");
|
|
3761
3900
|
try {
|
|
3762
3901
|
const css = await compileSassFile(filePath);
|
|
3763
3902
|
state.themeCss.set(themeName, css);
|
|
@@ -3793,7 +3932,7 @@ function startWatching(ctx) {
|
|
|
3793
3932
|
if (verboseTiming) console.log(`[dev-server:timing] diagnostics: live re-audit ${componentId} (1 component; total ${state.liveReauditCount})`);
|
|
3794
3933
|
}
|
|
3795
3934
|
} else if (ext === ".ts" && scriptsDir && filePath.startsWith(scriptsDir)) {
|
|
3796
|
-
const scriptId =
|
|
3935
|
+
const scriptId = basename6(filePath, ".ts");
|
|
3797
3936
|
state.scriptCache.delete(scriptId);
|
|
3798
3937
|
if (state.lastComponentId) {
|
|
3799
3938
|
hotreloader.push({ type: "content-swap", componentId: state.lastComponentId });
|
|
@@ -3839,7 +3978,7 @@ function startWatching(ctx) {
|
|
|
3839
3978
|
|
|
3840
3979
|
// packages/dev-server/src/export-io.ts
|
|
3841
3980
|
import { readFile as readFile16, writeFile as writeFile4, mkdir as mkdir4 } from "node:fs/promises";
|
|
3842
|
-
import { dirname as
|
|
3981
|
+
import { dirname as dirname7, join as join19, relative as relative8, resolve as resolve9 } from "node:path";
|
|
3843
3982
|
|
|
3844
3983
|
// packages/dev-server/src/export.ts
|
|
3845
3984
|
var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -4033,7 +4172,7 @@ async function writeExport(families, sink) {
|
|
|
4033
4172
|
for (const family of families) {
|
|
4034
4173
|
const baseRel = `${family.baseId}.hbs`;
|
|
4035
4174
|
const basePath = join19(sink, baseRel);
|
|
4036
|
-
await mkdir4(
|
|
4175
|
+
await mkdir4(dirname7(basePath), { recursive: true });
|
|
4037
4176
|
await writeFile4(basePath, family.baseHbs, "utf-8");
|
|
4038
4177
|
files.push(baseRel);
|
|
4039
4178
|
if (family.baseData) {
|
|
@@ -4078,7 +4217,7 @@ async function writeThreadedIncluders(threaded, patternsDir, sink) {
|
|
|
4078
4217
|
rewrites += res.rewrites;
|
|
4079
4218
|
const rel = relative8(patternsDir, hbsPath);
|
|
4080
4219
|
const outPath = join19(sink, rel);
|
|
4081
|
-
await mkdir4(
|
|
4220
|
+
await mkdir4(dirname7(outPath), { recursive: true });
|
|
4082
4221
|
await writeFile4(outPath, res.hbs, "utf-8");
|
|
4083
4222
|
files.push(rel);
|
|
4084
4223
|
}
|
|
@@ -4238,7 +4377,7 @@ async function startDevServer(config, cwd, opts = {}) {
|
|
|
4238
4377
|
try {
|
|
4239
4378
|
const css = await compileSassFile(join20(dir, `${name}.theme.scss`));
|
|
4240
4379
|
state.themeCss.set(name, css);
|
|
4241
|
-
const slots = config.themes && dir === cfg.themeDirs[0] ? swatchSlots : cfg.packageSwatchSlots;
|
|
4380
|
+
const slots = config.themes?.dir && dir === cfg.themeDirs[0] ? swatchSlots : cfg.packageSwatchSlots;
|
|
4242
4381
|
state.themeTokens.set(name, await extractThemeTokens(name, css, slots, dir));
|
|
4243
4382
|
} catch (e) {
|
|
4244
4383
|
console.warn(`[dev-server] Theme compile error (${name}):`, e);
|
|
@@ -4247,6 +4386,7 @@ async function startDevServer(config, cwd, opts = {}) {
|
|
|
4247
4386
|
}
|
|
4248
4387
|
}
|
|
4249
4388
|
}
|
|
4389
|
+
surfaceDefaultTheme(cfg.defaultTheme, [...state.themeCss.keys()]);
|
|
4250
4390
|
{
|
|
4251
4391
|
const dr = await buildDiscoveryMap(patternRoots);
|
|
4252
4392
|
state.discoveryResult = dr;
|
|
@@ -4260,6 +4400,7 @@ async function startDevServer(config, cwd, opts = {}) {
|
|
|
4260
4400
|
const styleData = await buildAllStyleData(styleRoots, allComponentIds);
|
|
4261
4401
|
applyStyleData(state, styleData);
|
|
4262
4402
|
surfaceDocumentBase(styleRoots, styleData.baseOutsideList, cwd);
|
|
4403
|
+
surfaceAssetRoots(cfg.assetRoots, cwd);
|
|
4263
4404
|
await reportUnresolvableScripts(dr.discoveryMap, cfg.scriptsDirs, cfg.globalScripts, cwd);
|
|
4264
4405
|
}
|
|
4265
4406
|
const boot = {
|
|
@@ -4301,9 +4442,9 @@ async function startDevServer(config, cwd, opts = {}) {
|
|
|
4301
4442
|
|
|
4302
4443
|
// packages/core/src/index.ts
|
|
4303
4444
|
import { build as esbuild } from "esbuild";
|
|
4304
|
-
import { existsSync as
|
|
4445
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
4305
4446
|
import { readFile as readFile17, writeFile as writeFile5, unlink, mkdir as mkdir5 } from "node:fs/promises";
|
|
4306
|
-
import { join as join21, dirname as
|
|
4447
|
+
import { join as join21, dirname as dirname8, resolve as resolve10, relative as relative9, isAbsolute } from "node:path";
|
|
4307
4448
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
4308
4449
|
import { createHash as createHash3 } from "node:crypto";
|
|
4309
4450
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -4331,7 +4472,7 @@ async function runAudit(root, configPath, format = "md") {
|
|
|
4331
4472
|
const { graph, reaudited, reused, artifactPath } = await runDiagnosticsAudit(config, root);
|
|
4332
4473
|
const report = formatAudit(graph, format);
|
|
4333
4474
|
const ext = format === "json" ? "json" : format === "text" ? "txt" : "md";
|
|
4334
|
-
const reportPath = join21(
|
|
4475
|
+
const reportPath = join21(dirname8(artifactPath), `diagnostics-report.${ext}`);
|
|
4335
4476
|
await writeFile5(reportPath, report, "utf-8");
|
|
4336
4477
|
console.log(report);
|
|
4337
4478
|
const affected = new Set(graph.occurrences.map((o) => o.component)).size;
|
|
@@ -4417,14 +4558,14 @@ async function runExport(root, configPath, outDir) {
|
|
|
4417
4558
|
}
|
|
4418
4559
|
async function loadConfig(root, configPath) {
|
|
4419
4560
|
if (configPath) {
|
|
4420
|
-
if (!
|
|
4561
|
+
if (!existsSync7(configPath)) {
|
|
4421
4562
|
throw new ConfigError(`--config file not found: ${configPath}`);
|
|
4422
4563
|
}
|
|
4423
4564
|
return validateConfig(await readConfigFile(configPath), configPath);
|
|
4424
4565
|
}
|
|
4425
4566
|
for (const name of ["pattern-dump.config.ts", "pattern-dump.config.json"]) {
|
|
4426
4567
|
const path = join21(root, name);
|
|
4427
|
-
if (
|
|
4568
|
+
if (existsSync7(path)) return validateConfig(await readConfigFile(path), name);
|
|
4428
4569
|
}
|
|
4429
4570
|
throw new ConfigError(
|
|
4430
4571
|
`No pattern-dump.config.ts or pattern-dump.config.json found in ${root} (and no --config given)`
|
|
@@ -4639,14 +4780,14 @@ var USAGE = `Usage: pd <command> [options]
|
|
|
4639
4780
|
help [command] Show this help`;
|
|
4640
4781
|
|
|
4641
4782
|
// packages/cli/src/init/run.ts
|
|
4642
|
-
import { existsSync as
|
|
4783
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
4643
4784
|
import { readFile as readFile19 } from "node:fs/promises";
|
|
4644
|
-
import { basename as
|
|
4785
|
+
import { basename as basename7, dirname as dirname10, join as join23, relative as relative11, resolve as resolve12 } from "node:path";
|
|
4645
4786
|
|
|
4646
4787
|
// packages/cli/package.json
|
|
4647
4788
|
var package_default = {
|
|
4648
4789
|
name: "@pattern-dump/cli",
|
|
4649
|
-
version: "0.1.0-alpha.
|
|
4790
|
+
version: "0.1.0-alpha.4",
|
|
4650
4791
|
private: true,
|
|
4651
4792
|
description: "The pd command and the published pattern-dump package.",
|
|
4652
4793
|
type: "module",
|
|
@@ -4682,7 +4823,7 @@ var PD_VERSION = package_default.version;
|
|
|
4682
4823
|
|
|
4683
4824
|
// packages/cli/src/init/files.ts
|
|
4684
4825
|
import { mkdir as mkdir6, readdir as readdir5, readFile as readFile18, writeFile as writeFile6 } from "node:fs/promises";
|
|
4685
|
-
import { dirname as
|
|
4826
|
+
import { dirname as dirname9, join as join22, relative as relative10, sep as sep2 } from "node:path";
|
|
4686
4827
|
async function readTemplateDir(dir) {
|
|
4687
4828
|
const out = [];
|
|
4688
4829
|
async function walk(current) {
|
|
@@ -4706,7 +4847,7 @@ async function applyPlan(target, plan) {
|
|
|
4706
4847
|
await mkdir6(target, { recursive: true });
|
|
4707
4848
|
for (const file of plan.writes) {
|
|
4708
4849
|
const abs = join22(target, file.path);
|
|
4709
|
-
await mkdir6(
|
|
4850
|
+
await mkdir6(dirname9(abs), { recursive: true });
|
|
4710
4851
|
await writeFile6(abs, file.content, { flag: "wx" });
|
|
4711
4852
|
}
|
|
4712
4853
|
await writeFile6(join22(target, "package.json"), plan.packageJson.content);
|
|
@@ -4789,12 +4930,12 @@ function mergePackageJson(current, answers, packageName) {
|
|
|
4789
4930
|
function dependencySpec(pdSource, cwd) {
|
|
4790
4931
|
if (pdSource === void 0) return `^${PD_VERSION}`;
|
|
4791
4932
|
const asPath = resolve12(cwd, pdSource);
|
|
4792
|
-
if (
|
|
4933
|
+
if (existsSync8(asPath)) return `file:${asPath}`;
|
|
4793
4934
|
return pdSource.startsWith(`${PD_PACKAGE_NAME}@`) ? pdSource.slice(PD_PACKAGE_NAME.length + 1) : pdSource;
|
|
4794
4935
|
}
|
|
4795
4936
|
async function insideGitRepo(target, io) {
|
|
4796
4937
|
let dir = target;
|
|
4797
|
-
while (!
|
|
4938
|
+
while (!existsSync8(dir) && dirname10(dir) !== dir) dir = dirname10(dir);
|
|
4798
4939
|
return await io.run("git", ["rev-parse", "--is-inside-work-tree"], dir) === 0;
|
|
4799
4940
|
}
|
|
4800
4941
|
async function runInit(cmd, io) {
|
|
@@ -4819,7 +4960,7 @@ async function runInit(cmd, io) {
|
|
|
4819
4960
|
}
|
|
4820
4961
|
const pkgPath = join23(target, "package.json");
|
|
4821
4962
|
let packageJson = null;
|
|
4822
|
-
if (
|
|
4963
|
+
if (existsSync8(pkgPath)) {
|
|
4823
4964
|
try {
|
|
4824
4965
|
packageJson = JSON.parse(await readFile19(pkgPath, "utf8"));
|
|
4825
4966
|
} catch (e) {
|
|
@@ -4829,7 +4970,7 @@ async function runInit(cmd, io) {
|
|
|
4829
4970
|
}
|
|
4830
4971
|
const prompt = io.interactive && !cmd.yes;
|
|
4831
4972
|
const existingName = typeof packageJson?.name === "string" ? packageJson.name : void 0;
|
|
4832
|
-
const name = cmd.name ?? (prompt ? await io.ask("Project name", existingName ?? toPackageName(
|
|
4973
|
+
const name = cmd.name ?? (prompt ? await io.ask("Project name", existingName ?? toPackageName(basename7(target))) : existingName ?? toPackageName(basename7(target)));
|
|
4833
4974
|
const brand = cmd.brand ?? (prompt ? await io.ask("Title in the Nav Rail", name) : name);
|
|
4834
4975
|
const examples = cmd.examples ?? (prompt ? await io.confirm("Include starter components", true) : true);
|
|
4835
4976
|
const gitDefault = !await insideGitRepo(target, io);
|
|
@@ -4837,7 +4978,7 @@ async function runInit(cmd, io) {
|
|
|
4837
4978
|
const install = cmd.install ?? (prompt ? await io.confirm("Run npm install", true) : true);
|
|
4838
4979
|
const answers = { name, brand, examples, dependency };
|
|
4839
4980
|
const templates = await readTemplates(io.templatesDir);
|
|
4840
|
-
const result = planInit(templates, answers, { packageJson, exists: (p) =>
|
|
4981
|
+
const result = planInit(templates, answers, { packageJson, exists: (p) => existsSync8(join23(target, p)) }, PD_PACKAGE_NAME);
|
|
4841
4982
|
if (!result.ok) {
|
|
4842
4983
|
io.log(`\u2717 ${result.reason}`);
|
|
4843
4984
|
return 1;
|
|
@@ -4877,7 +5018,7 @@ async function runInit(cmd, io) {
|
|
|
4877
5018
|
}
|
|
4878
5019
|
|
|
4879
5020
|
// packages/cli/src/init/local-build.ts
|
|
4880
|
-
import { existsSync as
|
|
5021
|
+
import { existsSync as existsSync9, statSync } from "node:fs";
|
|
4881
5022
|
import { join as join24 } from "node:path";
|
|
4882
5023
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
4883
5024
|
var BUILT = [
|
|
@@ -4896,9 +5037,9 @@ var mtime = (path) => {
|
|
|
4896
5037
|
};
|
|
4897
5038
|
function detectLocalBuild(moduleUrl, packageName, version) {
|
|
4898
5039
|
const repo = fileURLToPath6(new URL("../../../", moduleUrl)).replace(/[\\/]$/, "");
|
|
4899
|
-
if (!
|
|
5040
|
+
if (!existsSync9(join24(repo, "packages/cli/src/distribution.ts"))) return null;
|
|
4900
5041
|
const tarball = join24(repo, ".pd-pack", `${packageName}-${version}.tgz`);
|
|
4901
|
-
if (!
|
|
5042
|
+
if (!existsSync9(tarball)) return { repo, tarball: null, stale: false };
|
|
4902
5043
|
const newestBuild = Math.max(...BUILT.map((p) => mtime(join24(repo, p))));
|
|
4903
5044
|
return { repo, tarball, stale: newestBuild > mtime(tarball) };
|
|
4904
5045
|
}
|
|
@@ -37,9 +37,10 @@ export interface StylesConfig {
|
|
|
37
37
|
entry?: string | string[];
|
|
38
38
|
}
|
|
39
39
|
export interface ThemesConfig {
|
|
40
|
-
/** Directory of theme files (custom-property value-sets).
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
/** Directory of the project's own theme files (custom-property value-sets). Leave it out to use
|
|
41
|
+
* only the themes pattern packages provide, with `default` naming one of them. */
|
|
42
|
+
dir?: string;
|
|
43
|
+
/** Default theme name applied via data-theme on the preview body: a project theme or a package's. */
|
|
43
44
|
default: string;
|
|
44
45
|
/** Switch wiring: attribute toggle (default) or per-theme stylesheet swap. */
|
|
45
46
|
switch?: ThemeSwitch;
|
|
@@ -66,10 +67,17 @@ export interface ShellConfig {
|
|
|
66
67
|
* invoking `cwd`. This holds even when the file is supplied via `--config` from outside the
|
|
67
68
|
* root — which is what lets PD open a read-only project it does not own.
|
|
68
69
|
*/
|
|
69
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* A pattern package named in the config: the npm name, or the name plus options.
|
|
72
|
+
* - `exclude`: extra globs of the package's templates to hide.
|
|
73
|
+
* - `styles: false`: leave the package's stylesheets out (its templates, data, themes, scripts and
|
|
74
|
+
* assets are still used), e.g. when the project compiles that CSS itself. A package reached only
|
|
75
|
+
* as another package's peer can be named here just to carry this option.
|
|
76
|
+
*/
|
|
70
77
|
export type PackageReference = string | {
|
|
71
78
|
name: string;
|
|
72
79
|
exclude?: string[];
|
|
80
|
+
styles?: boolean;
|
|
73
81
|
};
|
|
74
82
|
export interface PatternDumpConfig {
|
|
75
83
|
sourceDir: string;
|
|
@@ -70,7 +70,7 @@ export interface TreeNode {
|
|
|
70
70
|
children?: TreeNode[];
|
|
71
71
|
}
|
|
72
72
|
export type DiagnosticSeverity = "error" | "warning" | "info";
|
|
73
|
-
export type DiagnosticKind = "RENDER_ERROR" | "UNFILLED_REQUIRED" | "SHAPE_MISMATCH" | "HTML_INVALID" | "CASCADE_WARNING" | "A11Y" | "HIGHLIGHT_FALLBACK" | "HANDLE_COLLISION";
|
|
73
|
+
export type DiagnosticKind = "RENDER_ERROR" | "UNFILLED_REQUIRED" | "SHAPE_MISMATCH" | "HTML_INVALID" | "CASCADE_WARNING" | "A11Y" | "HIGHLIGHT_FALLBACK" | "HANDLE_COLLISION" | "DATA_INVALID";
|
|
74
74
|
/** Fields every diagnostic carries, whichever engine produced it. */
|
|
75
75
|
interface DiagnosticBase {
|
|
76
76
|
severity: DiagnosticSeverity;
|
|
@@ -81,7 +81,7 @@ interface DiagnosticBase {
|
|
|
81
81
|
ruleId?: string;
|
|
82
82
|
/** JSON Schema / data pointer, e.g. "#/properties/label" — schema kinds only. */
|
|
83
83
|
path?: string;
|
|
84
|
-
/** Source-file position — RENDER_ERROR, best-effort. */
|
|
84
|
+
/** Source-file position — RENDER_ERROR and DATA_INVALID, best-effort. */
|
|
85
85
|
location?: {
|
|
86
86
|
file?: string;
|
|
87
87
|
line?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pattern-dump",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "A workbench for HTML and CSS design systems: live component previews, docs, checks and static publishing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"markdown-it": "^14.2.0",
|
|
70
70
|
"node-html-parser": "^7.1.0",
|
|
71
71
|
"postcss": "^8.5.15",
|
|
72
|
+
"postcss-selector-parser": "^7.1.1",
|
|
72
73
|
"sass": "^1.100.0",
|
|
73
74
|
"shiki": "^4.1.0",
|
|
74
75
|
"source-map": "^0.6.1",
|