stera-ui 0.5.0 → 0.6.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/dist/add-JUBSRCDJ.js +304 -0
- package/dist/chunk-2Y64FOD3.js +161 -0
- package/dist/{chunk-3KADOWKC.js → chunk-4E46BULJ.js} +8 -1
- package/dist/chunk-BJNLGEZJ.js +100 -0
- package/dist/chunk-KGMF6UW4.js +21 -0
- package/dist/chunk-KKUJRJ2N.js +209 -0
- package/dist/{chunk-F4NT3JC6.js → chunk-SIXUH4HI.js} +47 -20
- package/dist/cli.js +19 -1339
- package/dist/index.d.ts +3 -3
- package/dist/index.js +14 -10
- package/dist/init-E7O5WAUI.js +796 -0
- package/dist/list-M73QTIWR.js +44 -0
- package/dist/registry/index.d.ts +16 -10
- package/dist/registry/index.js +4 -1
- package/dist/schema/index.d.ts +43 -201
- package/dist/schema/index.js +3 -1
- package/dist/utils/index.d.ts +7 -2
- package/dist/utils/index.js +3 -2
- package/package.json +2 -2
- package/dist/chunk-T3QWOVJR.js +0 -60
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
CHECK,
|
|
4
|
+
CROSS,
|
|
5
|
+
brand
|
|
6
|
+
} from "./chunk-KGMF6UW4.js";
|
|
7
|
+
|
|
8
|
+
// src/schema/index.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var registryItemTypeSchema = z.enum([
|
|
11
|
+
"registry:ui",
|
|
12
|
+
"registry:component",
|
|
13
|
+
"registry:hook",
|
|
14
|
+
"registry:lib",
|
|
15
|
+
"registry:style",
|
|
16
|
+
"registry:font"
|
|
17
|
+
]);
|
|
18
|
+
var registryItemFileSchema = z.object({
|
|
19
|
+
path: z.string(),
|
|
20
|
+
type: registryItemTypeSchema,
|
|
21
|
+
content: z.string().optional(),
|
|
22
|
+
target: z.string().optional()
|
|
23
|
+
});
|
|
24
|
+
var registryItemFontSchema = z.object({
|
|
25
|
+
family: z.string(),
|
|
26
|
+
provider: z.literal("google"),
|
|
27
|
+
import: z.string(),
|
|
28
|
+
variable: z.string(),
|
|
29
|
+
weight: z.array(z.string()).optional(),
|
|
30
|
+
subsets: z.array(z.string()).optional(),
|
|
31
|
+
selector: z.string().optional(),
|
|
32
|
+
dependency: z.string().optional()
|
|
33
|
+
});
|
|
34
|
+
var registryItemCommonSchema = z.object({
|
|
35
|
+
name: z.string(),
|
|
36
|
+
dependencies: z.array(z.string()).optional(),
|
|
37
|
+
registryDependencies: z.array(z.string()).optional(),
|
|
38
|
+
files: z.array(registryItemFileSchema).optional()
|
|
39
|
+
});
|
|
40
|
+
var registryItemSchema = z.discriminatedUnion("type", [
|
|
41
|
+
registryItemCommonSchema.extend({
|
|
42
|
+
type: z.literal("registry:font"),
|
|
43
|
+
font: registryItemFontSchema,
|
|
44
|
+
files: z.array(registryItemFileSchema).optional()
|
|
45
|
+
}),
|
|
46
|
+
registryItemCommonSchema.extend({
|
|
47
|
+
type: registryItemTypeSchema.exclude(["registry:font"]),
|
|
48
|
+
files: z.array(registryItemFileSchema)
|
|
49
|
+
})
|
|
50
|
+
]);
|
|
51
|
+
var registryIndexEntrySchema = z.object({
|
|
52
|
+
name: z.string(),
|
|
53
|
+
type: z.string(),
|
|
54
|
+
dependencies: z.array(z.string()).optional(),
|
|
55
|
+
registryDependencies: z.array(z.string()).optional()
|
|
56
|
+
});
|
|
57
|
+
var registryIndexSchema = z.object({
|
|
58
|
+
name: z.string(),
|
|
59
|
+
items: z.array(registryIndexEntrySchema)
|
|
60
|
+
});
|
|
61
|
+
var configSchema = z.object({
|
|
62
|
+
$schema: z.string().optional(),
|
|
63
|
+
version: z.literal(1),
|
|
64
|
+
css: z.string(),
|
|
65
|
+
aliases: z.object({
|
|
66
|
+
components: z.string(),
|
|
67
|
+
utils: z.string(),
|
|
68
|
+
ui: z.string(),
|
|
69
|
+
lib: z.string(),
|
|
70
|
+
hooks: z.string()
|
|
71
|
+
}),
|
|
72
|
+
fonts: z.object({
|
|
73
|
+
strategy: z.enum(["stera-default", "keep-existing", "skip"]),
|
|
74
|
+
nextFont: z.boolean().optional()
|
|
75
|
+
}).optional()
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// src/registry/index.ts
|
|
79
|
+
var REGISTRY_URL = process.env.REGISTRY_URL ?? "https://ui.stera.sh/r";
|
|
80
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
81
|
+
var ComponentNotFoundError = class extends Error {
|
|
82
|
+
components;
|
|
83
|
+
constructor(components) {
|
|
84
|
+
super(
|
|
85
|
+
components.length === 1 ? `Component "${components[0]}" not found in registry.` : `Components not found in registry: ${components.map((c) => `"${c}"`).join(", ")}.`
|
|
86
|
+
);
|
|
87
|
+
this.name = "ComponentNotFoundError";
|
|
88
|
+
this.components = components;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var _indexCache = null;
|
|
92
|
+
async function fetchJSON(url) {
|
|
93
|
+
let res;
|
|
94
|
+
try {
|
|
95
|
+
res = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Timed out fetching ${url} after ${FETCH_TIMEOUT_MS / 1e3}s. Check your network connection.`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Failed to fetch ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
108
|
+
}
|
|
109
|
+
return res.json();
|
|
110
|
+
}
|
|
111
|
+
async function fetchRegistryIndex() {
|
|
112
|
+
if (_indexCache) return _indexCache;
|
|
113
|
+
const data = await fetchJSON(`${REGISTRY_URL}/index.json`);
|
|
114
|
+
const parsed = registryIndexSchema.safeParse(data);
|
|
115
|
+
if (!parsed.success) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Registry index at ${REGISTRY_URL}/index.json returned unexpected data.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
_indexCache = parsed.data.items;
|
|
121
|
+
return _indexCache;
|
|
122
|
+
}
|
|
123
|
+
async function fetchRegistryItem(name) {
|
|
124
|
+
const data = await fetchJSON(`${REGISTRY_URL}/${name}.json`);
|
|
125
|
+
const parsed = registryItemSchema.safeParse(data);
|
|
126
|
+
if (!parsed.success) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Registry item "${name}" returned unexpected data from ${REGISTRY_URL}/${name}.json.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return parsed.data;
|
|
132
|
+
}
|
|
133
|
+
async function getAllComponents() {
|
|
134
|
+
return fetchRegistryIndex();
|
|
135
|
+
}
|
|
136
|
+
async function resolveDependencies(names) {
|
|
137
|
+
const index = await fetchRegistryIndex();
|
|
138
|
+
const byName = new Map(index.map((entry) => [entry.name, entry]));
|
|
139
|
+
const needed = [];
|
|
140
|
+
const seen = /* @__PURE__ */ new Set();
|
|
141
|
+
const missing = [];
|
|
142
|
+
const queue = [...names];
|
|
143
|
+
while (queue.length > 0) {
|
|
144
|
+
const name = queue.shift();
|
|
145
|
+
if (seen.has(name)) continue;
|
|
146
|
+
seen.add(name);
|
|
147
|
+
const entry = byName.get(name);
|
|
148
|
+
if (!entry) {
|
|
149
|
+
missing.push(name);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
needed.push(name);
|
|
153
|
+
queue.push(...entry.registryDependencies ?? []);
|
|
154
|
+
}
|
|
155
|
+
if (missing.length > 0) {
|
|
156
|
+
throw new ComponentNotFoundError(missing);
|
|
157
|
+
}
|
|
158
|
+
return Promise.all(needed.map((name) => fetchRegistryItem(name)));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/utils/spinner.ts
|
|
162
|
+
var FRAMES = ["\u2022", "\u2726", "\u2736", "\u273B"].map(brand);
|
|
163
|
+
var INTERVAL_MS = 150;
|
|
164
|
+
function createSpinner(text) {
|
|
165
|
+
const isTTY = process.stdout.isTTY;
|
|
166
|
+
if (!isTTY) {
|
|
167
|
+
process.stdout.write(` ${text}...
|
|
168
|
+
`);
|
|
169
|
+
return {
|
|
170
|
+
succeed(msg) {
|
|
171
|
+
process.stdout.write(` ${CHECK} ${msg}
|
|
172
|
+
`);
|
|
173
|
+
},
|
|
174
|
+
fail(msg) {
|
|
175
|
+
process.stdout.write(` ${CROSS} ${msg}
|
|
176
|
+
`);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
let frameIndex = 0;
|
|
181
|
+
const interval = setInterval(() => {
|
|
182
|
+
process.stdout.write(`\r ${FRAMES[frameIndex % FRAMES.length]} ${text}`);
|
|
183
|
+
frameIndex++;
|
|
184
|
+
}, INTERVAL_MS);
|
|
185
|
+
const clear = () => {
|
|
186
|
+
clearInterval(interval);
|
|
187
|
+
process.stdout.write("\r" + " ".repeat(text.length + 6) + "\r");
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
succeed(msg) {
|
|
191
|
+
clear();
|
|
192
|
+
process.stdout.write(` ${CHECK} ${msg}
|
|
193
|
+
`);
|
|
194
|
+
},
|
|
195
|
+
fail(msg) {
|
|
196
|
+
clear();
|
|
197
|
+
process.stdout.write(` ${CROSS} ${msg}
|
|
198
|
+
`);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
ComponentNotFoundError,
|
|
205
|
+
fetchRegistryItem,
|
|
206
|
+
getAllComponents,
|
|
207
|
+
resolveDependencies,
|
|
208
|
+
createSpinner
|
|
209
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fetchRegistryItem
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BJNLGEZJ.js";
|
|
4
4
|
|
|
5
5
|
// src/utils/transform.ts
|
|
6
6
|
function applyTransforms(content, ctx, transforms) {
|
|
@@ -22,19 +22,31 @@ var transformImports = (content, ctx) => {
|
|
|
22
22
|
const { aliases } = ctx.config;
|
|
23
23
|
const rules = [];
|
|
24
24
|
if (aliases.utils !== DEFAULT_ALIASES.utils) {
|
|
25
|
-
rules.push({
|
|
25
|
+
rules.push({
|
|
26
|
+
type: "exact",
|
|
27
|
+
from: DEFAULT_ALIASES.utils,
|
|
28
|
+
to: aliases.utils
|
|
29
|
+
});
|
|
26
30
|
}
|
|
27
31
|
if (aliases.ui !== DEFAULT_ALIASES.ui) {
|
|
28
32
|
rules.push({ type: "prefix", from: DEFAULT_ALIASES.ui, to: aliases.ui });
|
|
29
33
|
}
|
|
30
34
|
if (aliases.components !== DEFAULT_ALIASES.components) {
|
|
31
|
-
rules.push({
|
|
35
|
+
rules.push({
|
|
36
|
+
type: "prefix",
|
|
37
|
+
from: DEFAULT_ALIASES.components,
|
|
38
|
+
to: aliases.components
|
|
39
|
+
});
|
|
32
40
|
}
|
|
33
41
|
if (aliases.lib !== DEFAULT_ALIASES.lib) {
|
|
34
42
|
rules.push({ type: "prefix", from: DEFAULT_ALIASES.lib, to: aliases.lib });
|
|
35
43
|
}
|
|
36
44
|
if (aliases.hooks !== DEFAULT_ALIASES.hooks) {
|
|
37
|
-
rules.push({
|
|
45
|
+
rules.push({
|
|
46
|
+
type: "prefix",
|
|
47
|
+
from: DEFAULT_ALIASES.hooks,
|
|
48
|
+
to: aliases.hooks
|
|
49
|
+
});
|
|
38
50
|
}
|
|
39
51
|
if (rules.length === 0) {
|
|
40
52
|
return content;
|
|
@@ -68,16 +80,30 @@ var TYPE_TO_ALIAS = {
|
|
|
68
80
|
"registry:hook": "hooks",
|
|
69
81
|
"registry:component": "components"
|
|
70
82
|
};
|
|
71
|
-
|
|
83
|
+
var matcherCache = /* @__PURE__ */ new Map();
|
|
84
|
+
function getTsConfigMatcher(projectRoot) {
|
|
85
|
+
let matcher = matcherCache.get(projectRoot);
|
|
86
|
+
if (matcher !== void 0) return matcher;
|
|
72
87
|
const tsConfig = loadConfig(projectRoot);
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
matcher = tsConfig.resultType === "success" && Object.keys(tsConfig.paths).length > 0 ? {
|
|
89
|
+
paths: tsConfig.paths,
|
|
90
|
+
match: createMatchPath(tsConfig.absoluteBaseUrl, tsConfig.paths)
|
|
91
|
+
} : null;
|
|
92
|
+
matcherCache.set(projectRoot, matcher);
|
|
93
|
+
return matcher;
|
|
94
|
+
}
|
|
95
|
+
function resolveAlias(alias, projectRoot) {
|
|
96
|
+
const matcher = getTsConfigMatcher(projectRoot);
|
|
97
|
+
if (matcher) {
|
|
98
|
+
const hasMatchingPrefix = Object.keys(matcher.paths).some((key) => {
|
|
75
99
|
const prefix = key.replace(/\/\*$/, "");
|
|
76
100
|
return alias === prefix || alias.startsWith(`${prefix}/`);
|
|
77
101
|
});
|
|
78
102
|
if (hasMatchingPrefix) {
|
|
79
|
-
const
|
|
80
|
-
|
|
103
|
+
const resolved = matcher.match(alias, void 0, () => true, [
|
|
104
|
+
".ts",
|
|
105
|
+
".tsx"
|
|
106
|
+
]);
|
|
81
107
|
if (resolved) {
|
|
82
108
|
return path.relative(projectRoot, resolved);
|
|
83
109
|
}
|
|
@@ -379,7 +405,9 @@ async function installDependencies(deps, cwd) {
|
|
|
379
405
|
if (fs5.existsSync(pkgPath)) {
|
|
380
406
|
try {
|
|
381
407
|
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
382
|
-
existing = new Set(
|
|
408
|
+
existing = new Set(
|
|
409
|
+
Object.keys({ ...pkg.dependencies, ...pkg.devDependencies })
|
|
410
|
+
);
|
|
383
411
|
} catch {
|
|
384
412
|
}
|
|
385
413
|
}
|
|
@@ -407,19 +435,18 @@ or use "pnpm add -w <package>" manually to install at the root.`
|
|
|
407
435
|
// src/utils/write-files.ts
|
|
408
436
|
import fs6 from "fs";
|
|
409
437
|
import path6 from "path";
|
|
410
|
-
import
|
|
438
|
+
import { confirm } from "@inquirer/prompts";
|
|
411
439
|
async function confirmOverwrite(relativePath) {
|
|
412
440
|
if (!process.stdin.isTTY) {
|
|
413
|
-
console.log(
|
|
441
|
+
console.log(
|
|
442
|
+
` Skipping ${relativePath} (already exists, use --overwrite to replace)`
|
|
443
|
+
);
|
|
414
444
|
return false;
|
|
415
445
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
446
|
+
return confirm({
|
|
447
|
+
message: `${relativePath} already exists. Overwrite?`,
|
|
448
|
+
default: false
|
|
419
449
|
});
|
|
420
|
-
const answer = await rl.question(` ${relativePath} already exists. Overwrite? (y/N) `);
|
|
421
|
-
rl.close();
|
|
422
|
-
return answer.toLowerCase() === "y";
|
|
423
450
|
}
|
|
424
451
|
async function writeComponentFiles(items, config, projectRoot, options = {}) {
|
|
425
452
|
const written = [];
|
|
@@ -431,13 +458,13 @@ async function writeComponentFiles(items, config, projectRoot, options = {}) {
|
|
|
431
458
|
if (fs6.existsSync(outputPath)) {
|
|
432
459
|
const existing = fs6.readFileSync(outputPath, "utf-8");
|
|
433
460
|
if (existing === file.content) {
|
|
434
|
-
skipped.push(relativePath);
|
|
461
|
+
skipped.push({ path: relativePath, reason: "unchanged" });
|
|
435
462
|
continue;
|
|
436
463
|
}
|
|
437
464
|
if (!options.overwrite) {
|
|
438
465
|
const confirmed = await confirmOverwrite(relativePath);
|
|
439
466
|
if (!confirmed) {
|
|
440
|
-
skipped.push(relativePath);
|
|
467
|
+
skipped.push({ path: relativePath, reason: "declined" });
|
|
441
468
|
continue;
|
|
442
469
|
}
|
|
443
470
|
}
|