@devstroupe/devkit-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +40 -0
  2. package/dist/boilerplates/angular-template/.dockerignore +4 -0
  3. package/dist/boilerplates/angular-template/.postcssrc.json +5 -0
  4. package/dist/boilerplates/angular-template/Dockerfile +14 -0
  5. package/dist/boilerplates/angular-template/angular.json +85 -0
  6. package/dist/boilerplates/angular-template/components.json +5 -0
  7. package/dist/boilerplates/angular-template/framework.code-workspace +7 -0
  8. package/dist/boilerplates/angular-template/nginx.conf +23 -0
  9. package/dist/boilerplates/angular-template/node_modules/.bin/browserslist +21 -0
  10. package/dist/boilerplates/angular-template/node_modules/.bin/jiti +21 -0
  11. package/dist/boilerplates/angular-template/node_modules/.bin/lessc +21 -0
  12. package/dist/boilerplates/angular-template/node_modules/.bin/ng +21 -0
  13. package/dist/boilerplates/angular-template/node_modules/.bin/ng-xi18n +21 -0
  14. package/dist/boilerplates/angular-template/node_modules/.bin/ngc +21 -0
  15. package/dist/boilerplates/angular-template/node_modules/.bin/sass +21 -0
  16. package/dist/boilerplates/angular-template/node_modules/.bin/terser +21 -0
  17. package/dist/boilerplates/angular-template/node_modules/.bin/tsc +21 -0
  18. package/dist/boilerplates/angular-template/node_modules/.bin/tsserver +21 -0
  19. package/dist/boilerplates/angular-template/node_modules/.bin/vite +21 -0
  20. package/dist/boilerplates/angular-template/node_modules/.bin/vitest +21 -0
  21. package/dist/boilerplates/angular-template/node_modules/.bin/yaml +21 -0
  22. package/dist/boilerplates/angular-template/package.json +47 -0
  23. package/dist/boilerplates/angular-template/postcss.config.js +5 -0
  24. package/dist/boilerplates/angular-template/proxy.conf.json +7 -0
  25. package/dist/boilerplates/angular-template/src/app/app.component.html +3 -0
  26. package/dist/boilerplates/angular-template/src/app/app.component.ts +12 -0
  27. package/dist/boilerplates/angular-template/src/app/app.config.ts +59 -0
  28. package/dist/boilerplates/angular-template/src/app/app.entity-routes.ts +4 -0
  29. package/dist/boilerplates/angular-template/src/app/app.routes.ts +25 -0
  30. package/dist/boilerplates/angular-template/src/app/core/guards/auth.guard.ts +16 -0
  31. package/dist/boilerplates/angular-template/src/app/core/services/auth.service.ts +98 -0
  32. package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.html +51 -0
  33. package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.ts +47 -0
  34. package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.html +59 -0
  35. package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.ts +47 -0
  36. package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.html +14 -0
  37. package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.ts +23 -0
  38. package/dist/boilerplates/angular-template/src/app/shared/interceptors/tenant.interceptor.ts +25 -0
  39. package/dist/boilerplates/angular-template/src/index.html +64 -0
  40. package/dist/boilerplates/angular-template/src/main.ts +6 -0
  41. package/dist/boilerplates/angular-template/src/styles.css +9 -0
  42. package/dist/boilerplates/angular-template/tsconfig.json +36 -0
  43. package/dist/boilerplates/nest-template/Dockerfile +16 -0
  44. package/dist/boilerplates/nest-template/node_modules/.bin/acorn +21 -0
  45. package/dist/boilerplates/nest-template/node_modules/.bin/nest +21 -0
  46. package/dist/boilerplates/nest-template/node_modules/.bin/prettier +21 -0
  47. package/dist/boilerplates/nest-template/node_modules/.bin/tsc +21 -0
  48. package/dist/boilerplates/nest-template/node_modules/.bin/tsserver +21 -0
  49. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm +21 -0
  50. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-commonjs +21 -0
  51. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-esm +21 -0
  52. package/dist/boilerplates/nest-template/node_modules/.bin/webpack +21 -0
  53. package/dist/boilerplates/nest-template/package.json +43 -0
  54. package/dist/boilerplates/nest-template/src/app.module.ts +24 -0
  55. package/dist/boilerplates/nest-template/src/database/data-source.ts +16 -0
  56. package/dist/boilerplates/nest-template/src/database/migrations/1700000000000-create-users.ts +26 -0
  57. package/dist/boilerplates/nest-template/src/main.ts +46 -0
  58. package/dist/boilerplates/nest-template/src/modules/auth/auth.controller.ts +34 -0
  59. package/dist/boilerplates/nest-template/src/modules/auth/auth.module.ts +22 -0
  60. package/dist/boilerplates/nest-template/src/modules/auth/auth.service.ts +57 -0
  61. package/dist/boilerplates/nest-template/src/modules/auth/current-user.decorator.ts +8 -0
  62. package/dist/boilerplates/nest-template/src/modules/auth/jwt-auth.guard.ts +31 -0
  63. package/dist/boilerplates/nest-template/src/modules/auth/roles.decorator.ts +4 -0
  64. package/dist/boilerplates/nest-template/src/modules/auth/roles.guard.ts +24 -0
  65. package/dist/boilerplates/nest-template/src/modules/user/database-seed.service.ts +47 -0
  66. package/dist/boilerplates/nest-template/src/modules/user/domain/user.repository.ts +9 -0
  67. package/dist/boilerplates/nest-template/src/modules/user/domain/user.ts +9 -0
  68. package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.orm-entity.ts +31 -0
  69. package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.repository.adapter.ts +53 -0
  70. package/dist/boilerplates/nest-template/src/modules/user/service/user.service.ts +44 -0
  71. package/dist/boilerplates/nest-template/src/modules/user/user.module.ts +20 -0
  72. package/dist/boilerplates/nest-template/tsconfig.build.json +4 -0
  73. package/dist/boilerplates/nest-template/tsconfig.json +21 -0
  74. package/dist/index.d.ts +2 -0
  75. package/dist/index.js +1967 -0
  76. package/dist/migrations/sort-entities.d.ts +2 -0
  77. package/dist/migrations/sort-entities.js +30 -0
  78. package/dist/rules/linter-rules.d.ts +12 -0
  79. package/dist/rules/linter-rules.js +338 -0
  80. package/dist/rules/linter-rules.test.d.ts +1 -0
  81. package/dist/rules/linter-rules.test.js +214 -0
  82. package/dist/templates/angular/dialog-handler.template.d.ts +2 -0
  83. package/dist/templates/angular/dialog-handler.template.js +49 -0
  84. package/dist/templates/angular/form.template.d.ts +3 -0
  85. package/dist/templates/angular/form.template.js +453 -0
  86. package/dist/templates/angular/index.d.ts +4 -0
  87. package/dist/templates/angular/index.js +20 -0
  88. package/dist/templates/angular/list.template.d.ts +3 -0
  89. package/dist/templates/angular/list.template.js +213 -0
  90. package/dist/templates/angular/service.template.d.ts +1 -0
  91. package/dist/templates/angular/service.template.js +20 -0
  92. package/dist/templates/cli-templates.d.ts +2 -0
  93. package/dist/templates/cli-templates.js +18 -0
  94. package/dist/templates/nest/crud.templates.d.ts +9 -0
  95. package/dist/templates/nest/crud.templates.js +362 -0
  96. package/dist/templates/nest/index.d.ts +3 -0
  97. package/dist/templates/nest/index.js +19 -0
  98. package/dist/templates/nest/microservice.templates.d.ts +4 -0
  99. package/dist/templates/nest/microservice.templates.js +157 -0
  100. package/dist/templates/nest/migration.template.d.ts +3 -0
  101. package/dist/templates/nest/migration.template.js +127 -0
  102. package/dist/templates/relationship-templates.test.d.ts +1 -0
  103. package/dist/templates/relationship-templates.test.js +181 -0
  104. package/dist/templates/shared/names.d.ts +3 -0
  105. package/dist/templates/shared/names.js +14 -0
  106. package/dist/templates/shared/relationships.d.ts +27 -0
  107. package/dist/templates/shared/relationships.js +96 -0
  108. package/dist/templates/ui/components/avatar.template.d.ts +3 -0
  109. package/dist/templates/ui/components/avatar.template.js +66 -0
  110. package/dist/templates/ui/components/badge.template.d.ts +3 -0
  111. package/dist/templates/ui/components/badge.template.js +27 -0
  112. package/dist/templates/ui/components/button.template.d.ts +5 -0
  113. package/dist/templates/ui/components/button.template.js +64 -0
  114. package/dist/templates/ui/components/card-list.template.d.ts +5 -0
  115. package/dist/templates/ui/components/card-list.template.js +79 -0
  116. package/dist/templates/ui/components/dialog.template.d.ts +5 -0
  117. package/dist/templates/ui/components/dialog.template.js +51 -0
  118. package/dist/templates/ui/components/filter.template.d.ts +4 -0
  119. package/dist/templates/ui/components/filter.template.js +218 -0
  120. package/dist/templates/ui/components/index.d.ts +10 -0
  121. package/dist/templates/ui/components/index.js +26 -0
  122. package/dist/templates/ui/components/input.template.d.ts +4 -0
  123. package/dist/templates/ui/components/input.template.js +76 -0
  124. package/dist/templates/ui/components/select.template.d.ts +4 -0
  125. package/dist/templates/ui/components/select.template.js +176 -0
  126. package/dist/templates/ui/components/simple-list.template.d.ts +5 -0
  127. package/dist/templates/ui/components/simple-list.template.js +89 -0
  128. package/dist/templates/ui/components/table.template.d.ts +5 -0
  129. package/dist/templates/ui/components/table.template.js +112 -0
  130. package/dist/templates/ui/index.d.ts +9 -0
  131. package/dist/templates/ui/index.js +25 -0
  132. package/dist/templates/ui/layout/header.template.d.ts +5 -0
  133. package/dist/templates/ui/layout/header.template.js +236 -0
  134. package/dist/templates/ui/layout/index.d.ts +4 -0
  135. package/dist/templates/ui/layout/index.js +20 -0
  136. package/dist/templates/ui/layout/main-layout.template.d.ts +5 -0
  137. package/dist/templates/ui/layout/main-layout.template.js +126 -0
  138. package/dist/templates/ui/layout/shell.template.d.ts +5 -0
  139. package/dist/templates/ui/layout/shell.template.js +76 -0
  140. package/dist/templates/ui/layout/sidebar.template.d.ts +5 -0
  141. package/dist/templates/ui/layout/sidebar.template.js +412 -0
  142. package/dist/templates/ui/playground.template.d.ts +5 -0
  143. package/dist/templates/ui/playground.template.js +570 -0
  144. package/dist/templates/ui/readme.template.d.ts +1 -0
  145. package/dist/templates/ui/readme.template.js +23 -0
  146. package/dist/templates/ui/shared/colors.d.ts +1 -0
  147. package/dist/templates/ui/shared/colors.js +31 -0
  148. package/dist/templates/ui/shared/profile-component.template.d.ts +5 -0
  149. package/dist/templates/ui/shared/profile-component.template.js +403 -0
  150. package/dist/templates/ui/shared/profile-service.template.d.ts +1 -0
  151. package/dist/templates/ui/shared/profile-service.template.js +44 -0
  152. package/dist/templates/ui/shared/theme-service.template.d.ts +1 -0
  153. package/dist/templates/ui/shared/theme-service.template.js +47 -0
  154. package/dist/templates/ui/spartan/badge-directive.template.d.ts +3 -0
  155. package/dist/templates/ui/spartan/badge-directive.template.js +50 -0
  156. package/dist/templates/ui/spartan/button-directive.template.d.ts +3 -0
  157. package/dist/templates/ui/spartan/button-directive.template.js +82 -0
  158. package/dist/templates/ui/spartan/button-token.template.d.ts +3 -0
  159. package/dist/templates/ui/spartan/button-token.template.js +31 -0
  160. package/dist/templates/ui/spartan/hlm-core.template.d.ts +3 -0
  161. package/dist/templates/ui/spartan/hlm-core.template.js +322 -0
  162. package/dist/templates/ui/spartan/index.d.ts +5 -0
  163. package/dist/templates/ui/spartan/index.js +21 -0
  164. package/dist/templates/ui/spartan/input-directive.template.d.ts +3 -0
  165. package/dist/templates/ui/spartan/input-directive.template.js +31 -0
  166. package/dist/templates/ui/theme-css.template.d.ts +7 -0
  167. package/dist/templates/ui/theme-css.template.js +210 -0
  168. package/dist/templates/ui-templates.d.ts +1 -0
  169. package/dist/templates/ui-templates.js +17 -0
  170. package/package.json +50 -0
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.devkitHlmCoreTemplate = devkitHlmCoreTemplate;
4
+ function devkitHlmCoreTemplate() {
5
+ return {
6
+ ts: `import { isPlatformBrowser } from '@angular/common';
7
+ import {
8
+ DestroyRef,
9
+ effect,
10
+ ElementRef,
11
+ HostAttributeToken,
12
+ inject,
13
+ Injector,
14
+ PLATFORM_ID,
15
+ runInInjectionContext,
16
+ } from '@angular/core';
17
+ import { type ClassValue, clsx } from 'clsx';
18
+ import { twMerge } from 'tailwind-merge';
19
+
20
+ export function hlm(...inputs: ClassValue[]) {
21
+ return twMerge(clsx(inputs));
22
+ }
23
+
24
+ // Global map to track class managers per element
25
+ const elementClassManagers = new WeakMap<HTMLElement, ElementClassManager>();
26
+ // Global mutation observer for all elements
27
+ let globalObserver: MutationObserver | null = null;
28
+ const observedElements = new Set<HTMLElement>();
29
+
30
+ interface ElementClassManager {
31
+ element: HTMLElement;
32
+ sources: Map<number, { classes: Set<string>; order: number }>;
33
+ baseClasses: Set<string>;
34
+ isUpdating: boolean;
35
+ nextOrder: number;
36
+ hasInitialized: boolean;
37
+ restoreRafId: number | null;
38
+ /** Transitions are suppressed until the first effect writes correct classes */
39
+ transitionsSuppressed: boolean;
40
+ /** Original inline transition value to restore after suppression (empty string = none was set) */
41
+ previousTransition: string;
42
+ /** Original inline transition priority to preserve !important when restoring */
43
+ previousTransitionPriority: string;
44
+ }
45
+
46
+ let sourceCounter = 0;
47
+
48
+ /**
49
+ * This function dynamically adds and removes classes for a given element without requiring
50
+ * the a class binding (e.g. \`[class]="..."\`) which may interfere with other class bindings.
51
+ *
52
+ * 1. This will merge the existing classes on the element with the new classes.
53
+ * 2. It will also remove any classes that were previously added by this function but are no longer present in the new classes.
54
+ * 3. Multiple calls to this function on the same element will be merged efficiently.
55
+ */
56
+ export function classes(computed: () => ClassValue[] | string, options: ClassesOptions = {}) {
57
+ runInInjectionContext(options.injector ?? inject(Injector), () => {
58
+ const elementRef = options.elementRef ?? inject(ElementRef);
59
+ const platformId = inject(PLATFORM_ID);
60
+ const destroyRef = inject(DestroyRef);
61
+ const baseClasses = inject(new HostAttributeToken('class'), { optional: true });
62
+
63
+ const element = elementRef.nativeElement;
64
+
65
+ // Create unique identifier for this source
66
+ const sourceId = sourceCounter++;
67
+
68
+ // Get or create the class manager for this element
69
+ let manager = elementClassManagers.get(element);
70
+
71
+ if (!manager) {
72
+ // Initialize base classes from variation (host attribute 'class')
73
+ const initialBaseClasses = new Set<string>();
74
+
75
+ if (baseClasses) {
76
+ toClassList(baseClasses).forEach((cls) => initialBaseClasses.add(cls));
77
+ }
78
+
79
+ manager = {
80
+ element,
81
+ sources: new Map(),
82
+ baseClasses: initialBaseClasses,
83
+ isUpdating: false,
84
+ nextOrder: 0,
85
+ hasInitialized: false,
86
+ restoreRafId: null,
87
+ transitionsSuppressed: false,
88
+ previousTransition: '',
89
+ previousTransitionPriority: '',
90
+ };
91
+ elementClassManagers.set(element, manager);
92
+
93
+ // Setup global observer if needed and register this element
94
+ setupGlobalObserver(platformId);
95
+ observedElements.add(element);
96
+
97
+ // Suppress transitions until the first effect writes correct classes and
98
+ // the browser has painted them. This prevents CSS transition animations
99
+ // during hydration when classes change from SSR state to client state.
100
+ if (isPlatformBrowser(platformId)) {
101
+ manager.previousTransition = element.style.getPropertyValue('transition');
102
+ manager.previousTransitionPriority = element.style.getPropertyPriority('transition');
103
+ element.style.setProperty('transition', 'none', 'important');
104
+ manager.transitionsSuppressed = true;
105
+ }
106
+ }
107
+
108
+ // Assign order once at registration time
109
+ const sourceOrder = manager.nextOrder++;
110
+
111
+ function updateClasses(): void {
112
+ // Get the new classes from the computed function
113
+ const newClasses = toClassList(computed());
114
+
115
+ // Update this source's classes, keeping the original order
116
+ manager!.sources.set(sourceId, {
117
+ classes: new Set(newClasses),
118
+ order: sourceOrder,
119
+ });
120
+
121
+ // Update the element
122
+ updateElement(manager!);
123
+
124
+ // Re-enable transitions after the first effect writes correct classes.
125
+ // Deferred to next animation frame so the browser paints the class change
126
+ // with transitions disabled first, then re-enables them.
127
+ if (manager!.transitionsSuppressed) {
128
+ manager!.transitionsSuppressed = false;
129
+ manager!.restoreRafId = requestAnimationFrame(() => {
130
+ manager!.restoreRafId = null;
131
+ restoreTransitionSuppression(manager!);
132
+ });
133
+ }
134
+ }
135
+
136
+ // Register cleanup with DestroyRef
137
+ destroyRef.onDestroy(() => {
138
+ if (manager!.restoreRafId !== null) {
139
+ cancelAnimationFrame(manager!.restoreRafId);
140
+ manager!.restoreRafId = null;
141
+ }
142
+
143
+ if (manager!.transitionsSuppressed) {
144
+ manager!.transitionsSuppressed = false;
145
+ restoreTransitionSuppression(manager!);
146
+ }
147
+
148
+ // Remove this source from the manager
149
+ manager!.sources.delete(sourceId);
150
+
151
+ // If no more sources, clean up the manager
152
+ if (manager!.sources.size === 0) {
153
+ cleanupManager(element);
154
+ } else {
155
+ // Update element without this source's classes
156
+ updateElement(manager!);
157
+ }
158
+ });
159
+
160
+ /**
161
+ * We need this effect to track changes to the computed classes. Ideally, we would use
162
+ * afterRenderEffect here, but that doesn't run in SSR contexts, so we use a standard
163
+ * effect which works in both browser and SSR.
164
+ */
165
+ effect(updateClasses);
166
+ });
167
+ }
168
+
169
+ function restoreTransitionSuppression(manager: ElementClassManager): void {
170
+ const prev = manager.previousTransition;
171
+ if (prev) {
172
+ manager.element.style.setProperty(
173
+ 'transition',
174
+ prev,
175
+ manager.previousTransitionPriority || undefined,
176
+ );
177
+ } else {
178
+ manager.element.style.removeProperty('transition');
179
+ }
180
+ }
181
+
182
+ // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
183
+ function setupGlobalObserver(platformId: Object): void {
184
+ if (isPlatformBrowser(platformId) && !globalObserver) {
185
+ // Create single global observer that watches the entire document
186
+ globalObserver = new MutationObserver((mutations) => {
187
+ for (const mutation of mutations) {
188
+ if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
189
+ const element = mutation.target as HTMLElement;
190
+ const manager = elementClassManagers.get(element);
191
+
192
+ // Only process elements we're managing
193
+ if (manager && observedElements.has(element)) {
194
+ if (manager.isUpdating) continue; // Ignore changes we're making
195
+
196
+ // Update base classes to include any externally added classes
197
+ const currentClasses = toClassList(element.className);
198
+ const allSourceClasses = new Set<string>();
199
+
200
+ // Collect all classes from all sources
201
+ for (const source of manager.sources.values()) {
202
+ for (const className of source.classes) {
203
+ allSourceClasses.add(className);
204
+ }
205
+ }
206
+
207
+ // Any classes not from sources become new base classes
208
+ manager.baseClasses.clear();
209
+
210
+ for (const className of currentClasses) {
211
+ if (!allSourceClasses.has(className)) {
212
+ manager.baseClasses.add(className);
213
+ }
214
+ }
215
+
216
+ updateElement(manager);
217
+ }
218
+ }
219
+ }
220
+ });
221
+
222
+ // Start observing the entire document for class attribute changes
223
+ globalObserver.observe(document, {
224
+ attributes: true,
225
+ attributeFilter: ['class'],
226
+ subtree: true, // Watch all descendants
227
+ });
228
+ }
229
+ }
230
+
231
+ function updateElement(manager: ElementClassManager): void {
232
+ if (manager.isUpdating) return; // Prevent recursive updates
233
+
234
+ manager.isUpdating = true;
235
+
236
+ // Handle initialization: capture base classes after first source registration
237
+ if (!manager.hasInitialized && manager.sources.size > 0) {
238
+ // Get current classes on element (may include SSR classes)
239
+ const currentClasses = toClassList(manager.element.className);
240
+
241
+ // Get all classes that will be applied by sources
242
+ const allSourceClasses = new Set<string>();
243
+ for (const source of manager.sources.values()) {
244
+ source.classes.forEach((className) => allSourceClasses.add(className));
245
+ }
246
+
247
+ // Only consider classes as "base" if they're not produced by any source
248
+ // This prevents SSR-rendered classes from being preserved as base classes
249
+ currentClasses.forEach((className) => {
250
+ if (!allSourceClasses.has(className)) {
251
+ manager.baseClasses.add(className);
252
+ }
253
+ });
254
+
255
+ manager.hasInitialized = true;
256
+ }
257
+
258
+ // Get classes from all sources, sorted by registration order (later takes precedence)
259
+ const sortedSources = Array.from(manager.sources.entries()).sort(
260
+ ([, a], [, b]) => a.order - b.order,
261
+ );
262
+
263
+ const allSourceClasses: string[] = [];
264
+ for (const [, source] of sortedSources) {
265
+ allSourceClasses.push(...source.classes);
266
+ }
267
+
268
+ // Combine base classes with all source classes, ensuring base classes take precedence
269
+ const classesToApply =
270
+ allSourceClasses.length > 0 || manager.baseClasses.size > 0
271
+ ? hlm([...allSourceClasses, ...manager.baseClasses])
272
+ : '';
273
+
274
+ // Apply the classes to the element
275
+ if (manager.element.className !== classesToApply) {
276
+ manager.element.className = classesToApply;
277
+ }
278
+
279
+ manager.isUpdating = false;
280
+ }
281
+
282
+ function cleanupManager(element: HTMLElement): void {
283
+ // Remove from global tracking
284
+ observedElements.delete(element);
285
+ elementClassManagers.delete(element);
286
+
287
+ // If no more elements being tracked, cleanup global observer
288
+ if (observedElements.size === 0 && globalObserver) {
289
+ globalObserver.disconnect();
290
+ globalObserver = null;
291
+ }
292
+ }
293
+
294
+ interface ClassesOptions {
295
+ elementRef?: ElementRef<HTMLElement>;
296
+ injector?: Injector;
297
+ }
298
+
299
+ // Cache for parsed class lists to avoid repeated string operations
300
+ const classListCache = new Map<string, string[]>();
301
+
302
+ function toClassList(className: string | ClassValue[]): string[] {
303
+ // For simple string inputs, use cache to avoid repeated parsing
304
+ if (typeof className === 'string' && classListCache.has(className)) {
305
+ return classListCache.get(className)!;
306
+ }
307
+
308
+ const result = clsx(className)
309
+ .split(' ')
310
+ .filter((c) => c.length > 0);
311
+
312
+ // Cache string results, but limit cache size to prevent memory growth
313
+ if (typeof className === 'string' && classListCache.size < 1000) {
314
+ classListCache.set(className, result);
315
+ }
316
+
317
+ return result;
318
+ }
319
+ `
320
+ };
321
+ }
322
+ // 16. Template da diretiva hlmBtn do Spartan local (hlm-button.ts oficial do Spartan v1.0.4)
@@ -0,0 +1,5 @@
1
+ export * from './hlm-core.template';
2
+ export * from './button-directive.template';
3
+ export * from './button-token.template';
4
+ export * from './input-directive.template';
5
+ export * from './badge-directive.template';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./hlm-core.template"), exports);
18
+ __exportStar(require("./button-directive.template"), exports);
19
+ __exportStar(require("./button-token.template"), exports);
20
+ __exportStar(require("./input-directive.template"), exports);
21
+ __exportStar(require("./badge-directive.template"), exports);
@@ -0,0 +1,3 @@
1
+ export declare function devkitHlmInputDirectiveTemplate(): {
2
+ ts: string;
3
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.devkitHlmInputDirectiveTemplate = devkitHlmInputDirectiveTemplate;
4
+ function devkitHlmInputDirectiveTemplate() {
5
+ return {
6
+ ts: `import { Directive } from '@angular/core';
7
+ import { BrnFieldControlDescribedBy } from '@spartan-ng/brain/field';
8
+ import { BrnInput } from '@spartan-ng/brain/input';
9
+ import { classes } from '@spartan-ng/helm/utils';
10
+
11
+ @Directive({
12
+ selector: '[hlmInput]',
13
+ hostDirectives: [
14
+ { directive: BrnInput, inputs: ['id', 'forceInvalid'] },
15
+ BrnFieldControlDescribedBy,
16
+ ],
17
+ host: { 'data-slot': 'input' },
18
+ standalone: true,
19
+ })
20
+ export class HlmInput {
21
+ constructor() {
22
+ classes(
23
+ () =>
24
+ 'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 data-[matches-spartan-invalid=true]:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
25
+ );
26
+ }
27
+ }
28
+ `
29
+ };
30
+ }
31
+ // 18. Template da diretiva hlmBadge do Spartan local (hlm-badge.ts oficial)
@@ -0,0 +1,7 @@
1
+ export declare function devkitThemeCssTemplate(config: {
2
+ preset?: 'nova' | 'vega' | 'lyra' | 'maia' | 'mira' | 'luma' | 'custom';
3
+ theme?: 'violet' | 'zinc' | 'slate' | 'orange' | 'rose' | 'custom';
4
+ primaryColor?: string;
5
+ secondaryColor?: string;
6
+ fontFamily?: string;
7
+ }): string;
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.devkitThemeCssTemplate = devkitThemeCssTemplate;
4
+ const colors_1 = require("./shared/colors");
5
+ function devkitThemeCssTemplate(config) {
6
+ const theme = config.theme || 'custom';
7
+ const fontFamily = config.fontFamily || "'Inter', sans-serif";
8
+ // Mapeamento de cores dos temas padrão do Shadcn/Spartan
9
+ const themeColors = {
10
+ violet: {
11
+ light: {
12
+ primary: '262.1 83.3% 57.8%',
13
+ primaryForeground: '0 0% 98%',
14
+ secondary: '240 4.8% 95.9%',
15
+ secondaryForeground: '240 5.9% 10%',
16
+ ring: '262.1 83.3% 57.8%',
17
+ border: '240 5.9% 90%',
18
+ input: '240 5.9% 90%'
19
+ },
20
+ dark: {
21
+ primary: '263.4 70% 50.4%',
22
+ primaryForeground: '210 20% 98%',
23
+ secondary: '240 3.7% 15.9%',
24
+ secondaryForeground: '0 0% 98%',
25
+ ring: '263.4 70% 50.4%',
26
+ border: '240 3.7% 15.9%',
27
+ input: '240 3.7% 15.9%'
28
+ }
29
+ },
30
+ zinc: {
31
+ light: {
32
+ primary: '240 5.9% 10%',
33
+ primaryForeground: '0 0% 98%',
34
+ secondary: '240 4.8% 95.9%',
35
+ secondaryForeground: '240 5.9% 10%',
36
+ ring: '240 5.9% 10%',
37
+ border: '240 5.9% 90%',
38
+ input: '240 5.9% 90%'
39
+ },
40
+ dark: {
41
+ primary: '0 0% 98%',
42
+ primaryForeground: '240 5.9% 10%',
43
+ secondary: '240 3.7% 15.9%',
44
+ secondaryForeground: '0 0% 98%',
45
+ ring: '240 4.9% 83.9%',
46
+ border: '240 3.7% 15.9%',
47
+ input: '240 3.7% 15.9%'
48
+ }
49
+ },
50
+ slate: {
51
+ light: {
52
+ primary: '222.2 47.4% 11.2%',
53
+ primaryForeground: '210 40% 98%',
54
+ secondary: '210 40% 96.1%',
55
+ secondaryForeground: '222.2 47.4% 11.2%',
56
+ ring: '222.2 84% 4.9%',
57
+ border: '214.3 31.8% 91.4%',
58
+ input: '214.3 31.8% 91.4%'
59
+ },
60
+ dark: {
61
+ primary: '210 40% 98%',
62
+ primaryForeground: '222.2 47.4% 11.2%',
63
+ secondary: '217.2 32.6% 17.5%',
64
+ secondaryForeground: '210 40% 98%',
65
+ ring: '217.2 91.2% 59.8%',
66
+ border: '217.2 32.6% 17.5%',
67
+ input: '217.2 32.6% 17.5%'
68
+ }
69
+ },
70
+ orange: {
71
+ light: {
72
+ primary: '24.6 95% 53.1%',
73
+ primaryForeground: '0 0% 98%',
74
+ secondary: '240 4.8% 95.9%',
75
+ secondaryForeground: '240 5.9% 10%',
76
+ ring: '24.6 95% 53.1%',
77
+ border: '240 5.9% 90%',
78
+ input: '240 5.9% 90%'
79
+ },
80
+ dark: {
81
+ primary: '20.5 90.2% 48.2%',
82
+ primaryForeground: '60 9.1% 97.8%',
83
+ secondary: '240 3.7% 15.9%',
84
+ secondaryForeground: '0 0% 98%',
85
+ ring: '20.5 90.2% 48.2%',
86
+ border: '240 3.7% 15.9%',
87
+ input: '240 3.7% 15.9%'
88
+ }
89
+ },
90
+ rose: {
91
+ light: {
92
+ primary: '346.8 77.2% 49.8%',
93
+ primaryForeground: '355.7 100% 97.3%',
94
+ secondary: '240 4.8% 95.9%',
95
+ secondaryForeground: '240 5.9% 10%',
96
+ ring: '346.8 77.2% 49.8%',
97
+ border: '240 5.9% 90%',
98
+ input: '240 5.9% 90%'
99
+ },
100
+ dark: {
101
+ primary: '346.8 77.2% 49.8%',
102
+ primaryForeground: '355.7 100% 97.3%',
103
+ secondary: '240 3.7% 15.9%',
104
+ secondaryForeground: '0 0% 98%',
105
+ ring: '346.8 77.2% 49.8%',
106
+ border: '240 3.7% 15.9%',
107
+ input: '240 3.7% 15.9%'
108
+ }
109
+ }
110
+ };
111
+ // Cores personalizadas / fallback
112
+ const primaryHex = config.primaryColor || '#7136ff';
113
+ const secondaryHex = config.secondaryColor || '#ff6633';
114
+ const primaryHsl = (0, colors_1.hexToHsl)(primaryHex);
115
+ const secondaryHsl = (0, colors_1.hexToHsl)(secondaryHex);
116
+ const customColors = {
117
+ light: {
118
+ primary: primaryHsl,
119
+ primaryForeground: '0 0% 98%',
120
+ secondary: secondaryHsl,
121
+ secondaryForeground: '240 5.9% 10%',
122
+ ring: primaryHsl,
123
+ border: '240 5.9% 90%',
124
+ input: '240 5.9% 90%'
125
+ },
126
+ dark: {
127
+ primary: primaryHsl,
128
+ primaryForeground: '240 5.9% 10%',
129
+ secondary: '240 3.7% 15.9%',
130
+ secondaryForeground: '0 0% 98%',
131
+ ring: primaryHsl,
132
+ border: '240 3.7% 15.9%',
133
+ input: '240 3.7% 15.9%'
134
+ }
135
+ };
136
+ const selectedTheme = (theme !== 'custom' && themeColors[theme]) ? themeColors[theme] : customColors;
137
+ return `/* Tema do DevKit.
138
+ O style visual dos primitives vem do Helm gerado pelo Spartan CLI em libs/ui. */
139
+
140
+ :root {
141
+ color-scheme: light;
142
+
143
+ --font-family: ${fontFamily};
144
+
145
+ /* Variáveis Spartan / Shadcn UI - Tema Light */
146
+ --background: hsl(0 0% 98%);
147
+ --foreground: hsl(240 10% 3.9%);
148
+ --card: hsl(0 0% 100%);
149
+ --card-foreground: hsl(240 10% 3.9%);
150
+ --popover: hsl(0 0% 100%);
151
+ --popover-foreground: hsl(240 10% 3.9%);
152
+ --primary: hsl(${selectedTheme.light.primary});
153
+ --primary-foreground: hsl(${selectedTheme.light.primaryForeground});
154
+ --secondary: hsl(${selectedTheme.light.secondary});
155
+ --secondary-foreground: hsl(${selectedTheme.light.secondaryForeground});
156
+ --muted: hsl(240 4.8% 95.9%);
157
+ --muted-foreground: hsl(240 3.8% 46.1%);
158
+ --accent: hsl(240 4.8% 95.9%);
159
+ --accent-foreground: hsl(240 5.9% 10%);
160
+ --destructive: hsl(0 84.2% 60.2%);
161
+ --destructive-foreground: hsl(0 0% 98%);
162
+ --border: hsl(${selectedTheme.light.border});
163
+ --input: hsl(${selectedTheme.light.input});
164
+ --ring: hsl(${selectedTheme.light.ring});
165
+ }
166
+
167
+ :root.dark,
168
+ .dark {
169
+ color-scheme: dark;
170
+
171
+ /* Variáveis Spartan / Shadcn UI - Tema Dark */
172
+ --background: hsl(240 10% 3.9%);
173
+ --foreground: hsl(0 0% 98%);
174
+ --card: hsl(240 10% 3.9%);
175
+ --card-foreground: hsl(0 0% 98%);
176
+ --popover: hsl(240 10% 3.9%);
177
+ --popover-foreground: hsl(0 0% 98%);
178
+ --primary: hsl(${selectedTheme.dark.primary});
179
+ --primary-foreground: hsl(${selectedTheme.dark.primaryForeground});
180
+ --secondary: hsl(${selectedTheme.dark.secondary});
181
+ --secondary-foreground: hsl(${selectedTheme.dark.secondaryForeground});
182
+ --muted: hsl(240 3.7% 15.9%);
183
+ --muted-foreground: hsl(240 5% 64.9%);
184
+ --accent: hsl(240 3.7% 15.9%);
185
+ --accent-foreground: hsl(0 0% 98%);
186
+ --destructive: hsl(0 62.8% 30.6%);
187
+ --destructive-foreground: hsl(0 0% 98%);
188
+ --border: hsl(${selectedTheme.dark.border});
189
+ --input: hsl(${selectedTheme.dark.input});
190
+ --ring: hsl(${selectedTheme.dark.ring});
191
+ }
192
+
193
+ body {
194
+ font-family: var(--font-family);
195
+ background-color: var(--background);
196
+ color: var(--foreground);
197
+ margin: 0;
198
+ }
199
+
200
+ @layer base {
201
+ * {
202
+ @apply border-border outline-ring/50;
203
+ }
204
+ body {
205
+ @apply bg-background text-foreground;
206
+ }
207
+ }
208
+
209
+ `;
210
+ }
@@ -0,0 +1 @@
1
+ export * from './ui';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ui"), exports);
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@devstroupe/devkit-cli",
3
+ "version": "1.0.0",
4
+ "description": "DevsTroupe Development Kit CLI — scaffold NestJS+Angular projects, inject Spartan UI, generate CRUDs and audit architectural governance",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "devstroupe",
8
+ "devkit",
9
+ "cli",
10
+ "nestjs",
11
+ "angular",
12
+ "spartan",
13
+ "crud",
14
+ "scaffolding",
15
+ "generator",
16
+ "code-generation",
17
+ "governance"
18
+ ],
19
+ "homepage": "https://github.com/devstroupe/devkit#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/devstroupe/devkit.git",
23
+ "directory": "packages/devkit-cli"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md"
31
+ ],
32
+ "main": "dist/index.js",
33
+ "bin": {
34
+ "devstroupe": "./dist/index.js"
35
+ },
36
+ "dependencies": {
37
+ "@devstroupe/devkit-core": "^1.0.0",
38
+ "commander": "^12.0.0",
39
+ "fs-extra": "^11.2.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/fs-extra": "^11.0.4",
43
+ "@types/node": "^20.11.0",
44
+ "typescript": "^5.4.5"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc && node postbuild.js && chmod +x dist/index.js",
48
+ "test": "tsc && node --test dist/rules/linter-rules.test.js dist/templates/relationship-templates.test.js"
49
+ }
50
+ }