@dsai-io/tools 1.0.7 → 1.2.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/index.js CHANGED
@@ -4,7 +4,7 @@ import path2__default, { relative, basename, extname, join, dirname, parse, reso
4
4
  import { cosmiconfig, cosmiconfigSync } from 'cosmiconfig';
5
5
  import * as fs3 from 'fs';
6
6
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, mkdirSync, rmSync } from 'fs';
7
- import { execSync } from 'child_process';
7
+ import { execFileSync, execSync } from 'child_process';
8
8
  import { createHash } from 'crypto';
9
9
  import fg from 'fast-glob';
10
10
  import { readFile, writeFile } from 'fs/promises';
@@ -976,20 +976,6 @@ var init_line_height = __esm({
976
976
  }
977
977
  });
978
978
 
979
- // src/tokens/style-dictionary/transforms/name.ts
980
- var nameKebab;
981
- var init_name = __esm({
982
- "src/tokens/style-dictionary/transforms/name.ts"() {
983
- nameKebab = {
984
- name: "name/kebab",
985
- type: "name",
986
- transform: (token) => {
987
- return token.path.join("-").replace(/_/g, "-").toLowerCase();
988
- }
989
- };
990
- }
991
- });
992
-
993
979
  // src/tokens/style-dictionary/transforms/name-js-identifier.ts
994
980
  function toPascalCaseSegment3(segment) {
995
981
  const needsNumericPrefix = /^\d/.test(segment);
@@ -1009,6 +995,20 @@ var init_name_js_identifier = __esm({
1009
995
  }
1010
996
  });
1011
997
 
998
+ // src/tokens/style-dictionary/transforms/name.ts
999
+ var nameKebab;
1000
+ var init_name = __esm({
1001
+ "src/tokens/style-dictionary/transforms/name.ts"() {
1002
+ nameKebab = {
1003
+ name: "name/kebab",
1004
+ type: "name",
1005
+ transform: (token) => {
1006
+ return token.path.join("-").replace(/_/g, "-").toLowerCase();
1007
+ }
1008
+ };
1009
+ }
1010
+ });
1011
+
1012
1012
  // src/tokens/style-dictionary/transforms/index.ts
1013
1013
  var transforms_exports = {};
1014
1014
  __export(transforms_exports, {
@@ -1037,8 +1037,8 @@ var init_transforms = __esm({
1037
1037
  init_dimension();
1038
1038
  init_font_weight();
1039
1039
  init_line_height();
1040
- init_name();
1041
1040
  init_name_js_identifier();
1041
+ init_name();
1042
1042
  init_font_weight();
1043
1043
  init_line_height();
1044
1044
  init_dimension();
@@ -1734,13 +1734,29 @@ var globalConfigSchema = z.object({
1734
1734
  framework: frameworkSchema.optional(),
1735
1735
  build: buildConfigSchema.optional()
1736
1736
  });
1737
+ var aliasesConfigSchema = z.object({
1738
+ importAlias: z.string().optional().default("@/"),
1739
+ ui: z.string().optional().default("src/components/ui"),
1740
+ hooks: z.string().optional().default("src/hooks"),
1741
+ utils: z.string().optional().default("src/lib/utils"),
1742
+ components: z.string().optional().default("src/components"),
1743
+ lib: z.string().optional().default("src/lib")
1744
+ });
1745
+ var componentsConfigSchema = z.object({
1746
+ enabled: z.boolean().optional().default(true),
1747
+ registryUrl: z.string().optional().default("https://registry.dsai.dev"),
1748
+ tsx: z.boolean().optional().default(true),
1749
+ overwrite: z.boolean().optional().default(false)
1750
+ });
1737
1751
  var dsaiConfigSchema = z.object({
1738
1752
  $schema: z.string().optional(),
1739
1753
  extends: z.union([z.string(), z.array(z.string())]).optional(),
1740
1754
  global: globalConfigSchema.optional(),
1741
1755
  tokens: tokensConfigSchema.optional(),
1742
1756
  themes: themesConfigSchema.optional(),
1743
- icons: iconsConfigSchema.optional()
1757
+ icons: iconsConfigSchema.optional(),
1758
+ aliases: aliasesConfigSchema.optional(),
1759
+ components: componentsConfigSchema.optional()
1744
1760
  });
1745
1761
  function formatValidationErrors(zodError) {
1746
1762
  return zodError.issues.map((err) => ({
@@ -1778,7 +1794,9 @@ function validateConfigSection(section, config) {
1778
1794
  global: globalConfigSchema,
1779
1795
  tokens: tokensConfigSchema,
1780
1796
  themes: themesConfigSchema,
1781
- icons: iconsConfigSchema
1797
+ icons: iconsConfigSchema,
1798
+ aliases: aliasesConfigSchema,
1799
+ components: componentsConfigSchema
1782
1800
  };
1783
1801
  const schema = sectionSchemas[section];
1784
1802
  if (!schema) {
@@ -1890,6 +1908,20 @@ var defaultIconsConfig = {
1890
1908
  optimize: true,
1891
1909
  prefix: "Icon"
1892
1910
  };
1911
+ var defaultAliasesConfig = {
1912
+ importAlias: "@/",
1913
+ ui: "src/components/ui",
1914
+ hooks: "src/hooks",
1915
+ utils: "src/lib/utils",
1916
+ components: "src/components",
1917
+ lib: "src/lib"
1918
+ };
1919
+ var defaultComponentsConfig = {
1920
+ enabled: true,
1921
+ registryUrl: "https://registry.dsai.dev",
1922
+ tsx: true,
1923
+ overwrite: false
1924
+ };
1893
1925
  var defaultTokensConfig = {
1894
1926
  source: "theme",
1895
1927
  sourceDir: DEFAULT_SOURCE_DIR,
@@ -1924,6 +1956,8 @@ var defaultGlobalConfig = {
1924
1956
  var defaultConfig = {
1925
1957
  tokens: defaultTokensConfig,
1926
1958
  icons: defaultIconsConfig,
1959
+ aliases: defaultAliasesConfig,
1960
+ components: defaultComponentsConfig,
1927
1961
  global: defaultGlobalConfig,
1928
1962
  configDir: process.cwd()
1929
1963
  };
@@ -2187,10 +2221,32 @@ function resolveTokensConfig(config, options) {
2187
2221
  postprocess: config?.postprocess
2188
2222
  };
2189
2223
  }
2224
+ function resolveAliasesConfig(config) {
2225
+ const base = defaultAliasesConfig;
2226
+ return {
2227
+ importAlias: config?.importAlias ?? base.importAlias,
2228
+ ui: config?.ui ?? base.ui,
2229
+ hooks: config?.hooks ?? base.hooks,
2230
+ utils: config?.utils ?? base.utils,
2231
+ components: config?.components ?? base.components,
2232
+ lib: config?.lib ?? base.lib
2233
+ };
2234
+ }
2235
+ function resolveComponentsConfig(config) {
2236
+ const base = defaultComponentsConfig;
2237
+ return {
2238
+ enabled: config?.enabled ?? base.enabled,
2239
+ registryUrl: config?.registryUrl ?? base.registryUrl,
2240
+ tsx: config?.tsx ?? base.tsx,
2241
+ overwrite: config?.overwrite ?? base.overwrite
2242
+ };
2243
+ }
2190
2244
  function applyOverrides(config, overrides) {
2191
2245
  return {
2192
2246
  tokens: overrides.tokens ? { ...config.tokens, ...overrides.tokens } : config.tokens,
2193
2247
  icons: overrides.icons ? { ...config.icons, ...overrides.icons } : config.icons,
2248
+ aliases: overrides.aliases ? { ...config.aliases, ...overrides.aliases } : config.aliases,
2249
+ components: overrides.components ? { ...config.components, ...overrides.components } : config.components,
2194
2250
  global: overrides.global ? { ...config.global, ...overrides.global } : config.global
2195
2251
  };
2196
2252
  }
@@ -2201,6 +2257,8 @@ function resolveConfig(config = {}, options = {}) {
2201
2257
  global: resolveGlobalConfig(mergedConfig.global, options),
2202
2258
  tokens: resolveTokensConfig(mergedConfig.tokens, options),
2203
2259
  icons: resolveIconsConfig(mergedConfig.icons, options),
2260
+ aliases: resolveAliasesConfig(mergedConfig.aliases),
2261
+ components: resolveComponentsConfig(mergedConfig.components),
2204
2262
  configDir
2205
2263
  };
2206
2264
  }
@@ -2216,6 +2274,8 @@ function createResolvedConfig(partial = {}) {
2216
2274
  global: partial.global ?? defaultConfig.global,
2217
2275
  tokens: partial.tokens ?? defaultConfig.tokens,
2218
2276
  icons: partial.icons ?? defaultConfig.icons,
2277
+ aliases: partial.aliases ?? defaultConfig.aliases,
2278
+ components: partial.components ?? defaultConfig.components,
2219
2279
  configDir: partial.configDir ?? process.cwd(),
2220
2280
  configPath: partial.configPath
2221
2281
  };
@@ -9072,6 +9132,1156 @@ async function buildIcons(config, options = {}) {
9072
9132
  result.duration = Date.now() - startTime;
9073
9133
  return result;
9074
9134
  }
9135
+ var registryItemTypeSchema = z.enum([
9136
+ "registry:ui",
9137
+ "registry:hook",
9138
+ "registry:util",
9139
+ "registry:lib",
9140
+ "registry:component",
9141
+ "registry:style",
9142
+ "registry:type"
9143
+ ]);
9144
+ var registryFileSchema = z.object({
9145
+ path: z.string().min(1, "File path is required"),
9146
+ type: registryItemTypeSchema,
9147
+ content: z.string(),
9148
+ target: z.string().optional()
9149
+ });
9150
+ var registryItemSchema = z.object({
9151
+ name: z.string().min(1, "Registry item name is required"),
9152
+ type: registryItemTypeSchema,
9153
+ title: z.string().min(1, "Title is required"),
9154
+ description: z.string().default(""),
9155
+ dependencies: z.array(z.string()).default([]),
9156
+ devDependencies: z.array(z.string()).default([]),
9157
+ registryDependencies: z.array(z.string()).default([]),
9158
+ files: z.array(registryFileSchema).min(1, "At least one file is required"),
9159
+ cssVars: z.object({
9160
+ light: z.record(z.string(), z.string()).optional(),
9161
+ dark: z.record(z.string(), z.string()).optional()
9162
+ }).optional(),
9163
+ categories: z.array(z.string()).optional()
9164
+ });
9165
+ var registryIndexEntrySchema = z.object({
9166
+ name: z.string(),
9167
+ type: registryItemTypeSchema,
9168
+ title: z.string(),
9169
+ description: z.string(),
9170
+ dependencies: z.array(z.string()),
9171
+ registryDependencies: z.array(z.string()),
9172
+ categories: z.array(z.string()).optional()
9173
+ });
9174
+ var registryIndexSchema = z.object({
9175
+ version: z.string(),
9176
+ count: z.number(),
9177
+ items: z.array(registryIndexEntrySchema)
9178
+ });
9179
+
9180
+ // src/registry/component-map.ts
9181
+ var componentMap = {
9182
+ accordion: {
9183
+ type: "registry:ui",
9184
+ title: "Accordion",
9185
+ description: "Collapsible content panels for presenting information in a limited space.",
9186
+ categories: ["disclosure", "layout"]
9187
+ },
9188
+ alert: {
9189
+ type: "registry:ui",
9190
+ title: "Alert",
9191
+ description: "Contextual feedback messages for user actions.",
9192
+ categories: ["feedback"]
9193
+ },
9194
+ avatar: {
9195
+ type: "registry:ui",
9196
+ title: "Avatar",
9197
+ description: "Graphical representation of a user or entity.",
9198
+ categories: ["data-display"]
9199
+ },
9200
+ badge: {
9201
+ type: "registry:ui",
9202
+ title: "Badge",
9203
+ description: "Small count or status indicator, typically displayed on other elements.",
9204
+ categories: ["data-display"]
9205
+ },
9206
+ breadcrumb: {
9207
+ type: "registry:ui",
9208
+ title: "Breadcrumb",
9209
+ description: "Navigation aid showing the current page location within a hierarchy.",
9210
+ categories: ["navigation"]
9211
+ },
9212
+ button: {
9213
+ type: "registry:ui",
9214
+ title: "Button",
9215
+ description: "Trigger for actions and events.",
9216
+ categories: ["actions"]
9217
+ },
9218
+ card: {
9219
+ type: "registry:ui",
9220
+ title: "Card",
9221
+ description: "Flexible container for grouping related content and actions.",
9222
+ categories: ["layout", "data-display"]
9223
+ },
9224
+ "card-list": {
9225
+ type: "registry:ui",
9226
+ title: "CardList",
9227
+ description: "Responsive list of selectable cards with keyboard navigation.",
9228
+ categories: ["layout", "data-display"]
9229
+ },
9230
+ carousel: {
9231
+ type: "registry:ui",
9232
+ title: "Carousel",
9233
+ description: "Slideshow component for cycling through content.",
9234
+ categories: ["data-display"]
9235
+ },
9236
+ checkbox: {
9237
+ type: "registry:ui",
9238
+ title: "Checkbox",
9239
+ description: "Toggle control for boolean selections.",
9240
+ categories: ["forms"]
9241
+ },
9242
+ "checkbox-group": {
9243
+ type: "registry:ui",
9244
+ title: "CheckboxGroup",
9245
+ description: "Managed group of checkboxes with shared state.",
9246
+ categories: ["forms"]
9247
+ },
9248
+ dropdown: {
9249
+ type: "registry:ui",
9250
+ title: "Dropdown",
9251
+ description: "Toggleable overlay menu for displaying a list of actions.",
9252
+ categories: ["navigation", "actions"],
9253
+ npmDependencies: ["@floating-ui/react"]
9254
+ },
9255
+ icon: {
9256
+ type: "registry:ui",
9257
+ title: "Icon",
9258
+ description: "Scalable vector icon component with accessibility support.",
9259
+ categories: ["data-display"]
9260
+ },
9261
+ input: {
9262
+ type: "registry:ui",
9263
+ title: "Input",
9264
+ description: "Text input field with validation and formatting support.",
9265
+ categories: ["forms"]
9266
+ },
9267
+ "list-group": {
9268
+ type: "registry:ui",
9269
+ title: "ListGroup",
9270
+ description: "Flexible component for displaying a series of items.",
9271
+ categories: ["data-display", "navigation"]
9272
+ },
9273
+ modal: {
9274
+ type: "registry:ui",
9275
+ title: "Modal",
9276
+ description: "Dialog overlay for focused content and user interactions.",
9277
+ categories: ["feedback", "disclosure"]
9278
+ },
9279
+ navbar: {
9280
+ type: "registry:ui",
9281
+ title: "Navbar",
9282
+ description: "Responsive navigation header with branding and links.",
9283
+ categories: ["navigation"]
9284
+ },
9285
+ pagination: {
9286
+ type: "registry:ui",
9287
+ title: "Pagination",
9288
+ description: "Navigation controls for paged content.",
9289
+ categories: ["navigation"]
9290
+ },
9291
+ popover: {
9292
+ type: "registry:ui",
9293
+ title: "Popover",
9294
+ description: "Floating content panel anchored to a trigger element.",
9295
+ categories: ["disclosure"],
9296
+ npmDependencies: ["@floating-ui/react"]
9297
+ },
9298
+ progress: {
9299
+ type: "registry:ui",
9300
+ title: "Progress",
9301
+ description: "Visual indicator of task completion.",
9302
+ categories: ["feedback"]
9303
+ },
9304
+ radio: {
9305
+ type: "registry:ui",
9306
+ title: "Radio",
9307
+ description: "Single-select control within a group of options.",
9308
+ categories: ["forms"]
9309
+ },
9310
+ scrollspy: {
9311
+ type: "registry:ui",
9312
+ title: "Scrollspy",
9313
+ description: "Automatically highlights navigation links based on scroll position.",
9314
+ categories: ["navigation"]
9315
+ },
9316
+ select: {
9317
+ type: "registry:ui",
9318
+ title: "Select",
9319
+ description: "Dropdown selector for choosing from a list of options.",
9320
+ categories: ["forms"],
9321
+ npmDependencies: ["@floating-ui/react"]
9322
+ },
9323
+ "selectable-card": {
9324
+ type: "registry:ui",
9325
+ title: "SelectableCard",
9326
+ description: "Card variant that acts as a selectable option.",
9327
+ categories: ["forms", "data-display"]
9328
+ },
9329
+ sheet: {
9330
+ type: "registry:ui",
9331
+ title: "Sheet",
9332
+ description: "Sliding panel overlay from screen edges.",
9333
+ categories: ["disclosure", "layout"]
9334
+ },
9335
+ spinner: {
9336
+ type: "registry:ui",
9337
+ title: "Spinner",
9338
+ description: "Loading indicator for asynchronous operations.",
9339
+ categories: ["feedback"]
9340
+ },
9341
+ switch: {
9342
+ type: "registry:ui",
9343
+ title: "Switch",
9344
+ description: "Toggle control for binary on/off states.",
9345
+ categories: ["forms"]
9346
+ },
9347
+ table: {
9348
+ type: "registry:ui",
9349
+ title: "Table",
9350
+ description: "Data table with sorting, selection, and responsive layout.",
9351
+ categories: ["data-display"]
9352
+ },
9353
+ tabs: {
9354
+ type: "registry:ui",
9355
+ title: "Tabs",
9356
+ description: "Tabbed interface for switching between content panels.",
9357
+ categories: ["navigation", "layout"]
9358
+ },
9359
+ "tabs-pro": {
9360
+ type: "registry:ui",
9361
+ title: "TabsPro",
9362
+ description: "Advanced tabbed interface with closable, sortable, and overflow support.",
9363
+ categories: ["navigation", "layout"]
9364
+ },
9365
+ toast: {
9366
+ type: "registry:ui",
9367
+ title: "Toast",
9368
+ description: "Brief notification messages that auto-dismiss.",
9369
+ categories: ["feedback"]
9370
+ },
9371
+ tooltip: {
9372
+ type: "registry:ui",
9373
+ title: "Tooltip",
9374
+ description: "Informational popup displayed on hover or focus.",
9375
+ categories: ["data-display"],
9376
+ npmDependencies: ["@floating-ui/react"]
9377
+ },
9378
+ typography: {
9379
+ type: "registry:ui",
9380
+ title: "Typography",
9381
+ description: "Text rendering primitives with semantic variants.",
9382
+ categories: ["data-display"]
9383
+ }
9384
+ };
9385
+ var hookMap = {
9386
+ "use-async": {
9387
+ type: "registry:hook",
9388
+ title: "useAsync",
9389
+ description: "Manages async operation lifecycle (loading, error, data states).",
9390
+ categories: ["state"]
9391
+ },
9392
+ "use-callback-ref": {
9393
+ type: "registry:hook",
9394
+ title: "useCallbackRef",
9395
+ description: "Stable callback reference that always points to the latest function.",
9396
+ categories: ["refs"]
9397
+ },
9398
+ "use-click-outside": {
9399
+ type: "registry:hook",
9400
+ title: "useClickOutside",
9401
+ description: "Detects clicks outside of a target element.",
9402
+ categories: ["dom"]
9403
+ },
9404
+ "use-controllable-state": {
9405
+ type: "registry:hook",
9406
+ title: "useControllableState",
9407
+ description: "Manages state that can be either controlled or uncontrolled.",
9408
+ categories: ["state"]
9409
+ },
9410
+ "use-dark-mode": {
9411
+ type: "registry:hook",
9412
+ title: "useDarkMode",
9413
+ description: "Detects and toggles dark mode preference.",
9414
+ categories: ["theme"]
9415
+ },
9416
+ "use-debounce": {
9417
+ type: "registry:hook",
9418
+ title: "useDebounce",
9419
+ description: "Debounces a value or callback over a specified delay.",
9420
+ categories: ["timing"]
9421
+ },
9422
+ "use-field": {
9423
+ type: "registry:hook",
9424
+ title: "useField",
9425
+ description: "Form field state management with validation.",
9426
+ categories: ["forms"]
9427
+ },
9428
+ "use-focus-trap": {
9429
+ type: "registry:hook",
9430
+ title: "useFocusTrap",
9431
+ description: "Traps keyboard focus within a container for modal-like experiences.",
9432
+ categories: ["a11y"]
9433
+ },
9434
+ "use-form": {
9435
+ type: "registry:hook",
9436
+ title: "useForm",
9437
+ description: "Comprehensive form state management with validation.",
9438
+ categories: ["forms"]
9439
+ },
9440
+ "use-hover": {
9441
+ type: "registry:hook",
9442
+ title: "useHover",
9443
+ description: "Tracks hover state of an element with enter/leave delays.",
9444
+ categories: ["dom"]
9445
+ },
9446
+ "use-id": {
9447
+ type: "registry:hook",
9448
+ title: "useId",
9449
+ description: "Generates stable unique identifiers for accessibility attributes.",
9450
+ categories: ["a11y"]
9451
+ },
9452
+ "use-intersection-observer": {
9453
+ type: "registry:hook",
9454
+ title: "useIntersectionObserver",
9455
+ description: "Observes element visibility within the viewport.",
9456
+ categories: ["dom"]
9457
+ },
9458
+ "use-key-press": {
9459
+ type: "registry:hook",
9460
+ title: "useKeyPress",
9461
+ description: "Listens for specific keyboard key presses.",
9462
+ categories: ["dom"]
9463
+ },
9464
+ "use-local-storage": {
9465
+ type: "registry:hook",
9466
+ title: "useLocalStorage",
9467
+ description: "Persists state to localStorage with serialization.",
9468
+ categories: ["state", "storage"]
9469
+ },
9470
+ "use-media-query": {
9471
+ type: "registry:hook",
9472
+ title: "useMediaQuery",
9473
+ description: "Matches CSS media queries and provides responsive breakpoint helpers.",
9474
+ categories: ["responsive"]
9475
+ },
9476
+ "use-mounted": {
9477
+ type: "registry:hook",
9478
+ title: "useMounted",
9479
+ description: "Tracks whether the component is currently mounted.",
9480
+ categories: ["lifecycle"]
9481
+ },
9482
+ "use-previous": {
9483
+ type: "registry:hook",
9484
+ title: "usePrevious",
9485
+ description: "Returns the previous value of a variable across renders.",
9486
+ categories: ["state"]
9487
+ },
9488
+ "use-reduced-motion": {
9489
+ type: "registry:hook",
9490
+ title: "useReducedMotion",
9491
+ description: "Detects user preference for reduced motion.",
9492
+ categories: ["a11y"]
9493
+ },
9494
+ "use-resize-observer": {
9495
+ type: "registry:hook",
9496
+ title: "useResizeObserver",
9497
+ description: "Observes element size changes via ResizeObserver.",
9498
+ categories: ["dom"]
9499
+ },
9500
+ "use-roving-focus": {
9501
+ type: "registry:hook",
9502
+ title: "useRovingFocus",
9503
+ description: "Implements roving tabindex pattern for composite widgets.",
9504
+ categories: ["a11y"]
9505
+ },
9506
+ "use-scroll-lock": {
9507
+ type: "registry:hook",
9508
+ title: "useScrollLock",
9509
+ description: "Prevents body scrolling while active (for modals/overlays).",
9510
+ categories: ["dom"]
9511
+ },
9512
+ "use-session-storage": {
9513
+ type: "registry:hook",
9514
+ title: "useSessionStorage",
9515
+ description: "Persists state to sessionStorage with serialization.",
9516
+ categories: ["state", "storage"]
9517
+ },
9518
+ "use-throttle": {
9519
+ type: "registry:hook",
9520
+ title: "useThrottle",
9521
+ description: "Throttles a value or callback to fire at most once per interval.",
9522
+ categories: ["timing"]
9523
+ }
9524
+ };
9525
+ var utilMap = {
9526
+ cn: {
9527
+ type: "registry:util",
9528
+ title: "cn",
9529
+ description: "Conditional class name composition utility.",
9530
+ categories: ["styling"]
9531
+ },
9532
+ a11y: {
9533
+ type: "registry:util",
9534
+ title: "a11y",
9535
+ description: "Accessibility utilities including screen reader announcements and ARIA helpers.",
9536
+ categories: ["a11y"]
9537
+ },
9538
+ async: {
9539
+ type: "registry:util",
9540
+ title: "async",
9541
+ description: "Async operation utilities: abortable tasks, queues, exponential backoff.",
9542
+ categories: ["async"]
9543
+ },
9544
+ browser: {
9545
+ type: "registry:util",
9546
+ title: "browser",
9547
+ description: "Browser environment detection and feature checks.",
9548
+ categories: ["platform"]
9549
+ },
9550
+ collections: {
9551
+ type: "registry:util",
9552
+ title: "collections",
9553
+ description: "Collection utilities: chunk, paginate, memoize, selectors.",
9554
+ categories: ["data"]
9555
+ },
9556
+ color: {
9557
+ type: "registry:util",
9558
+ title: "color",
9559
+ description: "Color manipulation utilities: contrast, luminance, hex/rgb conversion.",
9560
+ categories: ["styling"]
9561
+ },
9562
+ date: {
9563
+ type: "registry:util",
9564
+ title: "date",
9565
+ description: "Date formatting and relative time utilities.",
9566
+ categories: ["formatting"]
9567
+ },
9568
+ "merge-refs": {
9569
+ type: "registry:util",
9570
+ title: "mergeRefs",
9571
+ description: "Merges multiple React refs into a single callback ref.",
9572
+ categories: ["refs"]
9573
+ },
9574
+ dx: {
9575
+ type: "registry:util",
9576
+ title: "dx",
9577
+ description: "Developer experience helpers: component creation, context factories, polymorphic patterns.",
9578
+ categories: ["dx"]
9579
+ },
9580
+ forms: {
9581
+ type: "registry:util",
9582
+ title: "forms",
9583
+ description: "Form utilities: validators, field error extraction, dirty checking.",
9584
+ categories: ["forms"]
9585
+ },
9586
+ keyboard: {
9587
+ type: "registry:util",
9588
+ title: "keyboard",
9589
+ description: "Keyboard event helpers for detecting specific keys.",
9590
+ categories: ["dom"]
9591
+ },
9592
+ layout: {
9593
+ type: "registry:util",
9594
+ title: "layout",
9595
+ description: "Layout measurement utilities: element bounds, viewport size, resize observation.",
9596
+ categories: ["dom"]
9597
+ },
9598
+ misc: {
9599
+ type: "registry:util",
9600
+ title: "misc",
9601
+ description: "Miscellaneous utilities: clear icon, safe input props, event helpers.",
9602
+ categories: ["misc"]
9603
+ },
9604
+ motion: {
9605
+ type: "registry:util",
9606
+ title: "motion",
9607
+ description: "Animation utilities: spring physics, easing functions, distance calculations.",
9608
+ categories: ["animation"]
9609
+ },
9610
+ number: {
9611
+ type: "registry:util",
9612
+ title: "number",
9613
+ description: "Number formatting and clamping utilities.",
9614
+ categories: ["formatting"]
9615
+ },
9616
+ object: {
9617
+ type: "registry:util",
9618
+ title: "object",
9619
+ description: "Object manipulation utilities: deep merge, pick, omit.",
9620
+ categories: ["data"]
9621
+ },
9622
+ platform: {
9623
+ type: "registry:util",
9624
+ title: "platform",
9625
+ description: "Platform detection utilities: browser, OS, device pixel ratio, text direction.",
9626
+ categories: ["platform"]
9627
+ },
9628
+ responsive: {
9629
+ type: "registry:util",
9630
+ title: "responsive",
9631
+ description: "Responsive design utilities.",
9632
+ categories: ["responsive"]
9633
+ },
9634
+ safety: {
9635
+ type: "registry:util",
9636
+ title: "safety",
9637
+ description: "Security utilities: clipboard access, crypto ID generation, token generation.",
9638
+ categories: ["security"]
9639
+ },
9640
+ string: {
9641
+ type: "registry:util",
9642
+ title: "string",
9643
+ description: "String manipulation utilities: capitalize, slugify, variant classes.",
9644
+ categories: ["formatting"]
9645
+ },
9646
+ telemetry: {
9647
+ type: "registry:util",
9648
+ title: "telemetry",
9649
+ description: "Telemetry utilities: error catching, performance measurement, timing.",
9650
+ categories: ["observability"]
9651
+ },
9652
+ timing: {
9653
+ type: "registry:util",
9654
+ title: "timing",
9655
+ description: "Timing utilities: debounce and throttle functions.",
9656
+ categories: ["timing"]
9657
+ },
9658
+ types: {
9659
+ type: "registry:util",
9660
+ title: "types",
9661
+ description: "Shared type guards and type utilities.",
9662
+ categories: ["types"]
9663
+ },
9664
+ validation: {
9665
+ type: "registry:util",
9666
+ title: "validation",
9667
+ description: "Input validation utilities: email, URL, href safety checks.",
9668
+ categories: ["validation"]
9669
+ }
9670
+ };
9671
+ var directoryToRegistryName = {
9672
+ Accordion: "accordion",
9673
+ Alert: "alert",
9674
+ Avatar: "avatar",
9675
+ Badge: "badge",
9676
+ Breadcrumb: "breadcrumb",
9677
+ Button: "button",
9678
+ Card: "card",
9679
+ CardList: "card-list",
9680
+ Carousel: "carousel",
9681
+ Checkbox: "checkbox",
9682
+ CheckboxGroup: "checkbox-group",
9683
+ Dropdown: "dropdown",
9684
+ Icon: "icon",
9685
+ Input: "input",
9686
+ ListGroup: "list-group",
9687
+ Modal: "modal",
9688
+ Navbar: "navbar",
9689
+ Pagination: "pagination",
9690
+ Popover: "popover",
9691
+ Progress: "progress",
9692
+ Radio: "radio",
9693
+ Scrollspy: "scrollspy",
9694
+ Select: "select",
9695
+ SelectableCard: "selectable-card",
9696
+ Sheet: "sheet",
9697
+ Spinner: "spinner",
9698
+ Switch: "switch",
9699
+ Table: "table",
9700
+ Tabs: "tabs",
9701
+ TabsPro: "tabs-pro",
9702
+ Toast: "toast",
9703
+ Tooltip: "tooltip",
9704
+ Typography: "typography"
9705
+ };
9706
+ var hookDirectoryToRegistryName = {
9707
+ useAsync: "use-async",
9708
+ useCallbackRef: "use-callback-ref",
9709
+ useClickOutside: "use-click-outside",
9710
+ useControllableState: "use-controllable-state",
9711
+ useDarkMode: "use-dark-mode",
9712
+ useDebounce: "use-debounce",
9713
+ useField: "use-field",
9714
+ useFocusTrap: "use-focus-trap",
9715
+ useForm: "use-form",
9716
+ useHover: "use-hover",
9717
+ useId: "use-id",
9718
+ useIntersectionObserver: "use-intersection-observer",
9719
+ useKeyPress: "use-key-press",
9720
+ useLocalStorage: "use-local-storage",
9721
+ useMediaQuery: "use-media-query",
9722
+ useMounted: "use-mounted",
9723
+ usePrevious: "use-previous",
9724
+ useReducedMotion: "use-reduced-motion",
9725
+ useResizeObserver: "use-resize-observer",
9726
+ useRovingFocus: "use-roving-focus",
9727
+ useScrollLock: "use-scroll-lock",
9728
+ useSessionStorage: "use-session-storage",
9729
+ useThrottle: "use-throttle"
9730
+ };
9731
+
9732
+ // src/registry/builder.ts
9733
+ var EXCLUDE_PATTERNS = [
9734
+ /\.test\.(tsx?|jsx?)$/,
9735
+ /\.spec\.(tsx?|jsx?)$/,
9736
+ /\.stories\.(tsx?|jsx?)$/,
9737
+ /\.figma\.(tsx?|jsx?)$/,
9738
+ /\.a11y\.test\./,
9739
+ /\.security\.test\./,
9740
+ /\.integration\.test\./,
9741
+ /README\.md$/
9742
+ ];
9743
+ var REACT_BUILTINS = /* @__PURE__ */ new Set(["react", "react-dom", "react/jsx-runtime", "react-dom/client"]);
9744
+ var UTIL_SUBPATH_TO_REGISTRY = {
9745
+ index: "cn",
9746
+ keyboard: "keyboard",
9747
+ dom: "merge-refs",
9748
+ "dom/mergeRefs": "merge-refs",
9749
+ browser: "browser",
9750
+ validation: "validation",
9751
+ string: "string",
9752
+ misc: "misc",
9753
+ a11y: "a11y",
9754
+ types: "types",
9755
+ async: "async",
9756
+ collections: "collections",
9757
+ color: "color",
9758
+ date: "date",
9759
+ dx: "dx",
9760
+ forms: "forms",
9761
+ layout: "layout",
9762
+ motion: "motion",
9763
+ number: "number",
9764
+ object: "object",
9765
+ platform: "platform",
9766
+ responsive: "responsive",
9767
+ safety: "safety",
9768
+ telemetry: "telemetry",
9769
+ timing: "timing"
9770
+ };
9771
+ function shouldIncludeFile(filePath) {
9772
+ const ext = extname(filePath);
9773
+ if (![".ts", ".tsx", ".css"].includes(ext)) return false;
9774
+ return !EXCLUDE_PATTERNS.some((pattern) => pattern.test(filePath));
9775
+ }
9776
+ function readSourceFiles(dirPath) {
9777
+ if (!existsSync(dirPath) || !statSync(dirPath).isDirectory()) return [];
9778
+ const results = [];
9779
+ for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
9780
+ const fullPath = join(dirPath, entry.name);
9781
+ if (entry.isDirectory()) {
9782
+ for (const sub of readdirSync(fullPath, { withFileTypes: true })) {
9783
+ if (sub.isFile()) {
9784
+ const subPath = join(fullPath, sub.name);
9785
+ if (shouldIncludeFile(subPath)) {
9786
+ results.push({ path: relative(dirPath, subPath), content: readFileSync(subPath, "utf-8") });
9787
+ }
9788
+ }
9789
+ }
9790
+ } else if (entry.isFile() && shouldIncludeFile(fullPath)) {
9791
+ results.push({ path: entry.name, content: readFileSync(fullPath, "utf-8") });
9792
+ }
9793
+ }
9794
+ return results;
9795
+ }
9796
+ function extractCnSource(utilsIndexPath) {
9797
+ const content = readFileSync(utilsIndexPath, "utf-8");
9798
+ const cnPattern = /(\/\*\*[\s\S]*?\*\/\s*)?export function cn\b[\s\S]*?\n\}/;
9799
+ const match = cnPattern.exec(content);
9800
+ return match ? match[0] : "export function cn(...classes: (string | boolean | undefined | null)[]): string {\n return classes.filter(Boolean).join(' ');\n}";
9801
+ }
9802
+ function analyzeImports(files, knownNpmDeps) {
9803
+ const registryDeps = /* @__PURE__ */ new Set();
9804
+ const npmDeps = new Set(knownNpmDeps);
9805
+ const importPattern = /(?:import|export)\s+(?:[\s\S]*?)\s+from\s+['"]([^'"]+)['"]/g;
9806
+ for (const file of files) {
9807
+ let m;
9808
+ importPattern.lastIndex = 0;
9809
+ while ((m = importPattern.exec(file.content)) !== null) {
9810
+ const specifier = m[1] ?? "";
9811
+ const typesPattern = /\.\.\/(?:\.\.\/)?types(?:\/.*)?$/;
9812
+ if (typesPattern.test(specifier)) {
9813
+ registryDeps.add("dsai-types");
9814
+ continue;
9815
+ }
9816
+ const hookPattern = /\.\.\/(?:\.\.\/)?hooks\/(\w+)/;
9817
+ const hookMatch = hookPattern.exec(specifier);
9818
+ if (hookMatch && hookMatch[1]) {
9819
+ const regName = hookDirectoryToRegistryName[hookMatch[1]];
9820
+ if (regName) registryDeps.add(regName);
9821
+ continue;
9822
+ }
9823
+ const utilPattern = /\.\.\/(?:\.\.\/)?utils(?:\/(.+))?$/;
9824
+ const utilMatch = utilPattern.exec(specifier);
9825
+ if (utilMatch) {
9826
+ const subpath = utilMatch[1] ?? "index";
9827
+ const regName = UTIL_SUBPATH_TO_REGISTRY[subpath];
9828
+ if (regName) registryDeps.add(regName);
9829
+ continue;
9830
+ }
9831
+ const compPattern = /^\.\.\/(\.\.\/)?(?:components\/)?([A-Z]\w+)(?:\/.*)?$/;
9832
+ const compMatch = compPattern.exec(specifier);
9833
+ if (compMatch && compMatch[2]) {
9834
+ const compDir = compMatch[2];
9835
+ const regName = directoryToRegistryName[compDir];
9836
+ if (regName) registryDeps.add(regName);
9837
+ continue;
9838
+ }
9839
+ if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
9840
+ const parts = specifier.split("/");
9841
+ const pkgName = specifier.startsWith("@") && parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0] ?? specifier;
9842
+ if (pkgName && !REACT_BUILTINS.has(pkgName) && !pkgName.startsWith("@dsai-io/")) {
9843
+ npmDeps.add(pkgName);
9844
+ }
9845
+ }
9846
+ }
9847
+ }
9848
+ return { registryDeps, npmDeps };
9849
+ }
9850
+ function buildComponentItem(name, dirPath, log) {
9851
+ const meta = componentMap[name];
9852
+ if (!meta) {
9853
+ log(` [WARN] No metadata for component "${name}", skipping`);
9854
+ return null;
9855
+ }
9856
+ const sourceFiles = readSourceFiles(dirPath);
9857
+ if (sourceFiles.length === 0) {
9858
+ log(` [WARN] No source files found in ${dirPath}`);
9859
+ return null;
9860
+ }
9861
+ const { registryDeps, npmDeps } = analyzeImports(sourceFiles, meta.npmDependencies ?? []);
9862
+ const files = sourceFiles.map((f) => ({
9863
+ path: f.path,
9864
+ type: extname(f.path) === ".css" ? "registry:style" : meta.type,
9865
+ content: f.content
9866
+ }));
9867
+ return {
9868
+ name,
9869
+ type: meta.type,
9870
+ title: meta.title,
9871
+ description: meta.description,
9872
+ dependencies: [...npmDeps].sort(),
9873
+ devDependencies: [],
9874
+ registryDependencies: [...registryDeps].sort(),
9875
+ files,
9876
+ categories: meta.categories
9877
+ };
9878
+ }
9879
+ function buildHookItem(name, dirPath, log) {
9880
+ const meta = hookMap[name];
9881
+ if (!meta) {
9882
+ log(` [WARN] No metadata for hook "${name}", skipping`);
9883
+ return null;
9884
+ }
9885
+ const sourceFiles = readSourceFiles(dirPath);
9886
+ if (sourceFiles.length === 0) {
9887
+ log(` [WARN] No source files found in ${dirPath}`);
9888
+ return null;
9889
+ }
9890
+ const { registryDeps, npmDeps } = analyzeImports(sourceFiles, meta.npmDependencies ?? []);
9891
+ const files = sourceFiles.map((f) => ({
9892
+ path: f.path,
9893
+ type: extname(f.path) === ".css" ? "registry:style" : meta.type,
9894
+ content: f.content
9895
+ }));
9896
+ return {
9897
+ name,
9898
+ type: meta.type,
9899
+ title: meta.title,
9900
+ description: meta.description,
9901
+ dependencies: [...npmDeps].sort(),
9902
+ devDependencies: [],
9903
+ registryDependencies: [...registryDeps].sort(),
9904
+ files,
9905
+ categories: meta.categories
9906
+ };
9907
+ }
9908
+ function buildUtilItem(name, reactSrcDir, log) {
9909
+ const meta = utilMap[name];
9910
+ if (!meta) {
9911
+ log(` [WARN] No metadata for util "${name}", skipping`);
9912
+ return null;
9913
+ }
9914
+ let files;
9915
+ let registryDeps = /* @__PURE__ */ new Set();
9916
+ let npmDeps = /* @__PURE__ */ new Set();
9917
+ if (name === "cn") {
9918
+ const indexPath = join(reactSrcDir, "utils", "index.ts");
9919
+ const cnSource = extractCnSource(indexPath);
9920
+ files = [{ path: "cn.ts", type: "registry:util", content: cnSource }];
9921
+ } else if (name === "merge-refs") {
9922
+ const dirPath = join(reactSrcDir, "utils", "dom");
9923
+ const sourceFiles = readSourceFiles(dirPath);
9924
+ const analyzed = analyzeImports(sourceFiles, []);
9925
+ registryDeps = analyzed.registryDeps;
9926
+ npmDeps = analyzed.npmDeps;
9927
+ files = sourceFiles.map((f) => ({
9928
+ path: `dom/${f.path}`,
9929
+ type: extname(f.path) === ".css" ? "registry:style" : "registry:util",
9930
+ content: f.content
9931
+ }));
9932
+ } else {
9933
+ const dirPath = join(reactSrcDir, "utils", name);
9934
+ if (!existsSync(dirPath) || !statSync(dirPath).isDirectory()) {
9935
+ log(` [WARN] Util directory not found: ${dirPath}`);
9936
+ return null;
9937
+ }
9938
+ const sourceFiles = readSourceFiles(dirPath);
9939
+ if (sourceFiles.length === 0) {
9940
+ log(` [WARN] No source files found in ${dirPath}`);
9941
+ return null;
9942
+ }
9943
+ const analyzed = analyzeImports(sourceFiles, []);
9944
+ registryDeps = analyzed.registryDeps;
9945
+ npmDeps = analyzed.npmDeps;
9946
+ files = sourceFiles.map((f) => ({
9947
+ path: `${name}/${f.path}`,
9948
+ type: extname(f.path) === ".css" ? "registry:style" : "registry:util",
9949
+ content: f.content
9950
+ }));
9951
+ }
9952
+ return {
9953
+ name,
9954
+ type: meta.type,
9955
+ title: meta.title,
9956
+ description: meta.description,
9957
+ dependencies: [...npmDeps].sort(),
9958
+ devDependencies: [],
9959
+ registryDependencies: [...registryDeps].sort(),
9960
+ files,
9961
+ categories: meta.categories
9962
+ };
9963
+ }
9964
+ function buildTypesItem(reactSrcDir, log) {
9965
+ const typesDir = join(reactSrcDir, "types");
9966
+ const sourceFiles = readSourceFiles(typesDir);
9967
+ if (sourceFiles.length === 0) {
9968
+ log(" [WARN] No type files found");
9969
+ return null;
9970
+ }
9971
+ const files = sourceFiles.map((f) => {
9972
+ let content = f.content;
9973
+ content = content.replace(/export \{[^}]*\} from ['"]\.\.\/utils\/[^'"]+['"];?\n?/g, "");
9974
+ return {
9975
+ path: `types/${f.path}`,
9976
+ type: "registry:type",
9977
+ content
9978
+ };
9979
+ });
9980
+ return {
9981
+ name: "dsai-types",
9982
+ type: "registry:type",
9983
+ title: "Shared Types",
9984
+ description: "Shared type definitions (SafeHTMLAttributes, ComponentSize, PolymorphicComponentProps, etc.)",
9985
+ dependencies: [],
9986
+ devDependencies: [],
9987
+ registryDependencies: [],
9988
+ files,
9989
+ categories: ["types"]
9990
+ };
9991
+ }
9992
+ function buildRegistry(options) {
9993
+ const { reactSrcDir, outputDir, verbose = false } = options;
9994
+ const log = verbose ? (msg) => console.log(msg) : (_msg) => {
9995
+ };
9996
+ const componentsDir = join(reactSrcDir, "components");
9997
+ const hooksDir = join(reactSrcDir, "hooks");
9998
+ const allItems = [];
9999
+ log("[registry] Scanning components...");
10000
+ if (existsSync(componentsDir)) {
10001
+ for (const entry of readdirSync(componentsDir, { withFileTypes: true })) {
10002
+ if (!entry.isDirectory()) continue;
10003
+ const dirName = entry.name;
10004
+ const registryName = directoryToRegistryName[dirName];
10005
+ if (!registryName) {
10006
+ log(` [SKIP] Unknown component directory: ${dirName}`);
10007
+ continue;
10008
+ }
10009
+ log(` Building ${registryName}...`);
10010
+ const item = buildComponentItem(registryName, join(componentsDir, dirName), log);
10011
+ if (item) allItems.push(item);
10012
+ }
10013
+ }
10014
+ log("[registry] Scanning hooks...");
10015
+ if (existsSync(hooksDir)) {
10016
+ for (const entry of readdirSync(hooksDir, { withFileTypes: true })) {
10017
+ if (!entry.isDirectory()) continue;
10018
+ const dirName = entry.name;
10019
+ const registryName = hookDirectoryToRegistryName[dirName];
10020
+ if (!registryName) {
10021
+ log(` [SKIP] Unknown hook directory: ${dirName}`);
10022
+ continue;
10023
+ }
10024
+ log(` Building ${registryName}...`);
10025
+ const item = buildHookItem(registryName, join(hooksDir, dirName), log);
10026
+ if (item) allItems.push(item);
10027
+ }
10028
+ }
10029
+ log("[registry] Scanning utils...");
10030
+ for (const name of Object.keys(utilMap)) {
10031
+ log(` Building ${name}...`);
10032
+ const item = buildUtilItem(name, reactSrcDir, log);
10033
+ if (item) allItems.push(item);
10034
+ }
10035
+ log("[registry] Building shared types...");
10036
+ const typesItem = buildTypesItem(reactSrcDir, log);
10037
+ if (typesItem) {
10038
+ allItems.push(typesItem);
10039
+ log(` Built dsai-types (${typesItem.files.length} files)`);
10040
+ }
10041
+ log(`[registry] Writing ${allItems.length} items to ${outputDir}...`);
10042
+ for (const sub of ["components", "hooks", "utils", "types"]) {
10043
+ const dir = join(outputDir, sub);
10044
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
10045
+ }
10046
+ const typeToSubdir = {
10047
+ "registry:ui": "components",
10048
+ "registry:component": "components",
10049
+ "registry:hook": "hooks",
10050
+ "registry:util": "utils",
10051
+ "registry:lib": "utils",
10052
+ "registry:type": "types"
10053
+ };
10054
+ for (const item of allItems) {
10055
+ const subdir = typeToSubdir[item.type] ?? "utils";
10056
+ const filePath = join(outputDir, subdir, `${item.name}.json`);
10057
+ writeFileSync(filePath, JSON.stringify(item, null, 2) + "\n", "utf-8");
10058
+ log(` Wrote ${relative(outputDir, filePath)}`);
10059
+ }
10060
+ const indexEntries = allItems.map((item) => ({
10061
+ name: item.name,
10062
+ type: item.type,
10063
+ title: item.title,
10064
+ description: item.description,
10065
+ dependencies: item.dependencies,
10066
+ registryDependencies: item.registryDependencies,
10067
+ categories: item.categories
10068
+ }));
10069
+ const registryIndex = {
10070
+ version: "0.1.0",
10071
+ count: indexEntries.length,
10072
+ items: indexEntries
10073
+ };
10074
+ writeFileSync(join(outputDir, "index.json"), JSON.stringify(registryIndex, null, 2) + "\n", "utf-8");
10075
+ log(`[registry] Wrote index.json (${registryIndex.count} items)`);
10076
+ return registryIndex;
10077
+ }
10078
+ function loadItem(name, registryDir) {
10079
+ const subdirs = ["components", "hooks", "utils", "lib", "styles", "types"];
10080
+ for (const sub of subdirs) {
10081
+ const filePath = join(registryDir, sub, `${name}.json`);
10082
+ if (existsSync(filePath)) {
10083
+ return JSON.parse(readFileSync(filePath, "utf-8"));
10084
+ }
10085
+ }
10086
+ return null;
10087
+ }
10088
+ function resolveTree(names, registryDir) {
10089
+ const visited = /* @__PURE__ */ new Map();
10090
+ const queue = [...names];
10091
+ while (queue.length > 0) {
10092
+ const name = queue.shift();
10093
+ if (visited.has(name)) continue;
10094
+ const item = loadItem(name, registryDir);
10095
+ if (!item) {
10096
+ throw new Error(`Registry item "${name}" not found. Run \`dsai registry build\` or check the name.`);
10097
+ }
10098
+ visited.set(name, item);
10099
+ for (const dep of item.registryDependencies) {
10100
+ if (!visited.has(dep)) queue.push(dep);
10101
+ }
10102
+ }
10103
+ const inDeg = /* @__PURE__ */ new Map();
10104
+ for (const [name, item] of visited) {
10105
+ inDeg.set(name, item.registryDependencies.filter((d) => visited.has(d)).length);
10106
+ }
10107
+ const sorted = [];
10108
+ const ready = [];
10109
+ for (const [name, deg] of inDeg) {
10110
+ if (deg === 0) ready.push(name);
10111
+ }
10112
+ while (ready.length > 0) {
10113
+ const name = ready.shift();
10114
+ sorted.push(visited.get(name));
10115
+ for (const [otherName, otherItem] of visited) {
10116
+ if (otherItem.registryDependencies.includes(name)) {
10117
+ const newDeg = (inDeg.get(otherName) ?? 1) - 1;
10118
+ inDeg.set(otherName, newDeg);
10119
+ if (newDeg === 0) ready.push(otherName);
10120
+ }
10121
+ }
10122
+ }
10123
+ if (sorted.length !== visited.size) {
10124
+ const missing = [...visited.keys()].filter((n) => !sorted.some((s) => s.name === n));
10125
+ throw new Error(`Circular dependency detected involving: ${missing.join(", ")}`);
10126
+ }
10127
+ const allDeps = /* @__PURE__ */ new Set();
10128
+ const allDevDeps = /* @__PURE__ */ new Set();
10129
+ const lightVars = {};
10130
+ const darkVars = {};
10131
+ for (const item of sorted) {
10132
+ for (const dep of item.dependencies) allDeps.add(dep);
10133
+ for (const dep of item.devDependencies) allDevDeps.add(dep);
10134
+ if (item.cssVars?.light) Object.assign(lightVars, item.cssVars.light);
10135
+ if (item.cssVars?.dark) Object.assign(darkVars, item.cssVars.dark);
10136
+ }
10137
+ return {
10138
+ items: sorted,
10139
+ dependencies: [...allDeps],
10140
+ devDependencies: [...allDevDeps],
10141
+ cssVars: { light: lightVars, dark: darkVars }
10142
+ };
10143
+ }
10144
+
10145
+ // src/registry/transformer.ts
10146
+ function transformImports(content, options) {
10147
+ const { aliases } = options;
10148
+ let result = content;
10149
+ result = result.replace(
10150
+ /(from\s+['"])(?:\.\.\/)+types(?:\/([^'"]+))?(['"])/g,
10151
+ (_match, prefix, subpath, suffix) => {
10152
+ if (subpath) {
10153
+ return `${prefix}${aliases.importAlias}${aliases.components}/types/${subpath}${suffix}`;
10154
+ }
10155
+ return `${prefix}${aliases.importAlias}${aliases.components}/types${suffix}`;
10156
+ }
10157
+ );
10158
+ result = result.replace(
10159
+ /(from\s+['"])\.\.\/(([A-Z]\w+)(\/[^'"]+)?)(['"])/g,
10160
+ (_match, prefix, _fullPath, dirName, subPath, suffix) => {
10161
+ const kebab = dirName.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
10162
+ if (subPath) {
10163
+ return `${prefix}${aliases.importAlias}${aliases.ui}/${kebab}${subPath}${suffix}`;
10164
+ }
10165
+ return `${prefix}${aliases.importAlias}${aliases.ui}/${kebab}${suffix}`;
10166
+ }
10167
+ );
10168
+ result = result.replace(
10169
+ /(from\s+['"])(?:\.\.\/)+hooks\/(\w+)(['"])/g,
10170
+ `$1${aliases.importAlias}${aliases.hooks}/$2$3`
10171
+ );
10172
+ result = result.replace(
10173
+ /(from\s+['"])(?:\.\.\/)+utils\/(\w+(?:\/\w+)?)(['"])/g,
10174
+ `$1${aliases.importAlias}${aliases.utils}/$2$3`
10175
+ );
10176
+ result = result.replace(
10177
+ /(from\s+['"])(?:\.\.\/)+utils(['"])/g,
10178
+ `$1${aliases.importAlias}${aliases.utils}$2`
10179
+ );
10180
+ return result;
10181
+ }
10182
+ function normalizeExtensions(content, tsx) {
10183
+ if (!tsx) {
10184
+ return content.replace(/(from\s+['"][^'"]+)\.tsx(['"])/g, "$1.jsx$2").replace(/(from\s+['"][^'"]+)\.ts(['"])/g, "$1.js$2");
10185
+ }
10186
+ return content;
10187
+ }
10188
+ function getTargetDir(type, aliases) {
10189
+ switch (type) {
10190
+ case "registry:ui":
10191
+ return aliases.ui;
10192
+ case "registry:hook":
10193
+ return aliases.hooks;
10194
+ case "registry:util":
10195
+ return aliases.utils;
10196
+ case "registry:lib":
10197
+ return aliases.lib;
10198
+ case "registry:component":
10199
+ return aliases.components;
10200
+ case "registry:type":
10201
+ return aliases.components;
10202
+ case "registry:style":
10203
+ return aliases.ui;
10204
+ default:
10205
+ return aliases.lib;
10206
+ }
10207
+ }
10208
+ function detectPackageManager(projectDir) {
10209
+ if (existsSync(join(projectDir, "pnpm-lock.yaml"))) return "pnpm";
10210
+ if (existsSync(join(projectDir, "bun.lockb")) || existsSync(join(projectDir, "bun.lock"))) return "bun";
10211
+ if (existsSync(join(projectDir, "yarn.lock"))) return "yarn";
10212
+ return "npm";
10213
+ }
10214
+ function getInstallArgs(pm, packages, dev) {
10215
+ switch (pm) {
10216
+ case "pnpm":
10217
+ return ["pnpm", ["add", ...[], ...packages]];
10218
+ case "yarn":
10219
+ return ["yarn", ["add", ...[], ...packages]];
10220
+ case "bun":
10221
+ return ["bun", ["add", ...[], ...packages]];
10222
+ default:
10223
+ return ["npm", ["install", ...[], ...packages]];
10224
+ }
10225
+ }
10226
+ function writeRegistryItems(tree, options) {
10227
+ const { projectDir, aliases, components, overwrite, dryRun, log } = options;
10228
+ const result = { written: [], skipped: [], installedDeps: [] };
10229
+ const shouldOverwrite = overwrite ?? components.overwrite;
10230
+ for (const item of tree.items) {
10231
+ const targetBaseDir = getTargetDir(item.type, aliases);
10232
+ for (const file of item.files) {
10233
+ const fileName = basename(file.path);
10234
+ let targetPath;
10235
+ if (file.target) {
10236
+ targetPath = join(projectDir, file.target);
10237
+ } else if (item.type === "registry:ui" || item.type === "registry:component") {
10238
+ targetPath = join(projectDir, targetBaseDir, item.name, fileName);
10239
+ } else if (item.type === "registry:type") {
10240
+ targetPath = join(projectDir, targetBaseDir, file.path);
10241
+ } else {
10242
+ targetPath = join(projectDir, targetBaseDir, fileName);
10243
+ }
10244
+ if (existsSync(targetPath) && !shouldOverwrite) {
10245
+ if (log) log(` Skipped (exists): ${targetPath}`);
10246
+ result.skipped.push(targetPath);
10247
+ continue;
10248
+ }
10249
+ let content = file.content;
10250
+ content = transformImports(content, { aliases, tsx: components.tsx });
10251
+ content = normalizeExtensions(content, components.tsx);
10252
+ if (dryRun) {
10253
+ if (log) log(` Would write: ${targetPath}`);
10254
+ result.written.push(targetPath);
10255
+ continue;
10256
+ }
10257
+ const dir = dirname(targetPath);
10258
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
10259
+ writeFileSync(targetPath, content, "utf-8");
10260
+ if (log) log(` Written: ${targetPath}`);
10261
+ result.written.push(targetPath);
10262
+ }
10263
+ }
10264
+ const depsToInstall = tree.dependencies.filter((dep) => {
10265
+ const pkgJsonPath = join(projectDir, "package.json");
10266
+ if (existsSync(pkgJsonPath)) {
10267
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
10268
+ const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
10269
+ return !Reflect.get(allDeps, dep);
10270
+ }
10271
+ return true;
10272
+ });
10273
+ if (depsToInstall.length > 0 && !dryRun) {
10274
+ const pm = detectPackageManager(projectDir);
10275
+ const [cmd, args] = getInstallArgs(pm, depsToInstall);
10276
+ if (log) log(` Installing: ${cmd} ${args.join(" ")}`);
10277
+ execFileSync(cmd, args, { cwd: projectDir, stdio: "inherit" });
10278
+ result.installedDeps = depsToInstall;
10279
+ } else if (depsToInstall.length > 0 && dryRun) {
10280
+ if (log) log(` Would install: ${depsToInstall.join(", ")}`);
10281
+ result.installedDeps = depsToInstall;
10282
+ }
10283
+ return result;
10284
+ }
9075
10285
  function getPackageRoot() {
9076
10286
  const currentFile = fileURLToPath(import.meta.url);
9077
10287
  return resolve(dirname(currentFile), "..");
@@ -9181,6 +10391,6 @@ function deepMerge2(target, source) {
9181
10391
  return output;
9182
10392
  }
9183
10393
 
9184
- export { BOOTSTRAP_MAPPINGS, BOOTSTRAP_PATTERNS, CONFIG_FILE_NAMES, DEFAULT_CLEAN_DIRECTORIES, DEFAULT_COLLECTIONS_DIR, DEFAULT_FILE_NAMES, DEFAULT_ICONS_OUTPUT_DIR, DEFAULT_ICONS_SOURCE_DIR, DEFAULT_LOG_LEVEL, DEFAULT_OUTPUT_DIR, DEFAULT_PREFIX, DEFAULT_SOURCE_DIR, SHADCN_MAPPINGS, VALID_TOKEN_TYPES, addScssImportHeader, applyNameMapping, autoDetectThemes, bootstrapMapper, buildAllThemes, buildConfigSchema, buildIcons, buildTheme, buildTokens, buildTokensCLI, builtInFormats, builtInPreprocessors, builtInTransforms, checkDeprecatedOptions, checkMigrationNeeded, cleanSVGForReact, cleanTokenOutputs, cleanTokensCLI, clearConfigCache, createBundle, createBundleFromFiles, createBundles, createFixReferencesPreprocessor, createFrameworkMapper, createOutputConfig, createResolvedConfig, createStyleDictionaryConfig, cssTransformGroup, cssVariablesWithComments, customFormatSchema, customTransformSchema, deepMerge2 as deepMerge, defaultConfig, defaultFormats, defaultGlobalConfig, defaultIconFramework, defaultIconsConfig, defaultOutputFileNames, defaultReactIndexTemplate, defaultReactTemplate, defaultReactTypesTemplate, defaultSVGOConfig, defaultSelectorPattern, defaultSourcePatterns, defaultThemesConfig, defaultTokensConfig, defineConfig, defineConfigAsync, detectModes as detectFigmaModes, detectModes3 as detectModes, detectModes2 as detectTransformModes, diffTokens, dimensionRem, discoverThemeFiles, dsaiConfigSchema, dtcgFileSchema, dtcgTokenCollectionSchema, dtcgTokenSchema, ensureOutputDirs, envArrayKeys, envBooleanKeys, envMappings, envNumberKeys, extractMode, extractModes, extractViewBox, figmaExportSchema, figmaExportWithMetadataSchema, figmaVariablesResponseSchema, fileExists, filePathSchema, filterDiff, filterFiles, findPackageJson, fixReferences, flattenModeStructure, fontWeightUnitless, formatDuration, formatErrorMessage, formatValidationErrors, frameworkSchema, generateAndWriteChangelog, generateChangelog, generateChangelogCLI, generateMigrationScript, generateReactIcons, generateSVGSprite, generateThemeBuildConfig, getBreakingChanges, getConfigFromEnv, getCssFormat, getDefaultCssDir, getDefaultExtension, getDefaultFiles, getDefaultIgnorePatterns, getDefaultOutputDir, getDefaultSyncPaths, getDefaultTransformations, getEnvOverrides, getFrameworkMapper, getLogLevelFromEnv, getOutputFileName, getPackageRoot, getPreprocessedFilesForMode, getSDTokenType, getSDTokenValue, getThemeFiles, getThemeSelector, getTokenDescription, getTokenType, getTokenValue, globPatternSchema, globalConfigSchema, hasDTCGValue, hashTypeSchema, iconOptimizationSchema, iconSpriteSchema, iconsConfigSchema, isCI, isDTCGToken, isDirectory, isFile, isLegacyToken, isSDToken, isToken, isTokenReference, isValidIconName, isValidTokenType, jsTransformGroup, lineHeightUnitless, loadConfig, loadConfigSync, loadContent, logLevelSchema, logger, mapToBootstrapName, mapToShadcnName, mergeCollections, mergeCollectionsCLI, mergeConfigs, mergeContent, migrateConfig, migrateLegacyTokensConfig, nameKebab, normalizeIconName, optimizeSVG, optimizeSVGFiles, outputFormatSchema, parseSVG, parseSVGFiles, parseTokenReference, postprocessCLI, postprocessCss, postprocessCssFiles, preprocessFile, preprocessTokenFiles, processScssImportHeader, readSVGFile, registerAll, registerFormats, registerPreprocessors, registerTransformGroups, registerTransforms, replacePlaceholders, resolveAllOutputPaths, resolveConfig, resolveOutputPath, resolvePath, runBuildCLI, scanDirectories, scanSVGFiles, scssTransformGroup, searchConfigFile, setupStyleDictionary, shadcnMapper, shouldDisableColors, skipOptimization, sortFiles, styleDictionaryInputSchema, styleDictionaryTokenSchema, summarizeDiff, syncTokens, syncTokensCLI, themeDefinitionSchema, themeSelectorPatternSchema, themesConfigSchema, toComponentName, toDTCGToken, toIconName, tokenBuildConfigSchema, tokenCacheConfigSchema, tokenWatchConfigSchema, tokensConfigSchema, tokensHooksSchema, transformGroups, transformToken, transformTokenTree, transformTokens, transformTokensCLI, transformType, transformValue, typescriptDeclarations, validateConfig, validateConfigOrThrow, validateConfigSection, validateDTCGFile, validateDTCGTokens, validateFigmaCLI, validateFigmaExport, validateFigmaExportWithMetadata, validateFigmaExports, validateFigmaFile, validateFigmaVariablesResponse, validateOutputPaths, validateStyleDictionaryInput, validateStyleDictionaryTokens, validateThemeDefinitions, validateTokens, validateTokensCLI, version, versionSchema, writeChangelog };
10394
+ export { BOOTSTRAP_MAPPINGS, BOOTSTRAP_PATTERNS, CONFIG_FILE_NAMES, DEFAULT_CLEAN_DIRECTORIES, DEFAULT_COLLECTIONS_DIR, DEFAULT_FILE_NAMES, DEFAULT_ICONS_OUTPUT_DIR, DEFAULT_ICONS_SOURCE_DIR, DEFAULT_LOG_LEVEL, DEFAULT_OUTPUT_DIR, DEFAULT_PREFIX, DEFAULT_SOURCE_DIR, SHADCN_MAPPINGS, VALID_TOKEN_TYPES, addScssImportHeader, aliasesConfigSchema, applyNameMapping, autoDetectThemes, bootstrapMapper, buildAllThemes, buildConfigSchema, buildIcons, buildRegistry, buildTheme, buildTokens, buildTokensCLI, builtInFormats, builtInPreprocessors, builtInTransforms, checkDeprecatedOptions, checkMigrationNeeded, cleanSVGForReact, cleanTokenOutputs, cleanTokensCLI, clearConfigCache, componentsConfigSchema, createBundle, createBundleFromFiles, createBundles, createFixReferencesPreprocessor, createFrameworkMapper, createOutputConfig, createResolvedConfig, createStyleDictionaryConfig, cssTransformGroup, cssVariablesWithComments, customFormatSchema, customTransformSchema, deepMerge2 as deepMerge, defaultAliasesConfig, defaultComponentsConfig, defaultConfig, defaultFormats, defaultGlobalConfig, defaultIconFramework, defaultIconsConfig, defaultOutputFileNames, defaultReactIndexTemplate, defaultReactTemplate, defaultReactTypesTemplate, defaultSVGOConfig, defaultSelectorPattern, defaultSourcePatterns, defaultThemesConfig, defaultTokensConfig, defineConfig, defineConfigAsync, detectModes as detectFigmaModes, detectModes3 as detectModes, detectModes2 as detectTransformModes, diffTokens, dimensionRem, discoverThemeFiles, dsaiConfigSchema, dtcgFileSchema, dtcgTokenCollectionSchema, dtcgTokenSchema, ensureOutputDirs, envArrayKeys, envBooleanKeys, envMappings, envNumberKeys, extractMode, extractModes, extractViewBox, figmaExportSchema, figmaExportWithMetadataSchema, figmaVariablesResponseSchema, fileExists, filePathSchema, filterDiff, filterFiles, findPackageJson, fixReferences, flattenModeStructure, fontWeightUnitless, formatDuration, formatErrorMessage, formatValidationErrors, frameworkSchema, generateAndWriteChangelog, generateChangelog, generateChangelogCLI, generateMigrationScript, generateReactIcons, generateSVGSprite, generateThemeBuildConfig, getBreakingChanges, getConfigFromEnv, getCssFormat, getDefaultCssDir, getDefaultExtension, getDefaultFiles, getDefaultIgnorePatterns, getDefaultOutputDir, getDefaultSyncPaths, getDefaultTransformations, getEnvOverrides, getFrameworkMapper, getLogLevelFromEnv, getOutputFileName, getPackageRoot, getPreprocessedFilesForMode, getSDTokenType, getSDTokenValue, getThemeFiles, getThemeSelector, getTokenDescription, getTokenType, getTokenValue, globPatternSchema, globalConfigSchema, hasDTCGValue, hashTypeSchema, iconOptimizationSchema, iconSpriteSchema, iconsConfigSchema, isCI, isDTCGToken, isDirectory, isFile, isLegacyToken, isSDToken, isToken, isTokenReference, isValidIconName, isValidTokenType, jsTransformGroup, lineHeightUnitless, loadConfig, loadConfigSync, loadContent, logLevelSchema, logger, mapToBootstrapName, mapToShadcnName, mergeCollections, mergeCollectionsCLI, mergeConfigs, mergeContent, migrateConfig, migrateLegacyTokensConfig, nameKebab, normalizeExtensions, normalizeIconName, optimizeSVG, optimizeSVGFiles, outputFormatSchema, parseSVG, parseSVGFiles, parseTokenReference, postprocessCLI, postprocessCss, postprocessCssFiles, preprocessFile, preprocessTokenFiles, processScssImportHeader, readSVGFile, registerAll, registerFormats, registerPreprocessors, registerTransformGroups, registerTransforms, registryFileSchema, registryIndexEntrySchema, registryIndexSchema, registryItemSchema, registryItemTypeSchema, replacePlaceholders, resolveAllOutputPaths, resolveConfig, resolveOutputPath, resolvePath, resolveTree, runBuildCLI, scanDirectories, scanSVGFiles, scssTransformGroup, searchConfigFile, setupStyleDictionary, shadcnMapper, shouldDisableColors, skipOptimization, sortFiles, styleDictionaryInputSchema, styleDictionaryTokenSchema, summarizeDiff, syncTokens, syncTokensCLI, themeDefinitionSchema, themeSelectorPatternSchema, themesConfigSchema, toComponentName, toDTCGToken, toIconName, tokenBuildConfigSchema, tokenCacheConfigSchema, tokenWatchConfigSchema, tokensConfigSchema, tokensHooksSchema, transformGroups, transformImports, transformToken, transformTokenTree, transformTokens, transformTokensCLI, transformType, transformValue, typescriptDeclarations, validateConfig, validateConfigOrThrow, validateConfigSection, validateDTCGFile, validateDTCGTokens, validateFigmaCLI, validateFigmaExport, validateFigmaExportWithMetadata, validateFigmaExports, validateFigmaFile, validateFigmaVariablesResponse, validateOutputPaths, validateStyleDictionaryInput, validateStyleDictionaryTokens, validateThemeDefinitions, validateTokens, validateTokensCLI, version, versionSchema, writeChangelog, writeRegistryItems };
9185
10395
  //# sourceMappingURL=index.js.map
9186
10396
  //# sourceMappingURL=index.js.map