@webjsdev/ui 0.3.14 → 0.3.16
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 +8 -0
- package/package.json +1 -1
- package/src/commands/add.js +19 -6
- package/src/commands/lint.js +93 -0
- package/src/index.js +3 -1
- package/src/lint/grammar.js +839 -0
- package/src/lint/index.js +205 -0
- package/src/lint/rules/index.js +12 -0
- package/src/lint/rules/no-arbitrary-values.js +33 -0
- package/src/lint/rules/no-raw-colors.js +86 -0
- package/src/lint/rules/no-restyle.js +66 -0
- package/src/lint/scan.js +446 -0
- package/src/lint/theme-tokens.js +75 -0
- package/src/registry/extract.js +166 -0
- package/src/registry/schema.js +38 -0
- package/src/utils/package-manager.js +92 -0
package/src/registry/schema.js
CHANGED
|
@@ -82,6 +82,43 @@ export const registryItemCommonSchema = z.object({
|
|
|
82
82
|
categories: z.array(z.string()).optional(),
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
/** A rule's severity. Absent from `lint.rules` means `off`. */
|
|
86
|
+
export const lintSeveritySchema = z.enum(['off', 'warn', 'error']);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One rule's configuration: a bare severity, or an object adding `allow`
|
|
90
|
+
* (category names such as `layout` / `spacing`, or class-group names such
|
|
91
|
+
* as `rounded`). Kept `.strict()` so a typo is a config error, not a silent
|
|
92
|
+
* no-op.
|
|
93
|
+
*/
|
|
94
|
+
export const lintRuleSchema = z.union([
|
|
95
|
+
lintSeveritySchema,
|
|
96
|
+
z
|
|
97
|
+
.object({
|
|
98
|
+
severity: lintSeveritySchema.default('warn'),
|
|
99
|
+
allow: z.array(z.string()).optional(),
|
|
100
|
+
})
|
|
101
|
+
.strict(),
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The opt-in `lint` block of `components.json`, read by `webjsui lint`. No
|
|
106
|
+
* block means every rule is off and the command reports nothing.
|
|
107
|
+
*/
|
|
108
|
+
export const lintConfigSchema = z
|
|
109
|
+
.object({
|
|
110
|
+
ignore: z.array(z.string()).default([]),
|
|
111
|
+
rules: z
|
|
112
|
+
.object({
|
|
113
|
+
'no-raw-colors': lintRuleSchema.optional(),
|
|
114
|
+
'no-arbitrary-values': lintRuleSchema.optional(),
|
|
115
|
+
'no-restyle': lintRuleSchema.optional(),
|
|
116
|
+
})
|
|
117
|
+
.strict()
|
|
118
|
+
.default({}),
|
|
119
|
+
})
|
|
120
|
+
.strict();
|
|
121
|
+
|
|
85
122
|
export const rawConfigSchema = z
|
|
86
123
|
.object({
|
|
87
124
|
$schema: z.string().optional(),
|
|
@@ -94,6 +131,7 @@ export const rawConfigSchema = z
|
|
|
94
131
|
prefix: z.string().default('').optional(),
|
|
95
132
|
}),
|
|
96
133
|
iconLibrary: z.string().optional().default('lucide'),
|
|
134
|
+
lint: lintConfigSchema.optional(),
|
|
97
135
|
aliases: z.object({
|
|
98
136
|
components: z.string().default('components'),
|
|
99
137
|
utils: z.string().default('lib/utils'),
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-manager detection for `webjs ui add` (#1494).
|
|
3
|
+
*
|
|
4
|
+
* KEEP IN SYNC with `packages/cli/lib/package-manager.js`. The two published
|
|
5
|
+
* packages carry the same small module rather than one importing the other,
|
|
6
|
+
* so a `@webjsdev/cli` release can never fail at import time against an older
|
|
7
|
+
* `@webjsdev/ui` that lacks the export. `packages/cli/test/package-manager.test.mjs`
|
|
8
|
+
* asserts both copies agree on every fixture.
|
|
9
|
+
*
|
|
10
|
+
* Detection order (with `prefer: 'lockfile'`, the default):
|
|
11
|
+
* 1. A lockfile in `cwd` or any ancestor. The walk stops at the first
|
|
12
|
+
* workspace root (a package.json declaring `workspaces`, or a
|
|
13
|
+
* `pnpm-workspace.yaml`) or at the filesystem root, so an app nested in a
|
|
14
|
+
* workspace finds the root's lockfile. Within one directory the order is
|
|
15
|
+
* pnpm, yarn, bun (`bun.lock`, the text lockfile Bun writes since 1.2,
|
|
16
|
+
* and the older binary `bun.lockb`), then npm.
|
|
17
|
+
* 2. `npm_config_user_agent`, which npm, pnpm, yarn and bun set when they
|
|
18
|
+
* run a script or a `dlx` / `bunx` / `npx` binary.
|
|
19
|
+
* 3. `npm`.
|
|
20
|
+
* With `prefer: 'agent'` steps 1 and 2 swap, which suits `webjs create`: the
|
|
21
|
+
* tool that invoked it is the strongest signal for a directory that has no
|
|
22
|
+
* lockfile yet.
|
|
23
|
+
*/
|
|
24
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
25
|
+
import { dirname, join, resolve } from 'node:path';
|
|
26
|
+
|
|
27
|
+
/** @typedef {'npm'|'pnpm'|'yarn'|'bun'} PackageManager */
|
|
28
|
+
|
|
29
|
+
/** Lockfile name to manager, in per-directory precedence order. */
|
|
30
|
+
const LOCKFILES = /** @type {const} */ ([
|
|
31
|
+
['pnpm-lock.yaml', 'pnpm'],
|
|
32
|
+
['yarn.lock', 'yarn'],
|
|
33
|
+
['bun.lock', 'bun'],
|
|
34
|
+
['bun.lockb', 'bun'],
|
|
35
|
+
['package-lock.json', 'npm'],
|
|
36
|
+
['npm-shrinkwrap.json', 'npm'],
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Whether `dir` is a workspace root, where the lockfile walk stops.
|
|
41
|
+
* @param {string} dir
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
function isWorkspaceRoot(dir) {
|
|
45
|
+
if (existsSync(join(dir, 'pnpm-workspace.yaml'))) return true;
|
|
46
|
+
const pkgPath = join(dir, 'package.json');
|
|
47
|
+
if (!existsSync(pkgPath)) return false;
|
|
48
|
+
try {
|
|
49
|
+
return Boolean(JSON.parse(readFileSync(pkgPath, 'utf8')).workspaces);
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Walk up from `cwd` looking for a lockfile.
|
|
57
|
+
* @param {string} cwd
|
|
58
|
+
* @returns {PackageManager | null}
|
|
59
|
+
*/
|
|
60
|
+
export function managerFromLockfile(cwd) {
|
|
61
|
+
let dir = resolve(cwd);
|
|
62
|
+
for (;;) {
|
|
63
|
+
for (const [file, manager] of LOCKFILES) {
|
|
64
|
+
if (existsSync(join(dir, file))) return manager;
|
|
65
|
+
}
|
|
66
|
+
if (isWorkspaceRoot(dir)) return null;
|
|
67
|
+
const parent = dirname(dir);
|
|
68
|
+
if (parent === dir) return null;
|
|
69
|
+
dir = parent;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Read the manager from an `npm_config_user_agent` value such as
|
|
75
|
+
* `bun/1.3.14 npm/? node/v24.0.0 linux x64`.
|
|
76
|
+
* @param {string | undefined} ua
|
|
77
|
+
* @returns {PackageManager | null}
|
|
78
|
+
*/
|
|
79
|
+
export function managerFromUserAgent(ua) {
|
|
80
|
+
const name = String(ua || '').split('/')[0];
|
|
81
|
+
return name === 'pnpm' || name === 'yarn' || name === 'bun' || name === 'npm' ? name : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {{ cwd?: string | null, env?: Record<string, string | undefined>, prefer?: 'lockfile' | 'agent' }} [opts]
|
|
86
|
+
* @returns {PackageManager}
|
|
87
|
+
*/
|
|
88
|
+
export function detectPackageManager({ cwd = null, env = process.env, prefer = 'lockfile' } = {}) {
|
|
89
|
+
const fromLock = () => (cwd ? managerFromLockfile(cwd) : null);
|
|
90
|
+
const fromAgent = () => managerFromUserAgent(env.npm_config_user_agent);
|
|
91
|
+
return (prefer === 'agent' ? fromAgent() ?? fromLock() : fromLock() ?? fromAgent()) ?? 'npm';
|
|
92
|
+
}
|