inai-react-components 1.5.2 → 1.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/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +81 -101
- package/dist/commands/init.d.ts +8 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +35 -18
- package/dist/commands/status.d.ts +11 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/paths.d.ts +50 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +87 -1
- package/dist/utils/registry-resolver.d.ts +5 -0
- package/dist/utils/registry-resolver.d.ts.map +1 -1
- package/dist/utils/registry-resolver.js +60 -16
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;AA0BrB,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAChD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAsCA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE;IAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAAC,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAAE,EAC1G,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,iBAAiB,GAAG,IAAI,CAc1B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,iBAAiB,EAC5B,cAAc,EAAE,kBAAkB,GACjC,MAAM,CAiBR;AAgRD,wBAAsB,MAAM,CAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAmMpB;AAqCD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,UAAU,CAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqIf"}
|
package/dist/commands/add.js
CHANGED
|
@@ -10,7 +10,7 @@ import { saveSnapshot, sha256, } from "../utils/snapshot.js";
|
|
|
10
10
|
import { fuzzySearchNames } from "../utils/fuzzy-search.js";
|
|
11
11
|
import { normalizeThemeCss, getLocalTailwindCssTemplate, getLegacyTailwindCssTemplate, } from "./init.js";
|
|
12
12
|
import { autoInstallDeps } from "../utils/auto-install.js";
|
|
13
|
-
import { resolveLocalDir, getSourceRoot, rewriteCompanyUiImports, } from "../utils/paths.js";
|
|
13
|
+
import { resolveLocalDir, getSourceRoot, rewriteCompanyUiImports, rewriteLibImports, stripRelativeJsExtensions, } from "../utils/paths.js";
|
|
14
14
|
/**
|
|
15
15
|
* Parse a component spec into its registry namespace, type prefix and name.
|
|
16
16
|
*
|
|
@@ -173,13 +173,25 @@ async function installOne(component, registry, componentsJson, registryDir, root
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
let content = fs.readFileSync(registryFilePath, "utf-8");
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
// Normalize every import in the copied file so the installed code
|
|
177
|
+
// reads consistently regardless of where it came from:
|
|
178
|
+
//
|
|
179
|
+
// 1. `rewriteLibImports` — unifies `./lib/cn.js`, `../lib/cn.js`,
|
|
180
|
+
// and `@company/ui/lib/cn` onto the single `aliases.lib` alias.
|
|
181
|
+
// Runs first so `@company/ui/lib/*` is routed to `lib/`, not
|
|
182
|
+
// rewritten to `aliases.components/lib/` by the next step.
|
|
183
|
+
// 2. `rewriteCompanyUiImports` — blocks/templates reference sibling
|
|
184
|
+
// components via `from "@company/ui/<name>"`; rewrite those to
|
|
185
|
+
// the user's alias (`@/components/ui/<name>`). Components never
|
|
186
|
+
// use this pattern, but running it on everything is a no-op
|
|
187
|
+
// and keeps the pipeline uniform.
|
|
188
|
+
// 3. `stripRelativeJsExtensions` — the source uses `.js` suffixes
|
|
189
|
+
// for `moduleResolution: NodeNext`; consumer projects use
|
|
190
|
+
// bundler resolution so the suffix is unnecessary and visually
|
|
191
|
+
// confusing in `.tsx` files. Strip it from relative/alias specs.
|
|
192
|
+
content = rewriteLibImports(content, componentsJson);
|
|
193
|
+
content = rewriteCompanyUiImports(content, componentsJson);
|
|
194
|
+
content = stripRelativeJsExtensions(content);
|
|
183
195
|
if (options.dryRun) {
|
|
184
196
|
console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, localFilePath)}`));
|
|
185
197
|
}
|
|
@@ -195,15 +207,26 @@ async function installOne(component, registry, componentsJson, registryDir, root
|
|
|
195
207
|
}
|
|
196
208
|
copiedFiles.push(displayName);
|
|
197
209
|
}
|
|
198
|
-
// Internal deps (lib/cn, lib/animations, lib/i18n-context,
|
|
210
|
+
// Internal deps (lib/cn, lib/animations, lib/i18n-context, lib/api-client, …).
|
|
211
|
+
//
|
|
212
|
+
// Destination: the unified `aliases.lib` directory (falls back to
|
|
213
|
+
// `<sourceRoot>/lib/` for legacy `components.json` files without the
|
|
214
|
+
// field). Every component, block, and template shares this one lib
|
|
215
|
+
// tree; their imports are rewritten above via `rewriteLibImports` to
|
|
216
|
+
// point at `aliases.lib`, so placement here must match that alias.
|
|
199
217
|
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
218
|
+
// Collision policy: if a file already exists AND its content matches
|
|
219
|
+
// something the CLI previously wrote (or it's about to be overwritten
|
|
220
|
+
// with the exact same bytes), we treat it as a no-op. Otherwise we
|
|
221
|
+
// respect `force` / `skipExisting` / prompt like any other file — this
|
|
222
|
+
// protects the user's own `lib/utils.ts`, custom `api-client.ts`, etc.
|
|
203
223
|
//
|
|
204
224
|
// Extensions: most lib files are `.ts` but `i18n-context.tsx` contains
|
|
205
225
|
// JSX and must be copied as `.tsx`. We probe both in order.
|
|
206
|
-
const
|
|
226
|
+
const libDirRaw = componentsJson.aliases.lib;
|
|
227
|
+
const libDir = libDirRaw
|
|
228
|
+
? resolveLocalDir(libDirRaw, componentsJson)
|
|
229
|
+
: `${getSourceRoot(componentsJson)}/lib`;
|
|
207
230
|
const copiedInternalDeps = [];
|
|
208
231
|
for (const dep of component.internalDeps) {
|
|
209
232
|
const depBase = dep.split("/").pop();
|
|
@@ -222,102 +245,59 @@ async function installOne(component, registry, componentsJson, registryDir, root
|
|
|
222
245
|
else {
|
|
223
246
|
continue;
|
|
224
247
|
}
|
|
225
|
-
// e.g.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
248
|
+
// e.g. libDir = "src/lib" → target: "src/lib/i18n-context.tsx"
|
|
249
|
+
const depTargetPath = path.join(rootDir, libDir, depFileName);
|
|
250
|
+
// Lib files must go through the same import normalization as
|
|
251
|
+
// everything else — otherwise `i18n-context.tsx` would still
|
|
252
|
+
// contain `from "./i18n-types.js"` (relative-sibling) which breaks
|
|
253
|
+
// under the unified layout if the user's tsconfig ever shifts.
|
|
254
|
+
let depContent = fs.readFileSync(depSourcePath, "utf-8");
|
|
255
|
+
depContent = rewriteLibImports(depContent, componentsJson);
|
|
256
|
+
depContent = rewriteCompanyUiImports(depContent, componentsJson);
|
|
257
|
+
depContent = stripRelativeJsExtensions(depContent);
|
|
258
|
+
// Protect the user's pre-existing lib files. If the destination
|
|
259
|
+
// exists and its content differs from what we're about to write,
|
|
260
|
+
// respect `force`/`skipExisting`/prompt like the main copy loop.
|
|
261
|
+
if (fs.existsSync(depTargetPath)) {
|
|
262
|
+
const existing = fs.readFileSync(depTargetPath, "utf-8");
|
|
263
|
+
if (existing === depContent) {
|
|
264
|
+
// Identical — no work to do.
|
|
265
|
+
copiedInternalDeps.push(dep);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (!options.force) {
|
|
269
|
+
if (options.skipExisting) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (options.dryRun) {
|
|
273
|
+
// Treat as would-overwrite for dry-run logging.
|
|
274
|
+
}
|
|
275
|
+
else if (process.stdin.isTTY) {
|
|
276
|
+
const res = await prompts({
|
|
277
|
+
type: "confirm",
|
|
278
|
+
name: "overwrite",
|
|
279
|
+
message: `Lib file "${path.relative(rootDir, depTargetPath)}" already exists. Overwrite?`,
|
|
280
|
+
initial: false,
|
|
281
|
+
});
|
|
282
|
+
if (!res.overwrite)
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
// Non-interactive and not forced — skip silently to avoid
|
|
287
|
+
// clobbering the user's own implementation (e.g. api-client).
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
229
292
|
if (options.dryRun) {
|
|
230
293
|
console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, depTargetPath)}`));
|
|
231
294
|
}
|
|
232
295
|
else {
|
|
233
296
|
fs.mkdirSync(path.dirname(depTargetPath), { recursive: true });
|
|
234
|
-
fs.writeFileSync(depTargetPath,
|
|
297
|
+
fs.writeFileSync(depTargetPath, depContent);
|
|
235
298
|
}
|
|
236
299
|
copiedInternalDeps.push(dep);
|
|
237
300
|
}
|
|
238
|
-
// Block/template lib: blocks import via `../../lib/animations` and
|
|
239
|
-
// `../../lib/styles` relative to `<blocksDir>/<blockName>/page.tsx`,
|
|
240
|
-
// which resolves two levels up to `path.dirname(blocksDir)/lib/`.
|
|
241
|
-
// Copy the global block lib from `apps/docs/src/registry/lib/` there.
|
|
242
|
-
if (isMultiFile) {
|
|
243
|
-
const blocksDir = resolveLocalDir(componentsJson.aliases.blocks, componentsJson);
|
|
244
|
-
const blockLibDest = path.join(rootDir, path.dirname(blocksDir), "lib");
|
|
245
|
-
for (const libFile of ["animations.ts", "styles.ts"]) {
|
|
246
|
-
const src = path.join(registryDir, "apps", "docs", "src", "registry", "lib", libFile);
|
|
247
|
-
if (!fs.existsSync(src))
|
|
248
|
-
continue;
|
|
249
|
-
const dest = path.join(blockLibDest, libFile);
|
|
250
|
-
if (fs.existsSync(dest) && !options.force)
|
|
251
|
-
continue;
|
|
252
|
-
if (options.dryRun) {
|
|
253
|
-
console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, dest)}`));
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
fs.mkdirSync(blockLibDest, { recursive: true });
|
|
257
|
-
fs.copyFileSync(src, dest);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// Some data-heavy blocks (data-table-full, template-admin-dashboard,
|
|
261
|
-
// detail-panel-table, etc.) import from `../../../lib/api-client` and
|
|
262
|
-
// `../../../lib/api-types`, which resolves to `<sourceRoot>/lib/`.
|
|
263
|
-
// These are integration points with the user's backend that can't be
|
|
264
|
-
// shipped as real code — but we can write minimal stubs so the project
|
|
265
|
-
// compiles out of the box. Stubs are only written if the file doesn't
|
|
266
|
-
// already exist; if the user has a real implementation it stays intact.
|
|
267
|
-
const sourceRoot = getSourceRoot(componentsJson);
|
|
268
|
-
const userLibDir = path.join(rootDir, sourceRoot, "lib");
|
|
269
|
-
const stubApiTypes = path.join(userLibDir, "api-types.ts");
|
|
270
|
-
const stubApiClient = path.join(userLibDir, "api-client.ts");
|
|
271
|
-
if (!fs.existsSync(stubApiTypes) && !options.dryRun) {
|
|
272
|
-
fs.mkdirSync(userLibDir, { recursive: true });
|
|
273
|
-
fs.writeFileSync(stubApiTypes, `// Stub generated by inai-react-components. Replace with your real API types.
|
|
274
|
-
// These types satisfy the shape expected by data-heavy blocks
|
|
275
|
-
// (data-table-full, template-admin-dashboard, detail-panel-table, ...).
|
|
276
|
-
// If you already have a typed API layer, delete this file and point the
|
|
277
|
-
// block imports at your own module instead.
|
|
278
|
-
|
|
279
|
-
export interface PaginationMeta {
|
|
280
|
-
totalRows: number;
|
|
281
|
-
totalPages: number;
|
|
282
|
-
page: number;
|
|
283
|
-
pageSize: number;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export interface PaginatedResponse<T> {
|
|
287
|
-
data: T[];
|
|
288
|
-
pagination: PaginationMeta;
|
|
289
|
-
}
|
|
290
|
-
`);
|
|
291
|
-
}
|
|
292
|
-
if (!fs.existsSync(stubApiClient) && !options.dryRun) {
|
|
293
|
-
fs.mkdirSync(userLibDir, { recursive: true });
|
|
294
|
-
fs.writeFileSync(stubApiClient, `// Stub generated by inai-react-components. Replace with your real API client.
|
|
295
|
-
// Data-heavy blocks call \`fetchPaginated\` and \`downloadCsv\` at runtime.
|
|
296
|
-
// Without a real implementation the app will throw when you interact with
|
|
297
|
-
// those features — wire these up to your backend (fetch, tRPC, REST, etc.).
|
|
298
|
-
|
|
299
|
-
import type { PaginatedResponse } from "./api-types.js";
|
|
300
|
-
|
|
301
|
-
export async function fetchPaginated<T>(
|
|
302
|
-
endpoint: string,
|
|
303
|
-
_params: Record<string, unknown>
|
|
304
|
-
): Promise<PaginatedResponse<T>> {
|
|
305
|
-
throw new Error(
|
|
306
|
-
\`fetchPaginated stub called for "\${endpoint}". Replace <sourceRoot>/lib/api-client.ts with your real API client.\`
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export async function downloadCsv(
|
|
311
|
-
endpoint: string,
|
|
312
|
-
_params: Record<string, unknown>
|
|
313
|
-
): Promise<void> {
|
|
314
|
-
throw new Error(
|
|
315
|
-
\`downloadCsv stub called for "\${endpoint}". Replace <sourceRoot>/lib/api-client.ts with your real CSV exporter.\`
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
`);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
301
|
// Update components.json (skipped in dry-run).
|
|
322
302
|
if (!options.dryRun) {
|
|
323
303
|
const registryVersion = registry.version;
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -245,6 +245,7 @@ export interface ComponentsJson {
|
|
|
245
245
|
components: string;
|
|
246
246
|
blocks: string;
|
|
247
247
|
utils: string;
|
|
248
|
+
lib?: string;
|
|
248
249
|
};
|
|
249
250
|
theme: Theme;
|
|
250
251
|
font: {
|
|
@@ -273,12 +274,14 @@ export declare function getLegacyTailwindCssTemplate(theme: Theme, fontBody: Fon
|
|
|
273
274
|
export declare function normalizeThemeCss(css: string, theme: string): string;
|
|
274
275
|
/**
|
|
275
276
|
* Copies the i18n base files (context, types, defaults) from the registry
|
|
276
|
-
* to `<
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
277
|
+
* to `<sourceRoot>/lib/`. ~75 components import `useUIMessages` from the
|
|
278
|
+
* i18n context; the CLI rewrites those imports at install-time to the
|
|
279
|
+
* unified `aliases.lib` directory, so the files must land there.
|
|
280
|
+
*
|
|
281
|
+
* Never overwrites pre-existing files so a user's custom i18n provider
|
|
282
|
+
* stays intact across re-runs.
|
|
280
283
|
*/
|
|
281
|
-
export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string,
|
|
284
|
+
export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string, libDirRelative: string): string[];
|
|
282
285
|
export declare function runInit(config: InitConfig, targetDir: string, repoUrl?: string): Promise<{
|
|
283
286
|
success: boolean;
|
|
284
287
|
filesCreated: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAGrC,KAAK,KAAK,GAAG,MAAM,CAAC;AAEpB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DR,CAAC;AACX,KAAK,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAUxD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,WAAW,EAAE,UAAU,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -180,6 +180,11 @@ export function buildComponentsJson(config, repoUrl) {
|
|
|
180
180
|
aliasPrefix: "@/",
|
|
181
181
|
};
|
|
182
182
|
const utilsAlias = `${layout.aliasPrefix}lib/utils`;
|
|
183
|
+
// Unified destination for every shared lib file shipped by the CLI
|
|
184
|
+
// (cn, animations, i18n context, api stubs, ...). Stored in alias form
|
|
185
|
+
// so it can be used as an import specifier verbatim and also resolved
|
|
186
|
+
// back to a filesystem path via `resolveLocalDir`.
|
|
187
|
+
const libAlias = `${layout.aliasPrefix}lib`;
|
|
183
188
|
const json = {
|
|
184
189
|
$schema: "https://inai-ui.dev/schema.json",
|
|
185
190
|
style: "default",
|
|
@@ -193,6 +198,7 @@ export function buildComponentsJson(config, repoUrl) {
|
|
|
193
198
|
components: config.componentPath,
|
|
194
199
|
blocks: config.blockPath,
|
|
195
200
|
utils: utilsAlias,
|
|
201
|
+
lib: libAlias,
|
|
196
202
|
},
|
|
197
203
|
theme: config.theme,
|
|
198
204
|
font: {
|
|
@@ -347,25 +353,30 @@ function copyTokensToProject(registryDir, targetDir, theme, sourceRoot) {
|
|
|
347
353
|
}
|
|
348
354
|
/**
|
|
349
355
|
* Copies the i18n base files (context, types, defaults) from the registry
|
|
350
|
-
* to `<
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
356
|
+
* to `<sourceRoot>/lib/`. ~75 components import `useUIMessages` from the
|
|
357
|
+
* i18n context; the CLI rewrites those imports at install-time to the
|
|
358
|
+
* unified `aliases.lib` directory, so the files must land there.
|
|
359
|
+
*
|
|
360
|
+
* Never overwrites pre-existing files so a user's custom i18n provider
|
|
361
|
+
* stays intact across re-runs.
|
|
354
362
|
*/
|
|
355
|
-
export function copyI18nFiles(registryDir, targetDir,
|
|
363
|
+
export function copyI18nFiles(registryDir, targetDir, libDirRelative) {
|
|
356
364
|
if (!registryDir)
|
|
357
365
|
return [];
|
|
358
366
|
const files = ["i18n-context.tsx", "i18n-types.ts", "i18n-defaults.ts"];
|
|
359
367
|
const srcBase = path.join(registryDir, "packages", "ui", "src", "lib");
|
|
360
|
-
const destBase = path.join(targetDir,
|
|
368
|
+
const destBase = path.join(targetDir, libDirRelative);
|
|
361
369
|
fs.mkdirSync(destBase, { recursive: true });
|
|
362
370
|
const copied = [];
|
|
363
371
|
for (const file of files) {
|
|
364
372
|
const src = path.join(srcBase, file);
|
|
365
373
|
if (!fs.existsSync(src))
|
|
366
374
|
continue;
|
|
367
|
-
|
|
368
|
-
|
|
375
|
+
const dest = path.join(destBase, file);
|
|
376
|
+
if (fs.existsSync(dest))
|
|
377
|
+
continue; // don't clobber user files
|
|
378
|
+
fs.copyFileSync(src, dest);
|
|
379
|
+
copied.push(`${libDirRelative}/${file}`);
|
|
369
380
|
}
|
|
370
381
|
return copied;
|
|
371
382
|
}
|
|
@@ -382,15 +393,20 @@ export async function runInit(config, targetDir, repoUrl) {
|
|
|
382
393
|
fs.mkdirSync(componentDir, { recursive: true });
|
|
383
394
|
const blockDir = path.join(targetDir, config.blockPath);
|
|
384
395
|
fs.mkdirSync(blockDir, { recursive: true });
|
|
385
|
-
// 3. Create
|
|
386
|
-
//
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
|
|
396
|
+
// 3. Create the unified lib directory under `<sourceRoot>/lib/` and
|
|
397
|
+
// seed it with `cn.ts`. Every component/block lib file ships here;
|
|
398
|
+
// the CLI rewrites all imports at install-time to point at the
|
|
399
|
+
// `aliases.lib` alias so there's a single source of truth.
|
|
400
|
+
//
|
|
401
|
+
// Never overwrite an existing `cn.ts` — the user may have their own.
|
|
402
|
+
const libDirRelative = `${sourceRoot}/lib`;
|
|
403
|
+
const libDir = path.join(targetDir, libDirRelative);
|
|
390
404
|
fs.mkdirSync(libDir, { recursive: true });
|
|
391
405
|
const cnPath = path.join(libDir, "cn.ts");
|
|
392
|
-
fs.
|
|
393
|
-
|
|
406
|
+
if (!fs.existsSync(cnPath)) {
|
|
407
|
+
fs.writeFileSync(cnPath, getCnTemplate());
|
|
408
|
+
filesCreated.push(`${libDirRelative}/cn.ts`);
|
|
409
|
+
}
|
|
394
410
|
// 4. Copy tokens and create CSS
|
|
395
411
|
const cssRelPath = config.cssEntryPoint ?? `${sourceRoot}/index.css`;
|
|
396
412
|
const cssPath = path.join(targetDir, cssRelPath);
|
|
@@ -400,9 +416,10 @@ export async function runInit(config, targetDir, repoUrl) {
|
|
|
400
416
|
const registryDir = getCacheDir();
|
|
401
417
|
const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme, sourceRoot);
|
|
402
418
|
filesCreated.push(...tokenFiles);
|
|
403
|
-
// Copy i18n base files
|
|
404
|
-
// `./lib/i18n-context.js` imports
|
|
405
|
-
|
|
419
|
+
// Copy i18n base files to the unified lib directory so that components'
|
|
420
|
+
// `./lib/i18n-context.js` imports (rewritten at install-time to the
|
|
421
|
+
// `aliases.lib` alias) resolve.
|
|
422
|
+
const i18nFiles = copyI18nFiles(registryDir, targetDir, libDirRelative);
|
|
406
423
|
filesCreated.push(...i18nFiles);
|
|
407
424
|
fs.writeFileSync(cssPath, getLocalTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
|
|
408
425
|
}
|
|
@@ -17,6 +17,17 @@ export interface ComponentsJsonFile {
|
|
|
17
17
|
blocks: string;
|
|
18
18
|
templates?: string;
|
|
19
19
|
utils: string;
|
|
20
|
+
/**
|
|
21
|
+
* Destination directory for shared library utilities (`cn`, animation
|
|
22
|
+
* helpers, i18n context, API client stubs, …). When set, all lib files
|
|
23
|
+
* copied by `add` land here and imports inside components/blocks are
|
|
24
|
+
* rewritten to use this alias uniformly.
|
|
25
|
+
*
|
|
26
|
+
* Stored in alias form (e.g. `"@/lib"`) so it can be used directly as
|
|
27
|
+
* an import specifier. Falls back to `"${layout.aliasPrefix}lib"` when
|
|
28
|
+
* absent (legacy pre-1.6 configs).
|
|
29
|
+
*/
|
|
30
|
+
lib?: string;
|
|
20
31
|
};
|
|
21
32
|
theme: string;
|
|
22
33
|
font?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const program = new Command();
|
|
|
17
17
|
program
|
|
18
18
|
.name("inai-ui")
|
|
19
19
|
.description("CLI for InAI UI component library")
|
|
20
|
-
.version("1.
|
|
20
|
+
.version("1.6.1");
|
|
21
21
|
program
|
|
22
22
|
.command("init [repo-url]")
|
|
23
23
|
.description("Initialize InAI UI in your project. Optionally pass a Git repo URL to fetch components remotely.")
|
package/dist/utils/paths.d.ts
CHANGED
|
@@ -41,16 +41,65 @@ export declare function getSourceRoot(componentsJson: Pick<ComponentsJsonFile, "
|
|
|
41
41
|
* assume their tsconfig handles it).
|
|
42
42
|
*/
|
|
43
43
|
export declare function getComponentsImportAlias(componentsJson: Pick<ComponentsJsonFile, "aliases" | "layout">): string;
|
|
44
|
+
/**
|
|
45
|
+
* Compute the import-alias form of `aliases.lib`. Used when rewriting
|
|
46
|
+
* every lib import (relative `./lib/cn.js`, compound `../lib/cn.js`, and
|
|
47
|
+
* package `@company/ui/lib/cn`) to a single, consistent alias so the
|
|
48
|
+
* installed code never depends on a particular on-disk layout.
|
|
49
|
+
*
|
|
50
|
+
* Falls back to `${aliasPrefix}lib` when `aliases.lib` is missing — this
|
|
51
|
+
* keeps the CLI compatible with pre-1.6 `components.json` files that
|
|
52
|
+
* don't yet declare the field.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getLibImportAlias(componentsJson: Pick<ComponentsJsonFile, "aliases" | "layout">): string;
|
|
55
|
+
/**
|
|
56
|
+
* Rewrite every lib import in a copied source file to the unified
|
|
57
|
+
* `aliases.lib` alias. This handles:
|
|
58
|
+
* - Component sibling imports: `./lib/cn.js` → `@/lib/cn`
|
|
59
|
+
* - Compound-component imports: `../lib/cn.js` → `@/lib/cn`
|
|
60
|
+
* - Package imports: `@company/ui/lib/cn` → `@/lib/cn`
|
|
61
|
+
*
|
|
62
|
+
* The `.js` suffix (required in the source for `moduleResolution: NodeNext`)
|
|
63
|
+
* is stripped in the process so the resulting code reads naturally in a
|
|
64
|
+
* consumer project using bundler-style resolution (Vite, Next, TanStack
|
|
65
|
+
* Start, Webpack).
|
|
66
|
+
*
|
|
67
|
+
* Side-effect imports (`import "@company/ui/lib/xxx"`) get the same
|
|
68
|
+
* treatment.
|
|
69
|
+
*/
|
|
70
|
+
export declare function rewriteLibImports(source: string, componentsJson: Pick<ComponentsJsonFile, "aliases" | "layout">): string;
|
|
71
|
+
/**
|
|
72
|
+
* Strip `.js` extensions from relative and alias-prefixed imports in a
|
|
73
|
+
* copied source file. This is safe for consumer projects because they
|
|
74
|
+
* almost always use bundler-style module resolution (Vite, Next.js,
|
|
75
|
+
* TanStack Start, Webpack, esbuild), which resolves extensionless
|
|
76
|
+
* imports directly.
|
|
77
|
+
*
|
|
78
|
+
* Handles every common module reference form:
|
|
79
|
+
* - Static: `from "./x.js"`, `import "./x.js"` (side-effect)
|
|
80
|
+
* - Dynamic: `import("./x.js")` and `import(\`./x.js\`)`
|
|
81
|
+
* - Type-only: `typeof import("./x.js")`, `import("./x.js").Foo` (TS
|
|
82
|
+
* inline import types appearing mid-line, not at statement start)
|
|
83
|
+
*
|
|
84
|
+
* Only touches specifiers that start with `./`, `../`, `@/`, `~/`, or
|
|
85
|
+
* `$/` — package specifiers (`react`, `motion/react`, ...) and URLs are
|
|
86
|
+
* left untouched because they might legitimately end in `.js`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function stripRelativeJsExtensions(source: string): string;
|
|
44
89
|
/**
|
|
45
90
|
* Rewrite `@company/ui/*` imports in a block or template file to point
|
|
46
91
|
* at the user's locally-installed components. Without this, block files
|
|
47
92
|
* that `import { Button } from "@company/ui/button"` would fail at
|
|
48
93
|
* compile time because `@company/ui` doesn't exist in the consumer project.
|
|
49
94
|
*
|
|
95
|
+
* Note: `@company/ui/lib/*` is handled separately by `rewriteLibImports`
|
|
96
|
+
* (which must run BEFORE this function) so lib files route to
|
|
97
|
+
* `aliases.lib` instead of `aliases.components/lib`. This function only
|
|
98
|
+
* rewrites the non-lib specifiers that remain.
|
|
99
|
+
*
|
|
50
100
|
* Transformations:
|
|
51
101
|
* - `from "@company/ui/data-table"` → `from "~/components/ui/data-table"`
|
|
52
102
|
* - `from "@company/ui/data-table/sub"` → `from "~/components/ui/data-table/sub"`
|
|
53
|
-
* - `from "@company/ui/lib/animations"` → `from "~/components/ui/lib/animations"`
|
|
54
103
|
* - `from "@company/ui"` (bare barrel) → no rewrite (logged as unsupported)
|
|
55
104
|
*
|
|
56
105
|
* The alias prefix (`~/`, `@/`, etc.) is derived from the project layout
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAER;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAYR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAaR"}
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAER;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAYR;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAiBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAqBR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAYhE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAaR"}
|
package/dist/utils/paths.js
CHANGED
|
@@ -64,16 +64,102 @@ export function getComponentsImportAlias(componentsJson) {
|
|
|
64
64
|
}
|
|
65
65
|
return raw;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Compute the import-alias form of `aliases.lib`. Used when rewriting
|
|
69
|
+
* every lib import (relative `./lib/cn.js`, compound `../lib/cn.js`, and
|
|
70
|
+
* package `@company/ui/lib/cn`) to a single, consistent alias so the
|
|
71
|
+
* installed code never depends on a particular on-disk layout.
|
|
72
|
+
*
|
|
73
|
+
* Falls back to `${aliasPrefix}lib` when `aliases.lib` is missing — this
|
|
74
|
+
* keeps the CLI compatible with pre-1.6 `components.json` files that
|
|
75
|
+
* don't yet declare the field.
|
|
76
|
+
*/
|
|
77
|
+
export function getLibImportAlias(componentsJson) {
|
|
78
|
+
const raw = componentsJson.aliases.lib;
|
|
79
|
+
if (raw) {
|
|
80
|
+
// Already in alias form — return verbatim.
|
|
81
|
+
for (const prefix of KNOWN_PREFIXES) {
|
|
82
|
+
if (raw.startsWith(prefix))
|
|
83
|
+
return raw;
|
|
84
|
+
}
|
|
85
|
+
// Raw path — try to convert via layout.
|
|
86
|
+
const layout = componentsJson.layout;
|
|
87
|
+
if (layout && raw.startsWith(`${layout.sourceRoot}/`)) {
|
|
88
|
+
return `${layout.aliasPrefix}${raw.slice(layout.sourceRoot.length + 1)}`;
|
|
89
|
+
}
|
|
90
|
+
return raw;
|
|
91
|
+
}
|
|
92
|
+
// Fallback for legacy configs: derive from layout.
|
|
93
|
+
const prefix = componentsJson.layout?.aliasPrefix ?? "@/";
|
|
94
|
+
return `${prefix}lib`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Rewrite every lib import in a copied source file to the unified
|
|
98
|
+
* `aliases.lib` alias. This handles:
|
|
99
|
+
* - Component sibling imports: `./lib/cn.js` → `@/lib/cn`
|
|
100
|
+
* - Compound-component imports: `../lib/cn.js` → `@/lib/cn`
|
|
101
|
+
* - Package imports: `@company/ui/lib/cn` → `@/lib/cn`
|
|
102
|
+
*
|
|
103
|
+
* The `.js` suffix (required in the source for `moduleResolution: NodeNext`)
|
|
104
|
+
* is stripped in the process so the resulting code reads naturally in a
|
|
105
|
+
* consumer project using bundler-style resolution (Vite, Next, TanStack
|
|
106
|
+
* Start, Webpack).
|
|
107
|
+
*
|
|
108
|
+
* Side-effect imports (`import "@company/ui/lib/xxx"`) get the same
|
|
109
|
+
* treatment.
|
|
110
|
+
*/
|
|
111
|
+
export function rewriteLibImports(source, componentsJson) {
|
|
112
|
+
const libAlias = getLibImportAlias(componentsJson);
|
|
113
|
+
// 1) Relative imports: `./lib/foo.js`, `../lib/foo.js`, `../../lib/foo.js`
|
|
114
|
+
let result = source.replace(/(from\s+["'])(?:\.\.?\/)+lib\/([a-zA-Z0-9_-]+)(?:\.js)?(["'])/g, (_, pre, name, post) => `${pre}${libAlias}/${name}${post}`);
|
|
115
|
+
result = result.replace(/(import\s+["'])(?:\.\.?\/)+lib\/([a-zA-Z0-9_-]+)(?:\.js)?(["'])/g, (_, pre, name, post) => `${pre}${libAlias}/${name}${post}`);
|
|
116
|
+
// 2) Package imports: `@company/ui/lib/foo`
|
|
117
|
+
result = result.replace(/(from\s+["'])@company\/ui\/lib\/([a-zA-Z0-9_-]+)(?:\.js)?(["'])/g, (_, pre, name, post) => `${pre}${libAlias}/${name}${post}`);
|
|
118
|
+
result = result.replace(/(import\s+["'])@company\/ui\/lib\/([a-zA-Z0-9_-]+)(?:\.js)?(["'])/g, (_, pre, name, post) => `${pre}${libAlias}/${name}${post}`);
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Strip `.js` extensions from relative and alias-prefixed imports in a
|
|
123
|
+
* copied source file. This is safe for consumer projects because they
|
|
124
|
+
* almost always use bundler-style module resolution (Vite, Next.js,
|
|
125
|
+
* TanStack Start, Webpack, esbuild), which resolves extensionless
|
|
126
|
+
* imports directly.
|
|
127
|
+
*
|
|
128
|
+
* Handles every common module reference form:
|
|
129
|
+
* - Static: `from "./x.js"`, `import "./x.js"` (side-effect)
|
|
130
|
+
* - Dynamic: `import("./x.js")` and `import(\`./x.js\`)`
|
|
131
|
+
* - Type-only: `typeof import("./x.js")`, `import("./x.js").Foo` (TS
|
|
132
|
+
* inline import types appearing mid-line, not at statement start)
|
|
133
|
+
*
|
|
134
|
+
* Only touches specifiers that start with `./`, `../`, `@/`, `~/`, or
|
|
135
|
+
* `$/` — package specifiers (`react`, `motion/react`, ...) and URLs are
|
|
136
|
+
* left untouched because they might legitimately end in `.js`.
|
|
137
|
+
*/
|
|
138
|
+
export function stripRelativeJsExtensions(source) {
|
|
139
|
+
// 1) Static `from "..."` and `import "..."` statements.
|
|
140
|
+
const statement = /((?:from|import)\s+[^"'`]*["'`])((?:\.{1,2}\/|[@~$]\/)[^"'`]*)\.js(["'`])/g;
|
|
141
|
+
// 2) Dynamic / inline type `import("...")` calls. These can appear
|
|
142
|
+
// anywhere in a type position, so the preceding keyword isn't
|
|
143
|
+
// constrained to start of a statement.
|
|
144
|
+
const dynamic = /(import\s*\(\s*["'`])((?:\.{1,2}\/|[@~$]\/)[^"'`]*)\.js(["'`])/g;
|
|
145
|
+
return source
|
|
146
|
+
.replace(statement, (_, pre, spec, post) => `${pre}${spec}${post}`)
|
|
147
|
+
.replace(dynamic, (_, pre, spec, post) => `${pre}${spec}${post}`);
|
|
148
|
+
}
|
|
67
149
|
/**
|
|
68
150
|
* Rewrite `@company/ui/*` imports in a block or template file to point
|
|
69
151
|
* at the user's locally-installed components. Without this, block files
|
|
70
152
|
* that `import { Button } from "@company/ui/button"` would fail at
|
|
71
153
|
* compile time because `@company/ui` doesn't exist in the consumer project.
|
|
72
154
|
*
|
|
155
|
+
* Note: `@company/ui/lib/*` is handled separately by `rewriteLibImports`
|
|
156
|
+
* (which must run BEFORE this function) so lib files route to
|
|
157
|
+
* `aliases.lib` instead of `aliases.components/lib`. This function only
|
|
158
|
+
* rewrites the non-lib specifiers that remain.
|
|
159
|
+
*
|
|
73
160
|
* Transformations:
|
|
74
161
|
* - `from "@company/ui/data-table"` → `from "~/components/ui/data-table"`
|
|
75
162
|
* - `from "@company/ui/data-table/sub"` → `from "~/components/ui/data-table/sub"`
|
|
76
|
-
* - `from "@company/ui/lib/animations"` → `from "~/components/ui/lib/animations"`
|
|
77
163
|
* - `from "@company/ui"` (bare barrel) → no rewrite (logged as unsupported)
|
|
78
164
|
*
|
|
79
165
|
* The alias prefix (`~/`, `@/`, etc.) is derived from the project layout
|
|
@@ -5,6 +5,11 @@ export declare function getRegistryCacheDir(name: string): string;
|
|
|
5
5
|
* Clone (or fast-forward) a git registry into the legacy single-cache
|
|
6
6
|
* directory. Preserved for backward compatibility with the v0.5.0
|
|
7
7
|
* code path that called this directly.
|
|
8
|
+
*
|
|
9
|
+
* If a prior cache is present but refuses to fast-forward (dirty tree,
|
|
10
|
+
* diverged history, interrupted previous run), the cache is reset to
|
|
11
|
+
* match origin; if that also fails, the directory is nuked and a fresh
|
|
12
|
+
* clone is done. Users should never have to touch `~/.inai-ui/registry`.
|
|
8
13
|
*/
|
|
9
14
|
export declare function cloneRegistry(repoUrl: string): string;
|
|
10
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;
|
|
1
|
+
{"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AA8CD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAcrD;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CA+FjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAS7D"}
|
|
@@ -15,22 +15,71 @@ export function getCacheDir() {
|
|
|
15
15
|
export function getRegistryCacheDir(name) {
|
|
16
16
|
return path.join(REGISTRIES_CACHE_DIR, name);
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Attempt to refresh an existing git cache to the latest upstream state.
|
|
20
|
+
* Tries `git pull --ff-only` first, and if the working tree is dirty or
|
|
21
|
+
* has diverged from upstream (either of which aborts the fast-forward),
|
|
22
|
+
* falls back to a hard reset + clean so the cache matches origin exactly.
|
|
23
|
+
*
|
|
24
|
+
* The cache is an implementation detail of the CLI — users should never
|
|
25
|
+
* have to edit files inside it, so any local changes are unconditionally
|
|
26
|
+
* discarded in favor of whatever origin currently ships.
|
|
27
|
+
*
|
|
28
|
+
* Returns `true` on success, `false` if both pull and reset failed (in
|
|
29
|
+
* which case the caller should nuke the directory and re-clone).
|
|
30
|
+
*/
|
|
31
|
+
function refreshGitCache(cacheDir) {
|
|
32
|
+
try {
|
|
33
|
+
execSync("git pull --ff-only", { cwd: cacheDir, stdio: "pipe" });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Dirty tree, diverged history, or both. Salvage the clone by
|
|
38
|
+
// fetching fresh refs and resetting hard onto origin's default
|
|
39
|
+
// branch. `git clean -fd` drops any untracked files the user (or a
|
|
40
|
+
// previous botched run) left behind.
|
|
41
|
+
try {
|
|
42
|
+
execSync("git fetch --all --prune", { cwd: cacheDir, stdio: "pipe" });
|
|
43
|
+
// Derive the remote HEAD dynamically so we respect whatever branch
|
|
44
|
+
// origin tracks (main, master, develop, ...).
|
|
45
|
+
const remoteHead = execSync("git symbolic-ref refs/remotes/origin/HEAD", { cwd: cacheDir, stdio: ["pipe", "pipe", "pipe"] })
|
|
46
|
+
.toString()
|
|
47
|
+
.trim();
|
|
48
|
+
execSync(`git reset --hard ${remoteHead}`, {
|
|
49
|
+
cwd: cacheDir,
|
|
50
|
+
stdio: "pipe",
|
|
51
|
+
});
|
|
52
|
+
execSync("git clean -fd", { cwd: cacheDir, stdio: "pipe" });
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
18
60
|
/**
|
|
19
61
|
* Clone (or fast-forward) a git registry into the legacy single-cache
|
|
20
62
|
* directory. Preserved for backward compatibility with the v0.5.0
|
|
21
63
|
* code path that called this directly.
|
|
64
|
+
*
|
|
65
|
+
* If a prior cache is present but refuses to fast-forward (dirty tree,
|
|
66
|
+
* diverged history, interrupted previous run), the cache is reset to
|
|
67
|
+
* match origin; if that also fails, the directory is nuked and a fresh
|
|
68
|
+
* clone is done. Users should never have to touch `~/.inai-ui/registry`.
|
|
22
69
|
*/
|
|
23
70
|
export function cloneRegistry(repoUrl) {
|
|
24
71
|
if (fs.existsSync(path.join(LEGACY_CACHE_DIR, ".git"))) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else {
|
|
28
|
-
fs.mkdirSync(CACHE_BASE, { recursive: true });
|
|
29
|
-
if (fs.existsSync(LEGACY_CACHE_DIR)) {
|
|
30
|
-
fs.rmSync(LEGACY_CACHE_DIR, { recursive: true });
|
|
72
|
+
if (refreshGitCache(LEGACY_CACHE_DIR)) {
|
|
73
|
+
return LEGACY_CACHE_DIR;
|
|
31
74
|
}
|
|
32
|
-
|
|
75
|
+
// Salvage failed — nuke and re-clone below.
|
|
76
|
+
fs.rmSync(LEGACY_CACHE_DIR, { recursive: true, force: true });
|
|
77
|
+
}
|
|
78
|
+
fs.mkdirSync(CACHE_BASE, { recursive: true });
|
|
79
|
+
if (fs.existsSync(LEGACY_CACHE_DIR)) {
|
|
80
|
+
fs.rmSync(LEGACY_CACHE_DIR, { recursive: true });
|
|
33
81
|
}
|
|
82
|
+
execSync(`git clone "${repoUrl}" "${LEGACY_CACHE_DIR}"`, { stdio: "pipe" });
|
|
34
83
|
return LEGACY_CACHE_DIR;
|
|
35
84
|
}
|
|
36
85
|
/**
|
|
@@ -89,18 +138,13 @@ export async function resolveRegistry(registry, projectDir, options = {}) {
|
|
|
89
138
|
const cloneUrl = token ? embedTokenInGitUrl(registry.url, token) : registry.url;
|
|
90
139
|
const branch = registry.branch ?? "main";
|
|
91
140
|
if (fs.existsSync(path.join(cacheDir, ".git"))) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
catch {
|
|
96
|
-
// If pull fails (network hiccup, diverged), fall back to cached copy.
|
|
141
|
+
if (!refreshGitCache(cacheDir)) {
|
|
142
|
+
// Salvage failed — nuke and re-clone below.
|
|
143
|
+
fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
97
144
|
}
|
|
98
145
|
}
|
|
99
|
-
|
|
146
|
+
if (!fs.existsSync(path.join(cacheDir, ".git"))) {
|
|
100
147
|
fs.mkdirSync(REGISTRIES_CACHE_DIR, { recursive: true });
|
|
101
|
-
if (fs.existsSync(cacheDir)) {
|
|
102
|
-
fs.rmSync(cacheDir, { recursive: true });
|
|
103
|
-
}
|
|
104
148
|
execSync(`git clone --branch "${branch}" "${cloneUrl}" "${cacheDir}"`, { stdio: "pipe" });
|
|
105
149
|
}
|
|
106
150
|
return cacheDir;
|
package/package.json
CHANGED