@cmtlyt/unplugin-shadcn-registry-generate 0.1.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/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # unplugin-shadcn-registry-generate
2
+
3
+ 生成 shadcn 的 registry 和对应的 registry-item
4
+
5
+ ## 使用
6
+
7
+ 创建 `shadcn-exports.json` 文件, 示例内容如下
8
+
9
+ ```json
10
+ {
11
+ "$schema": "./node_modules/@cmtlyt/unplugin-shadcn-registry-generate",
12
+ "exports": [
13
+ { "path": "./src/atomic-functions/assert-never.ts" },
14
+ { "path": "./src/atomic-functions/sleep.ts" },
15
+ { "path": "./src/tools/allx.ts", "name": "promiseAllX", "description": "promiseAllX", "title": "promiseAllX" },
16
+ { "path": "./src/types/base.ts" }
17
+ ]
18
+ }
19
+ ```
20
+
21
+ 在打包工具配置文件中补充如下内容, 以 rslib 为例
22
+
23
+ ```ts
24
+ import { defineConfig } from '@rslib/core';
25
+ import shadcnRegistryGenerator from '@cmtlyt/unplugin-shadcn-registry-generate';
26
+
27
+ export default defineConfig({
28
+ lib: [
29
+ {
30
+ format: 'esm',
31
+ syntax: ['node 18'],
32
+ dts: true,
33
+ tools: {
34
+ rspack: {
35
+ plugins: [shadcnRegistryGenerator.rspack()]
36
+ },
37
+ },
38
+ },
39
+ ],
40
+ });
41
+ ```
42
+
43
+ 然后执行 `npm run build` 即可
44
+
45
+ ## 提示
46
+
47
+ name 生成规则如下
48
+
49
+ - 文件名不为 index 使用文件名
50
+ - 文件夹名
51
+
52
+ 所以 name 是可能会冲突的, 为了更好的控制 name 最好是手动配置 name
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "exports": {
6
+ "type": "array",
7
+ "items": {
8
+ "type": "object",
9
+ "properties": {
10
+ "name": { "type": "string" },
11
+ "path": { "type": "string" },
12
+ "description": { "type": "string" },
13
+ "title": { "type": "string" },
14
+ "author": { "type": "string" }
15
+ },
16
+ "required": ["path"]
17
+ }
18
+ }
19
+ },
20
+ "required": ["exports"],
21
+ "uniqueItems": true,
22
+ "minItems": 1
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { ShadcnRegisterGeneratorOptions } from './types';
2
+ declare const shadcnRegisterGenerator: import("unplugin").UnpluginInstance<ShadcnRegisterGeneratorOptions, boolean>;
3
+ export default shadcnRegisterGenerator;
package/dist/index.js ADDED
@@ -0,0 +1,391 @@
1
+ import { createUnplugin } from "unplugin";
2
+ import node_fs from "node:fs";
3
+ import node_path from "node:path";
4
+ import { readTSConfig, resolvePackageJSON } from "pkg-types";
5
+ import { createRequire } from "node:module";
6
+ import { randomUUID } from "node:crypto";
7
+ function initOuputDir(ctx) {
8
+ const { options } = ctx;
9
+ const { outputDir } = options;
10
+ if (!node_fs.existsSync(outputDir)) node_fs.mkdirSync(outputDir, {
11
+ recursive: true
12
+ });
13
+ }
14
+ function normalizeBasePath(basePath) {
15
+ if (basePath.endsWith('/')) return basePath;
16
+ return `${basePath}/`;
17
+ }
18
+ function normalizeOptions(options) {
19
+ if (!options.registryUrl) throw new Error('registryUrl is required');
20
+ return {
21
+ registryUrl: options.registryUrl,
22
+ outputDir: options.outputDir || './public/r',
23
+ basePath: normalizeBasePath(options.basePath || '~/'),
24
+ noRootRegistry: true === options.noRootRegistry
25
+ };
26
+ }
27
+ function readConfig(ctx) {
28
+ const configPath = node_path.join(ctx.baseDir, 'shadcn-exports.json');
29
+ if (!node_fs.existsSync(configPath)) return null;
30
+ return JSON.parse(node_fs.readFileSync(configPath, 'utf-8'));
31
+ }
32
+ async function initContext(ctx) {
33
+ ctx.baseDir = node_path.dirname(await resolvePackageJSON());
34
+ const config = await readConfig(ctx);
35
+ if (!config) console.warn('shadcn-exports.json not found');
36
+ ctx.config = config || {
37
+ exports: []
38
+ };
39
+ ctx.tsConfig = await readTSConfig(ctx.baseDir);
40
+ }
41
+ function createContext(options) {
42
+ return {
43
+ options: normalizeOptions(options),
44
+ baseDir: '',
45
+ config: null,
46
+ exports: null,
47
+ tsConfig: null,
48
+ runCtx: {
49
+ reqistrys: [],
50
+ dependenciesSet: null,
51
+ aliasMap: {}
52
+ }
53
+ };
54
+ }
55
+ function getNameFromPath(exportItem, ctx) {
56
+ if (node_fs.statSync(exportItem.path).isFile()) {
57
+ const baseName = node_path.basename(exportItem.path);
58
+ if (baseName.startsWith('index')) return node_path.basename(node_path.dirname(exportItem.path), ctx.baseDir);
59
+ return baseName.replace(/\.\w+$/, '');
60
+ }
61
+ return node_path.basename(exportItem.path, ctx.baseDir);
62
+ }
63
+ const fileRequire = createRequire(import.meta.url);
64
+ function isNodeOrgModule(id) {
65
+ return id.startsWith('node:') || !id.includes('/');
66
+ }
67
+ function pathMatch(realPath, id, isFile) {
68
+ if (isFile) return realPath === id;
69
+ return id.startsWith(realPath) && !id.includes('node_modules');
70
+ }
71
+ function fileInWorkspace(filePath, ctx) {
72
+ return pathMatch(ctx.baseDir, filePath, false);
73
+ }
74
+ function extTry(filePath, _ctx) {
75
+ const exts = [
76
+ '.ts',
77
+ '.tsx',
78
+ '.js',
79
+ '.jsx',
80
+ '.cjs',
81
+ '.mjs',
82
+ '.vue'
83
+ ];
84
+ for(let i = 0; i < exts.length; i++){
85
+ const ext = exts[i];
86
+ const fullPath = `${filePath}${ext}`;
87
+ if (node_fs.existsSync(fullPath)) return fullPath;
88
+ }
89
+ if (node_fs.existsSync(`${filePath}/index.ts`)) return `${filePath}/index.ts`;
90
+ return filePath;
91
+ }
92
+ function tsPathsResolve(id, ctx, filePath) {
93
+ try {
94
+ const tempId = fileRequire.resolve(id);
95
+ if (node_path.isAbsolute(tempId)) return {
96
+ type: 'original',
97
+ originalId: id,
98
+ resolvedId: id
99
+ };
100
+ } catch {}
101
+ if (isNodeOrgModule(id)) return {
102
+ type: 'original',
103
+ originalId: id,
104
+ resolvedId: id
105
+ };
106
+ const { paths, baseUrl } = ctx.tsConfig?.compilerOptions || {};
107
+ const fileDir = node_path.dirname(filePath);
108
+ if (!paths) return {
109
+ type: 'relative',
110
+ originalId: id,
111
+ resolvedId: extTry(node_path.resolve(fileDir, id), ctx)
112
+ };
113
+ const keys = Reflect.ownKeys(paths);
114
+ for(let i = 0; i < keys.length; i++){
115
+ const key = keys[i];
116
+ const value = paths[key][0].replace(/\*$/, '');
117
+ if (id === key) {
118
+ const resolvedId = extTry(node_path.resolve(baseUrl || ctx.baseDir, value), ctx);
119
+ return {
120
+ type: 'alias',
121
+ originalId: id,
122
+ resolvedId,
123
+ relativePath: node_path.relative(fileDir, resolvedId),
124
+ aliasPath: value
125
+ };
126
+ }
127
+ const keyWithoutStar = key.replace(/\*$/, '');
128
+ if (id.startsWith(keyWithoutStar)) {
129
+ const resolvedId = extTry(node_path.resolve(baseUrl || ctx.baseDir, id.replace(keyWithoutStar, value)), ctx);
130
+ return {
131
+ type: 'alias',
132
+ originalId: id,
133
+ resolvedId,
134
+ relativePath: node_path.relative(fileDir, resolvedId),
135
+ aliasPath: value
136
+ };
137
+ }
138
+ }
139
+ return {
140
+ type: 'relative',
141
+ originalId: id,
142
+ resolvedId: extTry(node_path.resolve(fileDir, id), ctx)
143
+ };
144
+ }
145
+ function getFileDependencies(filePath, fileContent, ctx, dependenciesSet, uuid) {
146
+ const dependencieRegexp = /import.*?from.*?(['"])(.*?)\1|import.*?(['"])(.*?)\3|import\(.*?(['"])(.*?)\5.*?\)|export.*?from.*?(['"])(.*?)\7/g;
147
+ const dependencies = [];
148
+ let match = dependencieRegexp.exec(fileContent);
149
+ while(null !== match){
150
+ const [, , id1, , id2, , id3, , id4] = match;
151
+ const id = id1 || id2 || id3 || id4;
152
+ try {
153
+ const { resolvedId, relativePath, type, ...resolveInfo } = tsPathsResolve(id, ctx, filePath);
154
+ if ('alias' === type && relativePath) ctx.runCtx.aliasMap[uuid].push({
155
+ ...resolveInfo,
156
+ relativePath,
157
+ resolvedId
158
+ });
159
+ if (dependenciesSet.has(resolvedId)) {
160
+ match = dependencieRegexp.exec(fileContent);
161
+ continue;
162
+ }
163
+ const depPath = fileRequire.resolve(resolvedId);
164
+ dependencies.push(...getFile(depPath, ctx, id, fileInWorkspace(depPath, ctx)));
165
+ dependenciesSet.add(depPath);
166
+ } catch (error) {
167
+ console.warn(error);
168
+ }
169
+ match = dependencieRegexp.exec(fileContent);
170
+ }
171
+ return dependencies;
172
+ }
173
+ function getFile(filePath, ctx, id, inWorkspace = true) {
174
+ const { runCtx, options } = ctx;
175
+ const { dependenciesSet } = runCtx;
176
+ if (dependenciesSet.has(filePath)) return [];
177
+ const relativePath = node_path.relative(ctx.baseDir, filePath);
178
+ const files = [];
179
+ const uuid = randomUUID();
180
+ const aliases = [];
181
+ ctx.runCtx.aliasMap[uuid] = aliases;
182
+ const fileContent = node_fs.readFileSync(filePath, 'utf-8');
183
+ if (inWorkspace) {
184
+ files.push({
185
+ uuid,
186
+ path: relativePath,
187
+ type: 'registry:file',
188
+ target: `${options.basePath}${node_path.relative(ctx.baseDir, filePath)}`,
189
+ fileType: 'workfile',
190
+ aliases,
191
+ fileContent
192
+ });
193
+ const deps = getFileDependencies(filePath, fileContent, ctx, dependenciesSet, uuid);
194
+ files.push(...deps);
195
+ } else {
196
+ const isDependency = filePath.includes('node_modules');
197
+ if (!isNodeOrgModule(filePath)) files.push({
198
+ uuid,
199
+ path: relativePath,
200
+ id,
201
+ fileType: isDependency ? 'dependency' : 'external',
202
+ aliases,
203
+ fileContent
204
+ });
205
+ }
206
+ return files;
207
+ }
208
+ function readDirFiles(realPath, files, ctx) {
209
+ node_fs.readdirSync(realPath).forEach((file)=>{
210
+ const filePath = node_path.join(realPath, file);
211
+ const isFile = node_fs.statSync(filePath).isFile();
212
+ if (isFile) return void files.push(...getFile(filePath, ctx));
213
+ readDirFiles(filePath, files, ctx);
214
+ });
215
+ }
216
+ function patchFileAndDeps(exportItem, ctx) {
217
+ const { extInfo, files, dependencies, registryDependencies } = exportItem;
218
+ ctx.runCtx.dependenciesSet = new Set();
219
+ if (extInfo.isFile) files.push(...getFile(exportItem.extInfo.realPath, ctx));
220
+ else readDirFiles(extInfo.realPath, files, ctx);
221
+ exportItem.files = files.filter((item)=>{
222
+ if ('workfile' === item.fileType) return true;
223
+ if ('registry' === item.fileType) {
224
+ registryDependencies.push(`./${item.id}.json`);
225
+ return false;
226
+ }
227
+ if ('dependency' === item.fileType) dependencies.push(item.id);
228
+ return false;
229
+ }).map((item)=>{
230
+ const { fileType: _, ...rest } = item;
231
+ return rest;
232
+ });
233
+ ctx.runCtx.dependenciesSet = null;
234
+ }
235
+ function resolveRegistryDependencieUrl(name, ctx) {
236
+ const { options } = ctx;
237
+ return `${options.registryUrl}/${name}.json`;
238
+ }
239
+ function registryItemOptimization(regItem, ctx) {
240
+ const { extInfo } = regItem;
241
+ const { fileMap } = extInfo;
242
+ const { reqistrys } = ctx.runCtx;
243
+ reqistrys.filter((item)=>{
244
+ if (item.name === regItem.name) return false;
245
+ if (item.extInfo.filePaths.some((filePath)=>!fileMap.has(filePath))) return false;
246
+ return true;
247
+ }).forEach((item)=>{
248
+ regItem.registryDependencies.push(resolveRegistryDependencieUrl(item.name, ctx));
249
+ item.extInfo.filePaths.forEach((filePath)=>{
250
+ fileMap.delete(filePath);
251
+ });
252
+ });
253
+ const files = Array.from(fileMap.values());
254
+ return {
255
+ ...regItem,
256
+ files
257
+ };
258
+ }
259
+ function clearExportsFields(ctx) {
260
+ const { exports } = ctx;
261
+ ctx.exports = exports.map((item)=>{
262
+ const { extInfo: _, ...otherItem } = item;
263
+ const files = otherItem.files.map((file)=>{
264
+ const { path: filePath, type, target } = file;
265
+ return {
266
+ path: filePath,
267
+ type,
268
+ target
269
+ };
270
+ });
271
+ return {
272
+ ...otherItem,
273
+ files
274
+ };
275
+ });
276
+ }
277
+ function filesSummary(item) {
278
+ const files = item.files;
279
+ const fileMap = new Map();
280
+ files.forEach((file)=>{
281
+ const { path: filePath } = file;
282
+ fileMap.set(filePath, file);
283
+ });
284
+ item.extInfo.filePaths = Array.from(fileMap.keys());
285
+ item.extInfo.fileMap = fileMap;
286
+ }
287
+ function generateExports(ctx) {
288
+ const { config } = ctx;
289
+ const { exports: _exports } = config;
290
+ const exports = _exports.map((item)=>{
291
+ const { path: _path, ...rest } = item;
292
+ const name = rest.name || getNameFromPath(item, ctx);
293
+ const { resolvedId: realPath } = tsPathsResolve(item.path, ctx, `${ctx.baseDir}/package.json`);
294
+ const isFile = node_fs.statSync(realPath).isFile();
295
+ const resolveId = fileRequire.resolve(realPath);
296
+ const registryItem = {
297
+ title: name,
298
+ name: name,
299
+ description: name,
300
+ registryDependencies: [],
301
+ dependencies: [],
302
+ files: [],
303
+ ...rest,
304
+ type: 'registry:item',
305
+ extInfo: {
306
+ realPath,
307
+ isFile,
308
+ resolveId
309
+ }
310
+ };
311
+ ctx.runCtx.reqistrys.push(registryItem);
312
+ return registryItem;
313
+ }).map((item)=>{
314
+ patchFileAndDeps(item, ctx);
315
+ filesSummary(item);
316
+ return item;
317
+ }).map((item)=>registryItemOptimization(item, ctx));
318
+ ctx.exports = exports;
319
+ return exports;
320
+ }
321
+ function generateRegistryJson(ctx) {
322
+ const { baseDir, options, config, exports } = ctx;
323
+ const { exports: _, $schema: __, ...otherConfig } = config;
324
+ const { outputDir, noRootRegistry } = options;
325
+ const registryJson = JSON.stringify({
326
+ $schema: 'https://ui.shadcn.com/schema/registry.json',
327
+ name: '',
328
+ homepage: '',
329
+ items: exports,
330
+ ...otherConfig
331
+ }, null, 2);
332
+ if (!noRootRegistry) node_fs.writeFileSync(node_path.join(baseDir, 'registry.json'), registryJson);
333
+ node_fs.writeFileSync(node_path.join(outputDir, 'registry.json'), registryJson);
334
+ }
335
+ function aliasTransformToRelative(ctx) {
336
+ const { exports } = ctx;
337
+ exports.forEach((item)=>{
338
+ const { files } = item;
339
+ files.forEach((file)=>{
340
+ const { aliases } = file;
341
+ if (0 === aliases.length) return;
342
+ aliases.forEach((alias)=>{
343
+ const { relativePath, originalId } = alias;
344
+ file.fileContent = file.fileContent.replace(new RegExp(originalId, 'g'), relativePath);
345
+ });
346
+ });
347
+ });
348
+ }
349
+ function generateRegistryItemJson(regItem) {
350
+ const { files: _files, extInfo: _, ...otherConfig } = regItem;
351
+ const files = _files.map((item)=>{
352
+ const { path: fromPath, type, target, fileContent } = item;
353
+ return {
354
+ path: fromPath,
355
+ type,
356
+ target,
357
+ content: fileContent
358
+ };
359
+ });
360
+ return {
361
+ $schema: 'https://ui.shadcn.com/schema/registry-item.json',
362
+ ...otherConfig,
363
+ files
364
+ };
365
+ }
366
+ function generateRegistryItemJsons(ctx) {
367
+ const { exports, options } = ctx;
368
+ const { outputDir } = options;
369
+ aliasTransformToRelative(ctx);
370
+ exports.forEach((item)=>{
371
+ const ouputPath = node_path.join(outputDir, `${item.name}.json`);
372
+ const regJson = generateRegistryItemJson(item);
373
+ node_fs.writeFileSync(ouputPath, JSON.stringify(regJson, null, 2));
374
+ });
375
+ }
376
+ const shadcnRegisterGenerator = createUnplugin((options)=>{
377
+ const ctx = createContext(options);
378
+ return {
379
+ name: 'unplugin-shadcn-register-generator',
380
+ async buildStart () {
381
+ await initContext(ctx);
382
+ generateExports(ctx);
383
+ initOuputDir(ctx);
384
+ generateRegistryItemJsons(ctx);
385
+ clearExportsFields(ctx);
386
+ generateRegistryJson(ctx);
387
+ }
388
+ };
389
+ });
390
+ const src = shadcnRegisterGenerator;
391
+ export default src;
@@ -0,0 +1,38 @@
1
+ import type { TSConfig } from 'pkg-types';
2
+ export interface ShadcnRegisterGeneratorOptions {
3
+ /**
4
+ * registry 仓库地址
5
+ */
6
+ registryUrl: string;
7
+ /**
8
+ * 输出目录
9
+ * @default './public/r'
10
+ */
11
+ outputDir?: string;
12
+ /**
13
+ * 基础 target 路径
14
+ * @default '~/'
15
+ */
16
+ basePath?: string;
17
+ /**
18
+ * 是否不生成根目录的 registry.json
19
+ * @default false
20
+ */
21
+ noRootRegistry?: boolean;
22
+ }
23
+ export interface Context {
24
+ options: Required<ShadcnRegisterGeneratorOptions>;
25
+ baseDir: string;
26
+ config: any;
27
+ exports: any;
28
+ tsConfig: TSConfig;
29
+ runCtx: {
30
+ reqistrys: any[];
31
+ dependenciesSet: Set<string>;
32
+ aliasMap: Record<string, Array<{
33
+ originalId: string;
34
+ relativePath: string;
35
+ resolvedId: string;
36
+ }>>;
37
+ };
38
+ }
@@ -0,0 +1,3 @@
1
+ import type { Context, ShadcnRegisterGeneratorOptions } from '../types';
2
+ export declare function initOuputDir(ctx: Context): void;
3
+ export declare function normalizeOptions(options: ShadcnRegisterGeneratorOptions): Required<ShadcnRegisterGeneratorOptions>;
@@ -0,0 +1,14 @@
1
+ import type { Context, ShadcnRegisterGeneratorOptions } from '../types';
2
+ export declare function initContext(ctx: Context): Promise<void>;
3
+ export declare function createContext(options: ShadcnRegisterGeneratorOptions): {
4
+ options: Required<ShadcnRegisterGeneratorOptions>;
5
+ baseDir: string;
6
+ config: null;
7
+ exports: null;
8
+ tsConfig: any;
9
+ runCtx: {
10
+ reqistrys: any[];
11
+ dependenciesSet: any;
12
+ aliasMap: {};
13
+ };
14
+ };
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../../types';
2
+ export declare function clearExportsFields(ctx: Context): void;
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../../types';
2
+ export declare function getFile(filePath: string, ctx: Context, id?: string, inWorkspace?: boolean): any[];
@@ -0,0 +1,3 @@
1
+ import type { Context } from '../../types';
2
+ export * from './clear-exports-fields';
3
+ export declare function generateExports(ctx: Context): any;
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../../types';
2
+ export declare function patchFileAndDeps(exportItem: any, ctx: Context): void;
@@ -0,0 +1,3 @@
1
+ import type { Context } from '../../types';
2
+ export declare function resolveRegistryDependencieUrl(name: string, ctx: Context): string;
3
+ export declare function registryItemOptimization(regItem: any, ctx: Context): any;
@@ -0,0 +1,2 @@
1
+ export * from './registry';
2
+ export * from './registry-item';
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../../types';
2
+ export declare function generateRegistryItemJsons(ctx: Context): void;
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../../types';
2
+ export declare function generateRegistryJson(ctx: Context): void;
@@ -0,0 +1,2 @@
1
+ import type { Context } from '../types';
2
+ export declare function getNameFromPath(exportItem: any, ctx: Context): string;
@@ -0,0 +1,8 @@
1
+ export * from './base';
2
+ export * from './context';
3
+ export * from './generate-exports';
4
+ export * from './generate-shadcn-registry';
5
+ export * from './get-name-from-path';
6
+ export * from './require';
7
+ export * from './ts-paths-resolve';
8
+ export * from './verify';
@@ -0,0 +1 @@
1
+ export declare const fileRequire: NodeJS.Require;
@@ -0,0 +1,14 @@
1
+ import type { Context } from '../types';
2
+ export declare function tsPathsResolve(id: string, ctx: Context, filePath: string): {
3
+ type: string;
4
+ originalId: string;
5
+ resolvedId: string;
6
+ relativePath?: undefined;
7
+ aliasPath?: undefined;
8
+ } | {
9
+ type: string;
10
+ originalId: string;
11
+ resolvedId: string;
12
+ relativePath: string;
13
+ aliasPath: any;
14
+ };
@@ -0,0 +1,4 @@
1
+ import type { Context } from '../types';
2
+ export declare function isNodeOrgModule(id: string): boolean;
3
+ export declare function pathMatch(realPath: string, id: string, isFile: boolean): boolean;
4
+ export declare function fileInWorkspace(filePath: string, ctx: Context): boolean;
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@cmtlyt/unplugin-shadcn-registry-generate",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "import": "./dist/index.js"
9
+ }
10
+ },
11
+ "types": "./dist/index.d.ts",
12
+ "files": [
13
+ "dist",
14
+ "configuration-schema.json"
15
+ ],
16
+ "dependencies": {
17
+ "pkg-types": "^2.3.0",
18
+ "unplugin": "^2.3.11"
19
+ },
20
+ "devDependencies": {
21
+ "@biomejs/biome": "2.3.8",
22
+ "@commitlint/cli": "^20.3.1",
23
+ "@commitlint/config-conventional": "^20.3.1",
24
+ "@rslib/core": "^0.19.2",
25
+ "@types/node": "^24.10.7",
26
+ "esno": "^4.8.0",
27
+ "husky": "^9.1.7",
28
+ "lint-staged": "^16.2.7",
29
+ "typescript": "^5.9.3"
30
+ },
31
+ "private": false,
32
+ "devEngines": {
33
+ "runtime": {
34
+ "name": "node",
35
+ "version": ">=18.0.0"
36
+ },
37
+ "packageManager": {
38
+ "name": "pnpm"
39
+ }
40
+ },
41
+ "homepage": "https://github.com/cmtlyt/unplugin-shadcn-registry-generate#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/cmtlyt/unplugin-shadcn-registry-generate/issues"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/cmtlyt/unplugin-shadcn-registry-generate.git"
48
+ },
49
+ "keywords": [
50
+ "cmtlyt",
51
+ "unplugin",
52
+ "shadcn",
53
+ "shadcn-plugin",
54
+ "generate-registry"
55
+ ],
56
+ "publishConfig": {
57
+ "access": "public",
58
+ "registry": "https://registry.npmjs.org/"
59
+ },
60
+ "scripts": {
61
+ "build": "rslib build",
62
+ "check": "biome check --write",
63
+ "dev": "rslib build --watch",
64
+ "format": "biome format --write"
65
+ }
66
+ }