stera-ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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-67ILD3JO.js → chunk-SIXUH4HI.js} +64 -21
- package/dist/cli.js +19 -1302
- package/dist/index.d.ts +3 -3
- package/dist/index.js +16 -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 +29 -187
- package/dist/schema/index.js +3 -1
- package/dist/utils/index.d.ts +9 -3
- package/dist/utils/index.js +5 -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
|
}
|
|
@@ -105,7 +131,8 @@ function resolveOutputPath(config, projectRoot, file) {
|
|
|
105
131
|
// src/utils/resolve-config.ts
|
|
106
132
|
import fs from "fs";
|
|
107
133
|
import path2 from "path";
|
|
108
|
-
var CONFIG_FILE = "
|
|
134
|
+
var CONFIG_FILE = "stera.config.json";
|
|
135
|
+
var LEGACY_CONFIG_FILE = "components.json";
|
|
109
136
|
function migrateConfig(raw) {
|
|
110
137
|
if (!("version" in raw) && "tailwind" in raw) {
|
|
111
138
|
const legacy = raw;
|
|
@@ -117,11 +144,22 @@ function migrateConfig(raw) {
|
|
|
117
144
|
}
|
|
118
145
|
return raw;
|
|
119
146
|
}
|
|
147
|
+
var warnedLegacyFilename = false;
|
|
148
|
+
function warnLegacyFilenameOnce(legacyPath) {
|
|
149
|
+
if (warnedLegacyFilename) return;
|
|
150
|
+
warnedLegacyFilename = true;
|
|
151
|
+
console.warn(
|
|
152
|
+
` \u26A0 Found ${LEGACY_CONFIG_FILE}. Rename to ${CONFIG_FILE} \u2014 legacy filename support will be removed in a future release.
|
|
153
|
+
(${legacyPath})`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
120
156
|
function findConfigPath(cwd) {
|
|
121
157
|
let dir = path2.resolve(cwd);
|
|
122
158
|
while (true) {
|
|
123
159
|
const configPath = path2.join(dir, CONFIG_FILE);
|
|
124
160
|
if (fs.existsSync(configPath)) return configPath;
|
|
161
|
+
const legacyPath = path2.join(dir, LEGACY_CONFIG_FILE);
|
|
162
|
+
if (fs.existsSync(legacyPath)) return legacyPath;
|
|
125
163
|
const parent = path2.dirname(dir);
|
|
126
164
|
if (parent === dir) return null;
|
|
127
165
|
dir = parent;
|
|
@@ -130,6 +168,9 @@ function findConfigPath(cwd) {
|
|
|
130
168
|
function loadConfig2(cwd) {
|
|
131
169
|
const configPath = findConfigPath(cwd);
|
|
132
170
|
if (!configPath) return null;
|
|
171
|
+
if (path2.basename(configPath) === LEGACY_CONFIG_FILE) {
|
|
172
|
+
warnLegacyFilenameOnce(configPath);
|
|
173
|
+
}
|
|
133
174
|
try {
|
|
134
175
|
const raw = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
135
176
|
return migrateConfig(raw);
|
|
@@ -364,7 +405,9 @@ async function installDependencies(deps, cwd) {
|
|
|
364
405
|
if (fs5.existsSync(pkgPath)) {
|
|
365
406
|
try {
|
|
366
407
|
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
367
|
-
existing = new Set(
|
|
408
|
+
existing = new Set(
|
|
409
|
+
Object.keys({ ...pkg.dependencies, ...pkg.devDependencies })
|
|
410
|
+
);
|
|
368
411
|
} catch {
|
|
369
412
|
}
|
|
370
413
|
}
|
|
@@ -392,19 +435,18 @@ or use "pnpm add -w <package>" manually to install at the root.`
|
|
|
392
435
|
// src/utils/write-files.ts
|
|
393
436
|
import fs6 from "fs";
|
|
394
437
|
import path6 from "path";
|
|
395
|
-
import
|
|
438
|
+
import { confirm } from "@inquirer/prompts";
|
|
396
439
|
async function confirmOverwrite(relativePath) {
|
|
397
440
|
if (!process.stdin.isTTY) {
|
|
398
|
-
console.log(
|
|
441
|
+
console.log(
|
|
442
|
+
` Skipping ${relativePath} (already exists, use --overwrite to replace)`
|
|
443
|
+
);
|
|
399
444
|
return false;
|
|
400
445
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
446
|
+
return confirm({
|
|
447
|
+
message: `${relativePath} already exists. Overwrite?`,
|
|
448
|
+
default: false
|
|
404
449
|
});
|
|
405
|
-
const answer = await rl.question(` ${relativePath} already exists. Overwrite? (y/N) `);
|
|
406
|
-
rl.close();
|
|
407
|
-
return answer.toLowerCase() === "y";
|
|
408
450
|
}
|
|
409
451
|
async function writeComponentFiles(items, config, projectRoot, options = {}) {
|
|
410
452
|
const written = [];
|
|
@@ -416,13 +458,13 @@ async function writeComponentFiles(items, config, projectRoot, options = {}) {
|
|
|
416
458
|
if (fs6.existsSync(outputPath)) {
|
|
417
459
|
const existing = fs6.readFileSync(outputPath, "utf-8");
|
|
418
460
|
if (existing === file.content) {
|
|
419
|
-
skipped.push(relativePath);
|
|
461
|
+
skipped.push({ path: relativePath, reason: "unchanged" });
|
|
420
462
|
continue;
|
|
421
463
|
}
|
|
422
464
|
if (!options.overwrite) {
|
|
423
465
|
const confirmed = await confirmOverwrite(relativePath);
|
|
424
466
|
if (!confirmed) {
|
|
425
|
-
skipped.push(relativePath);
|
|
467
|
+
skipped.push({ path: relativePath, reason: "declined" });
|
|
426
468
|
continue;
|
|
427
469
|
}
|
|
428
470
|
}
|
|
@@ -752,6 +794,7 @@ export {
|
|
|
752
794
|
transformImports,
|
|
753
795
|
resolveOutputPath,
|
|
754
796
|
CONFIG_FILE,
|
|
797
|
+
LEGACY_CONFIG_FILE,
|
|
755
798
|
findConfigPath,
|
|
756
799
|
loadConfig2 as loadConfig,
|
|
757
800
|
detectProject,
|