dowel-ui 0.13.0 → 0.14.1

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 CHANGED
@@ -155,6 +155,32 @@ against a baseline, and a check that it carries no word of its own to translate
155
155
 
156
156
  Full vocabulary, shown rather than tabulated: **[colours](https://lacodda.github.io/dowel/reference/tokens/)** in both themes, **[the scales](https://lacodda.github.io/dowel/reference/scales/)** - radius, type, motion, elevation and stacking order - and **[the accents](https://lacodda.github.io/dowel/reference/accents/)**, where the same screen is drawn in every colour of the line.
157
157
 
158
+ ## Moving an existing project over
159
+
160
+ A product arriving at dowel almost never arrives from nothing - it arrives from
161
+ stock shadcn/ui, whose theme names colours by their role in a page
162
+ (`--background`, `--muted-foreground`) where dowel names them by what they are
163
+ on a screen. The package ships the tools for that crossing:
164
+
165
+ ```console
166
+ $ npx dowel check # what is not on the dowel vocabulary yet
167
+ $ npx dowel codemod --write # rewrite the names that can be rewritten
168
+ $ npx dowel doctor # whether the installation itself is wired right
169
+ $ npx dowel diff dialog # what you changed since you copied it in
170
+ ```
171
+
172
+ `check`, `doctor` and `diff` only read; `codemod` writes, and only when asked
173
+ twice. Everything reads the catalogue inside the installed package, so none of
174
+ it needs the network.
175
+
176
+ Two things are deliberately never rewritten, and the tools say so rather than
177
+ guessing: a colour, because which token it was reaching for is a decision; and
178
+ `--accent`, because it is the one name both vocabularies use for opposite
179
+ things - stock's hover fill and dowel's product hue. The first run of `check`
180
+ against dowel's own stand reported twenty-four violations that were all correct
181
+ code, which is exactly how that rule was learned - see
182
+ [the migration guide](https://lacodda.github.io/dowel/guides/migration/).
183
+
158
184
  ## Roadmap
159
185
 
160
186
  Development goes in versions; each one is a single coherent theme, and ends in a release.
@@ -173,6 +199,7 @@ Development goes in versions; each one is a single coherent theme, and ends in a
173
199
 
174
200
  - [The stand](https://lacodda.github.io/dowel/stand/) - every component, live
175
201
  - [Getting started](https://lacodda.github.io/dowel/getting-started/), [the lint rules](https://lacodda.github.io/dowel/guides/linting/) and [what a component has to pass](https://lacodda.github.io/dowel/guides/gates/)
202
+ - [Moving from stock shadcn](https://lacodda.github.io/dowel/guides/migration/) - the four commands and what they refuse to do
176
203
  - [Components](https://lacodda.github.io/dowel/components/button/)
177
204
  - [Tokens](https://lacodda.github.io/dowel/reference/tokens/), [scales](https://lacodda.github.io/dowel/reference/scales/) and [accents](https://lacodda.github.io/dowel/reference/accents/)
178
205
  - [The vocabulary](https://lacodda.github.io/dowel/concepts/vocabulary/) this system uses for its own parts, and [the mistakes](https://lacodda.github.io/dowel/concepts/anti-patterns/) that actually get made against it
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { run } from './index.js';
3
+ /*
4
+ * The executable. Deliberately three lines: everything worth testing lives in
5
+ * `index.ts` and returns an exit code instead of calling `process.exit`, so a
6
+ * test can run a whole command without the runner exiting underneath it.
7
+ */
8
+ process.exitCode = run(process.argv.slice(2));
9
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAEhC;;;;GAIG;AAEH,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,22 @@
1
+ /** One substitution made in one place. */
2
+ export interface Change {
3
+ readonly line: number;
4
+ readonly from: string;
5
+ readonly to: string;
6
+ }
7
+ /** What the codemod did to one file, and what it declined to do. */
8
+ export interface Rewrite {
9
+ readonly source: string;
10
+ readonly changes: Change[];
11
+ /** Stock names left alone because the table has no equivalent. These are
12
+ * the reason a run can be "successful" and still not finished. */
13
+ readonly skipped: {
14
+ readonly line: number;
15
+ readonly name: string;
16
+ readonly note: string;
17
+ }[];
18
+ }
19
+ /** Rewrite one file's text. Returns the new source and an account of what
20
+ * happened - the caller decides whether to write it. */
21
+ export declare function rewriteSource(source: string): Rewrite;
22
+ //# sourceMappingURL=codemod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codemod.d.ts","sourceRoot":"","sources":["../../src/cli/codemod.ts"],"names":[],"mappings":"AAsBA,0CAA0C;AAC1C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED,oEAAoE;AACpE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;IAC1B;sEACkE;IAClE,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC5F;AAwCD;wDACwD;AACxD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAmCrD"}
@@ -0,0 +1,69 @@
1
+ import { stockNames, stockTokens } from './stock.js';
2
+ /** The 1-based line an offset falls on. */
3
+ function lineAt(source, index) {
4
+ let line = 1;
5
+ for (let i = 0; i < index; i += 1) {
6
+ if (source.charCodeAt(i) === 10 /* \n */)
7
+ line += 1;
8
+ }
9
+ return line;
10
+ }
11
+ /*
12
+ * The two shapes a stock name takes, as one pass.
13
+ *
14
+ * They are matched together rather than in two passes for a reason that cost
15
+ * an hour elsewhere in this repository: a second pass reads the output of the
16
+ * first, so a rename whose result contains another stock name gets renamed
17
+ * twice. `--accent` is exactly that case - stock `--accent` becomes `--soft`,
18
+ * and dowel's own `--accent` is a name the table also knows. One pass over the
19
+ * original text cannot double-apply.
20
+ *
21
+ * Alternation order is `stockNames`, which is longest-first, so `--sidebar-border`
22
+ * is matched whole rather than as `--sidebar` with a tail left behind.
23
+ */
24
+ const UTILITY_PREFIXES = 'bg|text|border|fill|stroke|ring|outline|divide|shadow|from|via|to|accent|caret|decoration';
25
+ function pattern() {
26
+ const names = stockNames.join('|');
27
+ return new RegExp(
28
+ // A custom property: `--muted-foreground`, in a stylesheet or in `var()`.
29
+ `--(?<property>${names})\\b` +
30
+ '|' +
31
+ // A utility: `bg-muted`, `hover:text-muted-foreground`. The opener is
32
+ // consumed so that `custom-bg-muted` does not match, and put back.
33
+ `(?<opener>^|[\\s"'\`:\\[({])(?<prefix>${UTILITY_PREFIXES})-(?<utility>${names})\\b`, 'gm');
34
+ }
35
+ /** Rewrite one file's text. Returns the new source and an account of what
36
+ * happened - the caller decides whether to write it. */
37
+ export function rewriteSource(source) {
38
+ const changes = [];
39
+ const skipped = [];
40
+ const next = source.replace(pattern(), (match, ...args) => {
41
+ // The named groups arrive last; the offset is two from the end, before the
42
+ // whole string and the groups object.
43
+ const groups = args[args.length - 1];
44
+ const offset = args[args.length - 3];
45
+ const line = lineAt(source, offset);
46
+ const property = groups.property;
47
+ if (property) {
48
+ const replacement = stockTokens[property];
49
+ if (replacement.kind !== 'token') {
50
+ skipped.push({ line, name: `--${property}`, note: replacement.note });
51
+ return match;
52
+ }
53
+ changes.push({ line, from: `--${property}`, to: `--${replacement.token}` });
54
+ return `--${replacement.token}`;
55
+ }
56
+ const utility = groups.utility;
57
+ const prefix = groups.prefix;
58
+ const opener = groups.opener ?? '';
59
+ const replacement = stockTokens[utility];
60
+ if (replacement.kind !== 'token') {
61
+ skipped.push({ line, name: `${prefix}-${utility}`, note: replacement.note });
62
+ return match;
63
+ }
64
+ changes.push({ line, from: `${prefix}-${utility}`, to: `${prefix}-${replacement.token}` });
65
+ return `${opener}${prefix}-${replacement.token}`;
66
+ });
67
+ return { source: next, changes, skipped };
68
+ }
69
+ //# sourceMappingURL=codemod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codemod.js","sourceRoot":"","sources":["../../src/cli/codemod.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /** One line of a diff. */
2
+ export interface DiffLine {
3
+ readonly kind: 'same' | 'added' | 'removed';
4
+ readonly text: string;
5
+ }
6
+ /** A run of changed lines with a little context, as a diff is normally read. */
7
+ export interface Hunk {
8
+ /** 1-based line number in the registry's copy where this hunk starts. */
9
+ readonly fromLine: number;
10
+ /** 1-based line number in the project's copy where this hunk starts. */
11
+ readonly toLine: number;
12
+ readonly lines: readonly DiffLine[];
13
+ }
14
+ /** Every line of both files, marked. */
15
+ export declare function diffLines(from: string, to: string): DiffLine[];
16
+ /** Group the marked lines into hunks with `context` unchanged lines around
17
+ * each run of changes. A component that differs in two places should print two
18
+ * short passages, not four hundred lines with a mark in the margin. */
19
+ export declare function hunks(marked: readonly DiffLine[], context?: number): Hunk[];
20
+ /** Whether two files differ at all, ignoring line endings. Cheaper than
21
+ * diffing, and it is the question asked first. */
22
+ export declare function differs(from: string, to: string): boolean;
23
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"AAoBA,0BAA0B;AAC1B,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,gFAAgF;AAChF,MAAM,WAAW,IAAI;IACnB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CACpC;AAwBD,wCAAwC;AACxC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,EAAE,CA8B9D;AAED;;uEAEuE;AACvE,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,OAAO,SAAI,GAAG,IAAI,EAAE,CAwCtE;AAED;kDACkD;AAClD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,122 @@
1
+ /*
2
+ * What has this project done to a component since it was copied in?
3
+ *
4
+ * The registry's whole promise is that a component becomes your file. That is
5
+ * a real freedom and it has a real cost: nothing upstream reaches back in, and
6
+ * nothing tells you what you changed. A year later, a component is different
7
+ * from the one that shipped and there is no record of whether that is your
8
+ * deliberate edit or a fix you never received.
9
+ *
10
+ * `diff` answers exactly that, from the catalogue inside the installed
11
+ * package: here is the file the registry serves, here is yours, here is where
12
+ * they part. It does not merge, and it will not offer to - the copy is the
13
+ * consumer's, and a tool that silently reconciled it would be taking back the
14
+ * thing the registry gave.
15
+ *
16
+ * The algorithm is a plain longest-common-subsequence over lines. A component
17
+ * is a few hundred lines; the quadratic cost is invisible, and the output is
18
+ * the one every reader already knows how to read.
19
+ */
20
+ /** Line endings are normalised before comparing.
21
+ *
22
+ * A checkout on Windows hands back CRLF for a file the registry serves with
23
+ * LF, and without this every single line of every component would differ - a
24
+ * report that is technically true and completely useless. The registry builder
25
+ * normalises for the same reason at the other end. */
26
+ function lines(text) {
27
+ return text.replace(/\r\n/g, '\n').split('\n');
28
+ }
29
+ /** The classic table. `common[i][j]` is the length of the longest common
30
+ * subsequence of the first `i` lines of `a` and the first `j` of `b`. */
31
+ function commonTable(a, b) {
32
+ const table = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
33
+ for (let i = a.length - 1; i >= 0; i -= 1) {
34
+ for (let j = b.length - 1; j >= 0; j -= 1) {
35
+ table[i][j] = a[i] === b[j] ? table[i + 1][j + 1] + 1 : Math.max(table[i + 1][j], table[i][j + 1]);
36
+ }
37
+ }
38
+ return table;
39
+ }
40
+ /** Every line of both files, marked. */
41
+ export function diffLines(from, to) {
42
+ const a = lines(from);
43
+ const b = lines(to);
44
+ const table = commonTable(a, b);
45
+ const out = [];
46
+ let i = 0;
47
+ let j = 0;
48
+ while (i < a.length && j < b.length) {
49
+ if (a[i] === b[j]) {
50
+ out.push({ kind: 'same', text: a[i] });
51
+ i += 1;
52
+ j += 1;
53
+ }
54
+ else if (table[i + 1][j] >= table[i][j + 1]) {
55
+ out.push({ kind: 'removed', text: a[i] });
56
+ i += 1;
57
+ }
58
+ else {
59
+ out.push({ kind: 'added', text: b[j] });
60
+ j += 1;
61
+ }
62
+ }
63
+ while (i < a.length) {
64
+ out.push({ kind: 'removed', text: a[i] });
65
+ i += 1;
66
+ }
67
+ while (j < b.length) {
68
+ out.push({ kind: 'added', text: b[j] });
69
+ j += 1;
70
+ }
71
+ return out;
72
+ }
73
+ /** Group the marked lines into hunks with `context` unchanged lines around
74
+ * each run of changes. A component that differs in two places should print two
75
+ * short passages, not four hundred lines with a mark in the margin. */
76
+ export function hunks(marked, context = 3) {
77
+ const changed = marked
78
+ .map((line, index) => (line.kind === 'same' ? -1 : index))
79
+ .filter((index) => index >= 0);
80
+ if (changed.length === 0)
81
+ return [];
82
+ /* Runs of change, merged when they are close enough that the context
83
+ * between them would overlap - otherwise the same lines print twice. */
84
+ const ranges = [];
85
+ for (const index of changed) {
86
+ const last = ranges[ranges.length - 1];
87
+ if (last && index - last.end <= context * 2) {
88
+ last.end = index;
89
+ continue;
90
+ }
91
+ ranges.push({ start: index, end: index });
92
+ }
93
+ /* Line numbers are counted by walking the marked list: a removed line
94
+ * advances only the "from" side, an added line only the "to" side. */
95
+ const fromNumbers = [];
96
+ const toNumbers = [];
97
+ let fromLine = 1;
98
+ let toLine = 1;
99
+ for (const line of marked) {
100
+ fromNumbers.push(fromLine);
101
+ toNumbers.push(toLine);
102
+ if (line.kind !== 'added')
103
+ fromLine += 1;
104
+ if (line.kind !== 'removed')
105
+ toLine += 1;
106
+ }
107
+ return ranges.map((range) => {
108
+ const start = Math.max(0, range.start - context);
109
+ const end = Math.min(marked.length - 1, range.end + context);
110
+ return {
111
+ fromLine: fromNumbers[start],
112
+ toLine: toNumbers[start],
113
+ lines: marked.slice(start, end + 1),
114
+ };
115
+ });
116
+ }
117
+ /** Whether two files differ at all, ignoring line endings. Cheaper than
118
+ * diffing, and it is the question asked first. */
119
+ export function differs(from, to) {
120
+ return from.replace(/\r\n/g, '\n') !== to.replace(/\r\n/g, '\n');
121
+ }
122
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /** How serious a finding is.
2
+ *
3
+ * `problem` is something that is wrong now; `note` is something worth knowing
4
+ * that may be deliberate. The split matters because the exit code follows it -
5
+ * a tool that fails a build over a preference gets removed from the build. */
6
+ export type Severity = 'problem' | 'note';
7
+ export interface Diagnosis {
8
+ readonly severity: Severity;
9
+ /** What was checked, as a short label the reader can scan a column of. */
10
+ readonly check: string;
11
+ /** What was found. */
12
+ readonly message: string;
13
+ /** What to do about it, when there is a single obvious thing. */
14
+ readonly fix?: string;
15
+ }
16
+ /** The bits of a registry catalogue this reads. Deliberately a narrow shape:
17
+ * the catalogue is a published contract with a schema of its own, and copying
18
+ * that schema in here as types would be a second place for it to drift. */
19
+ export interface Catalogue {
20
+ readonly items: readonly {
21
+ readonly name: string;
22
+ readonly type: string;
23
+ readonly dependencies?: readonly string[];
24
+ readonly files?: readonly {
25
+ readonly path: string;
26
+ readonly target?: string;
27
+ }[];
28
+ }[];
29
+ }
30
+ /** What the project looks like from the outside. Passed in rather than read
31
+ * here, so the checks below are pure and can be tested without a directory
32
+ * tree on disk for every case. */
33
+ export interface ProjectFacts {
34
+ /** Absolute path to the project root, for messages. */
35
+ readonly root: string;
36
+ /** The project's `package.json`, if it has one. */
37
+ readonly manifest?: {
38
+ readonly dependencies?: Record<string, string>;
39
+ readonly devDependencies?: Record<string, string>;
40
+ };
41
+ /** The version of `dowel-ui` actually installed, from its own manifest in
42
+ * `node_modules` - which is the only honest answer. A range in the project
43
+ * manifest says what was asked for, not what resolved. */
44
+ readonly installedVersion?: string;
45
+ /** Every stylesheet in the project, by path, with its text. */
46
+ readonly stylesheets: readonly {
47
+ readonly path: string;
48
+ readonly source: string;
49
+ }[];
50
+ /** The project's `components.json`, if shadcn has been configured. */
51
+ readonly componentsConfig?: {
52
+ readonly aliases?: Record<string, string>;
53
+ readonly tailwind?: {
54
+ readonly css?: string;
55
+ };
56
+ };
57
+ /** The catalogue shipped by the installed package, if it is there. */
58
+ readonly catalogue?: Catalogue;
59
+ /** Files that look like copied registry components, by the registry path
60
+ * they correspond to. */
61
+ readonly installedComponents: readonly {
62
+ readonly name: string;
63
+ readonly source: string;
64
+ }[];
65
+ }
66
+ /**
67
+ * Examine a project and say what is wrong with its installation.
68
+ *
69
+ * The order is the order a reader can act in: whether the package is there at
70
+ * all, then whether the theme is reaching the screen, then the accent, then
71
+ * what has been copied in and whether it still matches.
72
+ */
73
+ export declare function diagnose(facts: ProjectFacts): Diagnosis[];
74
+ /** Read the catalogue out of the installed package.
75
+ *
76
+ * This is what makes the tools work offline: the registry a consumer needs to
77
+ * reason about is the one they installed from, and it travelled with the
78
+ * package. Returns undefined rather than throwing - a missing catalogue is one
79
+ * of the things being diagnosed. */
80
+ export declare function readCatalogue(root: string): Catalogue | undefined;
81
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAqBA;;;;8EAI8E;AAC9E,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;AAEzC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;2EAE2E;AAC3E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAChF,EAAE,CAAA;CACJ;AAED;;kCAEkC;AAClC,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC9C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAClD,CAAA;IACD;;8DAE0D;IAC1D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACnF,sEAAsE;IACtE,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC9C,CAAA;IACD,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAA;IAC9B;6BACyB;IACzB,QAAQ,CAAC,mBAAmB,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC5F;AA6BD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,CAyIzD;AAED;;;;;oCAKoC;AACpC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAQjE"}
@@ -0,0 +1,185 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ /** Every accent file the line publishes is named for its product; a project
4
+ * importing two has two accents, and the later import wins silently. */
5
+ const ACCENT_IMPORT = /@import\s+['"](?:dowel-ui\/accents\/([a-z-]+)\.css|[^'"]*accents\/([a-z-]+)\.css)['"]/g;
6
+ /** The theme, however it is reached: from the package, or copied in by the
7
+ * registry and imported from wherever the project put it. */
8
+ const THEME_IMPORT = /@import\s+['"](?:dowel-ui\/theme\.css|[^'"]*dowel\/theme\.css)['"]/;
9
+ /** The one declaration a product outside the line makes for itself. */
10
+ const ACCENT_BASE = /--accent-base\s*:/;
11
+ /** Which version of the package a copied component was built against, from the
12
+ * dependency the registry records: `dowel-ui@^0.13.0`. */
13
+ function requiredVersion(dependencies) {
14
+ const entry = dependencies?.find((name) => name.startsWith('dowel-ui@'));
15
+ return entry?.slice('dowel-ui@'.length);
16
+ }
17
+ /** The major and minor of a version, as numbers. Returns undefined for
18
+ * anything that is not a plain semver - a git URL, a workspace protocol - so
19
+ * a caller can decline to reason about it rather than guess. */
20
+ function parseVersion(version) {
21
+ const match = /^\D*(\d+)\.(\d+)\./.exec(version);
22
+ if (!match)
23
+ return undefined;
24
+ return { major: Number(match[1]), minor: Number(match[2]) };
25
+ }
26
+ /**
27
+ * Examine a project and say what is wrong with its installation.
28
+ *
29
+ * The order is the order a reader can act in: whether the package is there at
30
+ * all, then whether the theme is reaching the screen, then the accent, then
31
+ * what has been copied in and whether it still matches.
32
+ */
33
+ export function diagnose(facts) {
34
+ const found = [];
35
+ const declared = facts.manifest?.dependencies?.['dowel-ui'] ?? facts.manifest?.devDependencies?.['dowel-ui'];
36
+ /* The package itself. A project can use the registry without it - the
37
+ * components import `cn` from it, so in practice it cannot, but the check
38
+ * says so rather than assuming. */
39
+ if (!declared && !facts.installedVersion) {
40
+ found.push({
41
+ severity: 'problem',
42
+ check: 'package',
43
+ message: 'dowel-ui is not a dependency of this project.',
44
+ fix: 'pnpm add dowel-ui',
45
+ });
46
+ }
47
+ else if (declared && !facts.installedVersion) {
48
+ found.push({
49
+ severity: 'problem',
50
+ check: 'package',
51
+ message: `dowel-ui is declared as ${declared} but is not installed.`,
52
+ fix: 'Install dependencies.',
53
+ });
54
+ }
55
+ /* The theme. Without it every token is undefined, which in CSS is not an
56
+ * error - the property is simply dropped, and the screen renders in the
57
+ * browser's defaults with the layout intact. That is the single most
58
+ * confusing state this system has, and it looks like "the components are
59
+ * broken". */
60
+ const themeImports = facts.stylesheets.filter((sheet) => THEME_IMPORT.test(sheet.source));
61
+ if (themeImports.length === 0) {
62
+ found.push({
63
+ severity: 'problem',
64
+ check: 'theme',
65
+ message: 'No stylesheet imports the dowel theme, so every token is undefined.',
66
+ fix: "Add `@import 'dowel-ui/theme.css';` after `@import 'tailwindcss';`.",
67
+ });
68
+ }
69
+ else if (themeImports.length > 1) {
70
+ found.push({
71
+ severity: 'note',
72
+ check: 'theme',
73
+ message: `The theme is imported in ${themeImports.length} stylesheets: ${themeImports
74
+ .map((sheet) => sheet.path)
75
+ .join(', ')}.`,
76
+ fix: 'Import it once, in the entry stylesheet.',
77
+ });
78
+ }
79
+ /* The accent. A product of the line imports its file; anything else sets the
80
+ * one declaration. Neither is a hard error - the theme has a default - but a
81
+ * product with no accent is a product wearing dowel's own amber, which is
82
+ * almost never what was intended. */
83
+ const accents = new Set();
84
+ for (const sheet of facts.stylesheets) {
85
+ for (const match of sheet.source.matchAll(ACCENT_IMPORT)) {
86
+ accents.add(match[1] ?? match[2] ?? '');
87
+ }
88
+ }
89
+ const setsAccentBase = facts.stylesheets.some((sheet) => ACCENT_BASE.test(sheet.source));
90
+ if (accents.size === 0 && !setsAccentBase) {
91
+ found.push({
92
+ severity: 'note',
93
+ check: 'accent',
94
+ message: 'No accent is set, so the theme uses its own.',
95
+ fix: "Import your product's accent, or set `--accent-base` to your colour.",
96
+ });
97
+ }
98
+ else if (accents.size > 1) {
99
+ found.push({
100
+ severity: 'problem',
101
+ check: 'accent',
102
+ message: `Two accents are imported (${[...accents].sort().join(', ')}); whichever is imported last wins.`,
103
+ fix: 'Import one.',
104
+ });
105
+ }
106
+ else if (accents.size === 1 && setsAccentBase) {
107
+ found.push({
108
+ severity: 'note',
109
+ check: 'accent',
110
+ message: `An accent file is imported (${[...accents][0]}) and \`--accent-base\` is also set by hand; one of them is dead.`,
111
+ });
112
+ }
113
+ /* shadcn's own configuration. Without it `shadcn add` has nowhere to put a
114
+ * file, and the failure it produces talks about aliases rather than about
115
+ * this. */
116
+ if (!facts.componentsConfig) {
117
+ found.push({
118
+ severity: 'note',
119
+ check: 'components.json',
120
+ message: 'No components.json, so `shadcn add` cannot resolve where to write a component.',
121
+ fix: 'npx shadcn@latest init',
122
+ });
123
+ }
124
+ else if (!facts.componentsConfig.aliases?.ui) {
125
+ found.push({
126
+ severity: 'problem',
127
+ check: 'components.json',
128
+ message: 'components.json has no `ui` alias; every dowel component targets it.',
129
+ fix: 'Add an `aliases.ui` entry pointing at your components directory.',
130
+ });
131
+ }
132
+ /* What has been copied in, against what the catalogue says it needs. A
133
+ * component copied at 0.9 and left alone imports `cn` from a package that
134
+ * has moved four minors since; usually fine, occasionally not, and always
135
+ * worth knowing before debugging something else. */
136
+ const installed = parseVersion(facts.installedVersion ?? '');
137
+ if (facts.catalogue && installed) {
138
+ const behind = [];
139
+ for (const component of facts.installedComponents) {
140
+ const item = facts.catalogue.items.find((candidate) => candidate.name === component.name);
141
+ const required = requiredVersion(item?.dependencies);
142
+ const wanted = required ? parseVersion(required) : undefined;
143
+ if (!wanted)
144
+ continue;
145
+ if (wanted.major > installed.major || (wanted.major === installed.major && wanted.minor > installed.minor)) {
146
+ behind.push(`${component.name} (needs dowel-ui ${required})`);
147
+ }
148
+ }
149
+ if (behind.length > 0) {
150
+ found.push({
151
+ severity: 'problem',
152
+ check: 'components',
153
+ message: `Components copied in expect a newer package than is installed: ${behind.join(', ')}.`,
154
+ fix: 'Update dowel-ui.',
155
+ });
156
+ }
157
+ }
158
+ if (facts.catalogue && facts.installedComponents.length === 0) {
159
+ found.push({
160
+ severity: 'note',
161
+ check: 'components',
162
+ message: 'No dowel components found in this project.',
163
+ fix: 'npx shadcn@latest add https://lacodda.github.io/dowel/r/app.json',
164
+ });
165
+ }
166
+ return found;
167
+ }
168
+ /** Read the catalogue out of the installed package.
169
+ *
170
+ * This is what makes the tools work offline: the registry a consumer needs to
171
+ * reason about is the one they installed from, and it travelled with the
172
+ * package. Returns undefined rather than throwing - a missing catalogue is one
173
+ * of the things being diagnosed. */
174
+ export function readCatalogue(root) {
175
+ const path = resolve(root, 'node_modules/dowel-ui/dist/registry.json');
176
+ if (!existsSync(path))
177
+ return undefined;
178
+ try {
179
+ return JSON.parse(readFileSync(path, 'utf8'));
180
+ }
181
+ catch {
182
+ return undefined;
183
+ }
184
+ }
185
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** What a command decided. The number is the process exit code, and it is
2
+ * deliberately narrow: 0 for a clean run, 1 for findings, 2 for being asked to
3
+ * do something impossible. A build that treats "found things" the same as
4
+ * "could not run" cannot be trusted either way. */
5
+ type Outcome = 0 | 1 | 2;
6
+ export declare function run(argv: readonly string[]): Outcome;
7
+ export {};
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AA2CA;;;mDAGmD;AACnD,KAAK,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AA6WxB,wBAAgB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAqBpD"}