@hkdigital/lib-core 0.5.63 → 0.5.66

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
@@ -277,6 +277,43 @@ pnpm run upgrade:all # Update all packages
277
277
  pnpm run publish:npm # Version bump and publish to npm
278
278
  ```
279
279
 
280
+ ### Import Validation
281
+
282
+ The library includes a validation script to enforce consistent import
283
+ patterns. Run it in your project:
284
+
285
+ ```bash
286
+ node node_modules/@hkdigital/lib-core/scripts/validate-imports.mjs
287
+ ```
288
+
289
+ **Validation rules (enforced for `src/lib/` files only):**
290
+
291
+ 1. **Cross-domain imports** - Use `$lib/` instead of `../../../`
292
+ 2. **Parent index.js imports** - Use `$lib/` or import specific files
293
+ 3. **Non-standard extensions** - Include full extension (e.g.,
294
+ `.svelte.js`)
295
+ 4. **Directory imports** - Write explicitly (e.g., `./path/index.js`)
296
+ 5. **File existence** - All import paths must resolve to existing files
297
+
298
+ **Routes are exempt from strict rules:**
299
+
300
+ Files in `src/routes/` can use relative imports freely, including parent
301
+ navigation and index.js imports. Since SvelteKit doesn't provide a
302
+ `$routes` alias, relative imports are the standard pattern for route
303
+ files.
304
+
305
+ **Example output:**
306
+
307
+ ```
308
+ src/lib/ui/components/Button.svelte:7
309
+ from '$lib/ui/primitives/buttons'
310
+ => from '$lib/ui/primitives/buttons/index.js'
311
+
312
+ src/routes/explorer/[...path]/+page.svelte:4
313
+ from '../components/index.js'
314
+ ✅ Allowed in routes
315
+ ```
316
+
280
317
  ### Import Patterns and Export Structure
281
318
 
282
319
  **Public exports use domain-specific files matching folder names:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.63",
3
+ "version": "0.5.66",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"
@@ -2,10 +2,8 @@
2
2
 
3
3
  import { readdir, readFile, stat } from 'node:fs/promises';
4
4
  import { join, relative, resolve, dirname } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
5
 
7
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
- const PROJECT_ROOT = join(__dirname, '..');
6
+ const PROJECT_ROOT = process.cwd();
9
7
  const SRC_DIR = join(PROJECT_ROOT, 'src');
10
8
 
11
9
  /**
@@ -96,6 +94,8 @@ async function validateFile(filePath) {
96
94
  const relativePath = relative(PROJECT_ROOT, filePath);
97
95
  const isTestFile = filePath.endsWith('.test.js') ||
98
96
  filePath.endsWith('.spec.js');
97
+ const isInLib = filePath.includes('/src/lib/');
98
+ const isInRoutes = filePath.includes('/src/routes/');
99
99
 
100
100
  // Check each line for import statements
101
101
  const lines = content.split('\n');
@@ -127,17 +127,20 @@ async function validateFile(filePath) {
127
127
  }
128
128
 
129
129
  // Check 1: Cross-domain relative imports (3+ levels up)
130
- if (importPath.match(/^\.\.\/\.\.\/\.\.\//)) {
130
+ // Only enforce for lib files
131
+ if (isInLib && importPath.match(/^\.\.\/\.\.\/\.\.\//)) {
131
132
  errors.push(
132
- `${relativePath}:${lineNum} - Cross-domain relative import ` +
133
- `(use $lib/ instead)`
133
+ `${relativePath}:${lineNum}\n` +
134
+ ` from '${importPath}'\n` +
135
+ ` => Use $lib/ for cross-domain imports`
134
136
  );
135
137
  continue;
136
138
  }
137
139
 
138
- // Check 2: Local index.js imports (skip for test files)
140
+ // Check 2: Local index.js imports (skip for test files and routes)
139
141
  // Allow ./index.js and ./subfolder/index.js but flag parent navigation
140
- if (!isTestFile && importPath.match(/\/index\.js$/)) {
142
+ // Only enforce for lib files
143
+ if (isInLib && !isTestFile && importPath.match(/\/index\.js$/)) {
141
144
  // Allow same-directory and child directory imports
142
145
  // Examples: ./index.js, ./subfolder/index.js, ./(meta)/index.js
143
146
  // Flag parent navigation: ../index.js, ../../index.js
@@ -145,8 +148,9 @@ async function validateFile(filePath) {
145
148
 
146
149
  if (isParentNavigation) {
147
150
  errors.push(
148
- `${relativePath}:${lineNum} - Parent index.js import ` +
149
- `(use $lib/ or import specific file)`
151
+ `${relativePath}:${lineNum}\n` +
152
+ ` from '${importPath}'\n` +
153
+ ` => Use $lib/ or import specific file instead`
150
154
  );
151
155
  continue;
152
156
  }
@@ -256,8 +260,9 @@ async function validateFile(filePath) {
256
260
  if (stats.isFile()) {
257
261
  const correctImport = baseImportPath + ext;
258
262
  errors.push(
259
- `${relativePath}:${lineNum} - Missing non-standard ` +
260
- `extension (use '${correctImport}')`
263
+ `${relativePath}:${lineNum}\n` +
264
+ ` from '${importPath}'\n` +
265
+ ` => from '${correctImport}'`
261
266
  );
262
267
  foundNonStandard = true;
263
268
  break;
@@ -288,9 +293,10 @@ async function validateFile(filePath) {
288
293
 
289
294
  if (wouldBeParentNavigation) {
290
295
  errors.push(
291
- `${relativePath}:${lineNum} - Directory import requires ` +
292
- `parent navigation (create export file like '${importPath}.js' ` +
293
- `or import specific file)`
296
+ `${relativePath}:${lineNum}\n` +
297
+ ` from '${importPath}'\n` +
298
+ ` => Create export file like '${importPath}.js' or ` +
299
+ `import specific file`
294
300
  );
295
301
  continue;
296
302
  }
@@ -298,8 +304,9 @@ async function validateFile(filePath) {
298
304
  const suggestion = importPath.endsWith('/') ?
299
305
  `${importPath}index.js` : `${importPath}/index.js`;
300
306
  errors.push(
301
- `${relativePath}:${lineNum} - Directory import ` +
302
- `(write explicitly: '${suggestion}')`
307
+ `${relativePath}:${lineNum}\n` +
308
+ ` from '${importPath}'\n` +
309
+ ` => from '${suggestion}'`
303
310
  );
304
311
  continue;
305
312
  }
@@ -338,8 +345,9 @@ async function validateFile(filePath) {
338
345
 
339
346
  if (!fileExists) {
340
347
  errors.push(
341
- `${relativePath}:${lineNum} - Import path does not exist: ` +
342
- `'${importPath}'`
348
+ `${relativePath}:${lineNum}\n` +
349
+ ` from '${importPath}'\n` +
350
+ ` => Import path does not exist`
343
351
  );
344
352
  }
345
353
  }
@@ -363,8 +371,8 @@ async function main() {
363
371
 
364
372
  if (allErrors.length > 0) {
365
373
  console.error('❌ Found import path violations:\n');
366
- allErrors.forEach(error => console.error(` ${error}`));
367
- console.error(`\n${allErrors.length} error(s) found.`);
374
+ allErrors.forEach(error => console.error(`${error}\n`));
375
+ console.error(`${allErrors.length} error(s) found.`);
368
376
  process.exit(1);
369
377
  }
370
378