@hkdigital/lib-core 0.5.77 → 0.5.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -309,7 +309,6 @@ The validator automatically reads path aliases from your
309
309
  `svelte.config.js` and applies the same barrel export validation rules
310
310
  to alias imports. This ensures consistent import patterns across:
311
311
  - Internal `$lib/` imports
312
- - Project aliases like `$hklib-core`, `$hklib-pro`, etc.
313
312
  - External `@hkdigital/*` package imports
314
313
 
315
314
  **Validation rules (enforced for `src/lib/` files only):**
@@ -344,14 +343,6 @@ import Button from '$lib/ui/primitives/buttons/Button.svelte';
344
343
  import { ProfileBlocks } from '$lib/ui/components.js';
345
344
  import { Button } from '$lib/ui/primitives.js';
346
345
 
347
- // Project aliases - instead of deep imports:
348
- import { Logger } from '$hklib-core/logging/logger/Logger.js';
349
- import { HttpClient } from '$hklib-core/network/http/HttpClient.js';
350
-
351
- // Use barrel exports:
352
- import { Logger } from '$hklib-core/logging.js';
353
- import { HttpClient } from '$hklib-core/network/http.js';
354
-
355
346
  // External imports - instead of deep imports:
356
347
  import { TextButton } from '@hkdigital/lib-core/ui/primitives/buttons/index.js';
357
348
  import { TextInput } from '@hkdigital/lib-core/ui/primitives/inputs/index.js';
@@ -380,7 +371,6 @@ Validating import paths...
380
371
  Found project aliases:
381
372
  $src → src
382
373
  $examples → src/routes/examples
383
- $hklib-core → src/lib
384
374
 
385
375
  src/lib/ui/panels/Panel.svelte:3
386
376
  from '$src/lib/ui/components.js'
@@ -394,10 +384,6 @@ src/lib/ui/pages/Profile.svelte:8
394
384
  from '$lib/ui/components/profile-blocks/ProfileBlocks.svelte'
395
385
  => from '$lib/ui/components.js' (use barrel export for shorter imports)
396
386
 
397
- src/lib/forms/LoginForm.svelte:4
398
- from '$hklib-core/logging/logger/Logger.js'
399
- => from '$hklib-core/logging.js' (use barrel export)
400
-
401
387
  src/lib/forms/LoginForm.svelte:6
402
388
  from '@hkdigital/lib-core/ui/primitives/buttons/index.js'
403
389
  => from '@hkdigital/lib-core/ui/primitives.js' (use barrel export)
@@ -409,8 +395,8 @@ src/routes/explorer/[...path]/+page.svelte:4
409
395
 
410
396
  **What gets checked for barrel export suggestions:**
411
397
 
412
- The validator only suggests barrel exports (for `$lib/`, project aliases,
413
- and external `@hkdigital/*` packages) for:
398
+ The validator only suggests barrel exports (for `$lib/` and external
399
+ `@hkdigital/*` packages) for:
414
400
  - Explicit `index.js` imports
415
401
  - Component files (`.svelte`)
416
402
  - Class files (capitalized `.js` files)
@@ -418,20 +404,6 @@ and external `@hkdigital/*` packages) for:
418
404
  Intentional imports like `helpers.js`, `config.js`, or other lowercase
419
405
  utility files are assumed to be the public API and won't be flagged.
420
406
 
421
- **Alias configuration:**
422
-
423
- The validator automatically detects aliases in your `svelte.config.js`.
424
- For example, if your config has:
425
- ```js
426
- alias: {
427
- $src: 'src',
428
- $hklib-core: 'node_modules/@hkdigital/lib-core/dist'
429
- }
430
- ```
431
-
432
- The validator will apply the same barrel export rules to these aliases
433
- as it does to `$lib/` and `@hkdigital/*` imports.
434
-
435
407
  ### Import Patterns and Export Structure
436
408
 
437
409
  **Public exports use domain-specific files matching folder names:**
package/claude.md CHANGED
@@ -130,6 +130,51 @@ This is a modern SvelteKit library built with Svelte 5 and Skeleton.dev v3 compo
130
130
 
131
131
  **Import validation:** Run `node scripts/validate-imports.mjs` to validate import patterns. The validator checks for barrel export files at each level and suggests the highest-level file that exports your target. These rules are enforced for `src/lib/` files only. Files in `src/routes/` can use relative imports freely. See README.md "Import Validation" section for usage in other projects.
132
132
 
133
+ ### Critical: Aliases in Libraries vs Apps
134
+
135
+ **IMPORTANT**: Due to Vite/SvelteKit limitations, aliases in library
136
+ code (`src/lib/**`) must resolve to paths **inside the project folder**.
137
+ Aliases to external packages or paths outside the project break when
138
+ building libraries.
139
+
140
+ **The problem:**
141
+ ```javascript
142
+ // ❌ These aliases don't work in src/lib/** files:
143
+ // svelte.config.js
144
+ alias: {
145
+ '$ext': 'node_modules/@hkdigital/lib-core/dist', // Outside project
146
+ '$pkg': '@hkdigital/lib-core' // Package name (doesn't resolve)
147
+ }
148
+
149
+ // In src/lib/** - BREAKS during build!
150
+ import { Button } from '$ext/ui/primitives.js';
151
+ ```
152
+
153
+ **The solution:**
154
+ - **In library code (`src/lib/**`)**: Use direct package imports
155
+ - **In app code (`src/routes/**`)**: Aliases work fine
156
+
157
+ ```javascript
158
+ // ✅ Library code - use direct imports
159
+ import { Button } from '@hkdigital/lib-core/ui/primitives.js';
160
+
161
+ // ✅ App code - aliases OK (not built/published)
162
+ import { Button } from '$ext/ui/primitives.js';
163
+ ```
164
+
165
+ **Local aliases work everywhere:**
166
+ ```javascript
167
+ // svelte.config.js
168
+ alias: {
169
+ '$lib': 'src/lib', // ✅ Inside project - works everywhere
170
+ '$examples': 'src/routes/examples' // ✅ Inside project
171
+ }
172
+ ```
173
+
174
+ **Why**: Vite/SvelteKit aliases are designed for internal project
175
+ structure. Build tools cannot properly handle aliases pointing outside
176
+ the project or to package names.
177
+
133
178
  ## Class Export Conventions
134
179
  - **All classes should be default exports**: `export default class ClassName`
135
180
  - **Import classes without destructuring**: `import ClassName from './ClassName.js'`
@@ -87,8 +87,8 @@ const STROKE_WIDTH_SIZES = {
87
87
  *
88
88
  * @example Usage with generateTailwindThemeExtensions
89
89
  * ```javascript
90
- * import { generateTailwindThemeExtensions } from '@hkdigital/lib-core/design/index.js';
91
- * import { designTokens } from '@hkdigital/lib-core/design/config/design-tokens.js';
90
+ * import { generateTailwindThemeExtensions } from '../index.js';
91
+ * import { designTokens } from './design-tokens.js';
92
92
  *
93
93
  * const themeExtensions = generateTailwindThemeExtensions(designTokens);
94
94
  * ```
@@ -27,8 +27,8 @@
27
27
  * // ... other exports
28
28
  *
29
29
  * // your-project/tailwind.config.js
30
- * import { generateTailwindThemeExtensions } from '@hkdigital/lib-core/design/index.js';
31
- * import { customUtilitiesPlugin } from '@hkdigital/lib-core/design/index.js';
30
+ * import { generateTailwindThemeExtensions } from '../index.js';
31
+ * import { customUtilitiesPlugin } from '../index.js';
32
32
  * import * as designConfig from './src/lib/design/design-config.js';
33
33
  *
34
34
  * export default {
@@ -27,8 +27,8 @@
27
27
  * // ... other exports
28
28
  *
29
29
  * // your-project/tailwind.config.js
30
- * import { generateTailwindThemeExtensions } from '@hkdigital/lib-core/design/index.js';
31
- * import { customUtilitiesPlugin } from '@hkdigital/lib-core/design/index.js';
30
+ * import { generateTailwindThemeExtensions } from '../index.js';
31
+ * import { customUtilitiesPlugin } from '../index.js';
32
32
  * import * as designConfig from './src/lib/design/design-config.js';
33
33
  *
34
34
  * export default {
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @example Basic usage with default tokens
9
9
  * ```javascript
10
- * import { generateTailwindThemeExtensions, designTokens, customUtilitiesPlugin } from '@hkdigital/lib-core/design/index.js';
10
+ * import { generateTailwindThemeExtensions, designTokens, customUtilitiesPlugin } from './index.js';
11
11
  *
12
12
  * const themeExtensions = generateTailwindThemeExtensions(designTokens);
13
13
  *
@@ -21,7 +21,7 @@
21
21
  *
22
22
  * @example Custom design tokens
23
23
  * ```javascript
24
- * import { generateTailwindThemeExtensions } from '@hkdigital/lib-core/design/index.js';
24
+ * import { generateTailwindThemeExtensions } from './index.js';
25
25
  *
26
26
  * const myTokens = {
27
27
  * TEXT_POINT_SIZES: [4, 8, 12, 16, 24],
@@ -25,7 +25,7 @@
25
25
  * @example
26
26
  * // +layout.svelte
27
27
  * <script>
28
- * import { designTokens, designTokensToRootCssVars } from '@hkdigital/lib-core/design/index.js';
28
+ * import { designTokens, designTokensToRootCssVars } from '../index.js';
29
29
  * </script>
30
30
  *
31
31
  * <svelte:head>
@@ -114,7 +114,7 @@ function setRootCssVar(varName, value) {
114
114
  * @example
115
115
  * // +layout.svelte
116
116
  * <script>
117
- * import { designTokens, designTokensToRootCssVars } from '@hkdigital/lib-core/design/index.js';
117
+ * import { designTokens, designTokensToRootCssVars } from '../index.js';
118
118
  * </script>
119
119
  *
120
120
  * <svelte:head>
@@ -188,7 +188,7 @@ When integrating with a service management system, you can set up global
188
188
  error handling and forward service logs to the main logger:
189
189
 
190
190
  ```javascript
191
- import { ServiceManager } from '$hklib-core/services/index.js';
191
+ import { ServiceManager } from '@hkdigital/lib-core/services/index.js';
192
192
  import { initClientLogger } from '$lib/logging/client.js';
193
193
 
194
194
  /** @type {ServiceManager} */
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @example
10
10
  * // Basic usage
11
- * import { Logger, LOG, INFO, DEBUG } from '@hkdigital/lib-core/logger/index.js';
11
+ * import { Logger, LOG, INFO, DEBUG } from '../../../logger/index.js';
12
12
  *
13
13
  * const logger = new Logger('myService', INFO);
14
14
  *
@@ -163,7 +163,7 @@ Manages multiple services with dependency resolution and coordinated lifecycle o
163
163
  ### Usage
164
164
 
165
165
  ```javascript
166
- import { ServiceManager } from '$hklib-core/services/index.js';
166
+ import { ServiceManager } from '@hkdigital/lib-core/services/index.js';
167
167
 
168
168
  import DatabaseService from './services/DatabaseService.js';
169
169
  import AuthService from './services/AuthService.js';
@@ -211,7 +211,7 @@ class AuthService extends ServiceBase {
211
211
  /** @type {(<T>(serviceName: string) => T)} */
212
212
  #getService;
213
213
 
214
- /** @type {() => import('$hklib-core/services/index.js').ServiceManager} */
214
+ /** @type {() => import('@hkdigital/lib-core/services/index.js').ServiceManager} */
215
215
  #getManager;
216
216
 
217
217
  constructor(serviceName, options) {
@@ -257,7 +257,7 @@ export default class PlayerService extends ServiceBase {
257
257
 
258
258
  /**
259
259
  * @param {string} serviceName
260
- * @param {import('$hklib-core/services/typedef.js').ServiceOptions} [options]
260
+ * @param {import('@hkdigital/lib-core/services/typedef.js').ServiceOptions} [options]
261
261
  */
262
262
  constructor(serviceName, options) {
263
263
  super(serviceName, options);
@@ -7,7 +7,7 @@
7
7
  } from './gamebox.util.js';
8
8
 
9
9
  import { enableContainerScaling } from '../../../../design/index.js';
10
- // import { enableContainerScaling } from '@hkdigital/lib-core/design/index.js';
10
+ // import { enableContainerScaling } from '../../../../design/index.js';
11
11
 
12
12
  /**
13
13
  * @typedef {{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.77",
3
+ "version": "0.5.79",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"
package/scripts/README.md CHANGED
@@ -35,6 +35,8 @@ node scripts/validate-imports.mjs
35
35
  etc. must be explicit
36
36
  5. **Import paths must exist** - All imports must resolve to actual
37
37
  files
38
+ 6. **Aliases must resolve inside project** - Library code (`src/lib/`)
39
+ can only use aliases that resolve to paths inside the project folder
38
40
 
39
41
  ## Import Rules
40
42
 
@@ -180,6 +182,69 @@ import { current } from './existing-file.js';
180
182
  them at build time or runtime. Helps prevent errors when refactoring
181
183
  or moving files.
182
184
 
185
+ ### Rule 6: Aliases must resolve inside the project
186
+
187
+ **Library code must only use aliases that resolve to paths inside the
188
+ project folder**
189
+
190
+ Aliases are designed for internal project structure, not external
191
+ packages. Due to Vite/SvelteKit limitations, aliases that point
192
+ outside the project folder or to package names cannot work correctly in
193
+ library code.
194
+
195
+ ❌ Bad (aliases that don't work in `src/lib/`):
196
+ ```javascript
197
+ // svelte.config.js
198
+ alias: {
199
+ // Points to node_modules (outside project)
200
+ '$ext-lib': 'node_modules/@some/library/dist',
201
+
202
+ // Package name (Vite treats as relative path, doesn't resolve)
203
+ '$pkg': '@some/library',
204
+
205
+ // Absolute path outside project
206
+ '$external': '/usr/local/lib/something'
207
+ }
208
+
209
+ // In src/lib/ui/MyComponent.svelte
210
+ import { Button } from '$ext-lib/ui/primitives.js';
211
+ // ^ Breaks when building library!
212
+ ```
213
+
214
+ ✅ Good (use direct package imports):
215
+ ```javascript
216
+ // In src/lib/ui/MyComponent.svelte
217
+ import { Button } from '@some/library/ui/primitives.js';
218
+ ```
219
+
220
+ ✅ Good (local aliases work everywhere):
221
+ ```javascript
222
+ // svelte.config.js
223
+ alias: {
224
+ '$lib': 'src/lib', // ✅ Inside project
225
+ '$examples': 'src/routes/examples' // ✅ Inside project
226
+ }
227
+
228
+ // In src/lib/ui/MyComponent.svelte
229
+ import { helper } from '$lib/util/helpers.js'; // ✅ Works!
230
+ ```
231
+
232
+ ✅ Also good (aliases work fine in app code):
233
+ ```javascript
234
+ // In src/routes/+page.svelte (not built/published)
235
+ import { Button } from '$ext-lib/ui/primitives.js';
236
+ // ✅ OK - app code isn't published
237
+ ```
238
+
239
+ **Scope:**
240
+ - **Enforced in**: `src/lib/**` (library code that gets built)
241
+ - **Allowed in**: `src/routes/**` (app code, not published)
242
+
243
+ **Why:** Vite/SvelteKit aliases are designed for internal project
244
+ structure. Build tools (`@sveltejs/package`, Vite) cannot properly
245
+ handle aliases pointing outside the project folder or to package names.
246
+ For external dependencies, use direct imports.
247
+
183
248
  ## How Module Resolution Works
184
249
 
185
250
  Understanding how Node.js and Vite resolve imports helps explain
@@ -23,6 +23,15 @@ const EXTERNAL_SCOPES_TO_VALIDATE = ['@hkdigital'];
23
23
  */
24
24
  let PROJECT_ALIASES = {};
25
25
 
26
+ /**
27
+ * Unsafe aliases that don't resolve inside the project folder
28
+ * These break when building libraries with @sveltejs/package
29
+ *
30
+ * Maps alias name to suggested fix (package name or explanation)
31
+ * @type {Map<string, string>}
32
+ */
33
+ const UNSAFE_ALIASES = new Map();
34
+
26
35
  /**
27
36
  * Load aliases from svelte.config.js
28
37
  *
@@ -47,10 +56,66 @@ async function loadAliases() {
47
56
  return {};
48
57
  }
49
58
 
59
+ /**
60
+ * Extract package name from node_modules path
61
+ *
62
+ * @param {string} path - Path containing node_modules
63
+ *
64
+ * @returns {string|null} Package name or null
65
+ */
66
+ function extractPackageNameFromPath(path) {
67
+ // Find node_modules in the path
68
+ const match = path.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
69
+ if (match) {
70
+ return match[1]; // Returns @scope/package or package
71
+ }
72
+ return null;
73
+ }
74
+
75
+ /**
76
+ * Detect unsafe aliases that don't resolve inside the project
77
+ * Populates the UNSAFE_ALIASES map
78
+ */
79
+ function detectUnsafeAliases() {
80
+ UNSAFE_ALIASES.clear();
81
+
82
+ for (const [alias, target] of Object.entries(PROJECT_ALIASES)) {
83
+ let suggestion = null;
84
+
85
+ // Resolve to absolute path
86
+ const resolvedPath = isAbsolute(target) ?
87
+ target : join(PROJECT_ROOT, target);
88
+
89
+ // Normalize both paths for comparison (resolve symlinks, etc.)
90
+ const normalizedResolved = resolve(resolvedPath);
91
+ const normalizedRoot = resolve(PROJECT_ROOT);
92
+
93
+ // Check if resolved path is inside the project folder
94
+ const isInsideProject = normalizedResolved.startsWith(normalizedRoot);
95
+
96
+ if (!isInsideProject) {
97
+ // Path is outside project - check if it's in node_modules
98
+ if (resolvedPath.includes('/node_modules/')) {
99
+ const packageName = extractPackageNameFromPath(resolvedPath);
100
+ if (packageName) {
101
+ suggestion = packageName;
102
+ }
103
+ } else {
104
+ // Outside project but not node_modules
105
+ suggestion = '(path outside project - use direct imports)';
106
+ }
107
+
108
+ if (suggestion) {
109
+ UNSAFE_ALIASES.set(alias, suggestion);
110
+ }
111
+ }
112
+ }
113
+ }
114
+
50
115
  /**
51
116
  * Resolve an alias path to its filesystem location
52
117
  *
53
- * @param {string} aliasPath - Import path using alias (e.g., $hklib-core/...)
118
+ * @param {string} aliasPath - Import path using alias (e.g., $examples/...)
54
119
  *
55
120
  * @returns {string|null} Resolved filesystem path or null
56
121
  */
@@ -379,9 +444,9 @@ async function findExternalBarrelExport(importPath, targetName) {
379
444
  /**
380
445
  * Find highest-level barrel export in alias path
381
446
  *
382
- * For $hklib-core/ui/primitives/buttons/index.js:
383
- * - Check $hklib-core/ui/primitives.js
384
- * - Check $hklib-core/ui.js
447
+ * For $components/ui/primitives/buttons/index.js:
448
+ * - Check $components/ui/primitives.js
449
+ * - Check $components/ui.js
385
450
  *
386
451
  * @param {string} importPath - Alias import path
387
452
  * @param {string} targetName - Name of export to find
@@ -538,6 +603,42 @@ async function validateFile(filePath) {
538
603
  );
539
604
 
540
605
  if (isAliasImport) {
606
+ // Find which alias is being used
607
+ let matchedAlias = null;
608
+ for (const alias of Object.keys(PROJECT_ALIASES)) {
609
+ if (importPath === alias || importPath.startsWith(alias + '/')) {
610
+ matchedAlias = alias;
611
+ break;
612
+ }
613
+ }
614
+
615
+ // Check for unsafe alias usage in library code
616
+ if (isInLib && matchedAlias && UNSAFE_ALIASES.has(matchedAlias)) {
617
+ const suggestion = UNSAFE_ALIASES.get(matchedAlias);
618
+ const pathAfterAlias = importPath.slice(matchedAlias.length);
619
+
620
+ // Construct suggested import if it's a package name
621
+ let errorMsg;
622
+ if (suggestion.startsWith('(')) {
623
+ // Generic message (not a package name)
624
+ errorMsg = `${relativePath}:${lineNum}\n` +
625
+ ` from '${importPath}'\n` +
626
+ ` => ${suggestion}`;
627
+ } else {
628
+ // Package name - construct full import path
629
+ const suggestedImport = suggestion + pathAfterAlias;
630
+ errorMsg = `${relativePath}:${lineNum}\n` +
631
+ ` from '${importPath}'\n` +
632
+ ` => from '${suggestedImport}' ` +
633
+ `(alias resolves outside project)`;
634
+ }
635
+
636
+ errors.push(errorMsg);
637
+
638
+ // Skip further validation for this import
639
+ continue;
640
+ }
641
+
541
642
  // Extract imported names from the import statement
542
643
  const importedNames = extractImportNames(line);
543
644
 
@@ -981,6 +1082,22 @@ async function main() {
981
1082
  console.log();
982
1083
  }
983
1084
 
1085
+ // Detect unsafe aliases (outside project folder)
1086
+ detectUnsafeAliases();
1087
+
1088
+ if (UNSAFE_ALIASES.size > 0) {
1089
+ console.log(
1090
+ '⚠️ Unsafe aliases detected (resolve outside project folder):'
1091
+ );
1092
+ for (const [alias, suggestion] of UNSAFE_ALIASES.entries()) {
1093
+ console.log(
1094
+ ` ${alias} → ${suggestion} ` +
1095
+ `(breaks in src/lib/, OK in src/routes/)`
1096
+ );
1097
+ }
1098
+ console.log();
1099
+ }
1100
+
984
1101
  const files = await findFiles(SRC_DIR);
985
1102
  const allErrors = [];
986
1103