@hkdigital/lib-core 0.5.69 → 0.5.71
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.
|
@@ -13,6 +13,6 @@ declare const Presenter: import("svelte").Component<{
|
|
|
13
13
|
classes?: string;
|
|
14
14
|
slides?: import("./typedef.js").Slide[];
|
|
15
15
|
presenterRef?: import("./Presenter.state.svelte.js").PresenterRef;
|
|
16
|
-
layoutSnippet: import("svelte").Snippet<[import("
|
|
16
|
+
layoutSnippet: import("svelte").Snippet<[import("./typedef.js").Slide | null, import("./typedef.js").Layer]>;
|
|
17
17
|
loadingSnippet?: import("svelte").Snippet;
|
|
18
18
|
}, {}, "presenterRef">;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { default as Presenter } from "./Presenter.svelte";
|
|
2
2
|
export { default as ImageSlide } from "./ImageSlide.svelte";
|
|
3
3
|
export { PresenterState } from "./Presenter.state.svelte.js";
|
|
4
|
-
export * from "./typedef.js";
|
|
5
4
|
export * from "./constants.js";
|
|
6
5
|
export * from "./util.js";
|
package/package.json
CHANGED
|
@@ -12,6 +12,55 @@ const SRC_DIR = join(PROJECT_ROOT, 'src');
|
|
|
12
12
|
*/
|
|
13
13
|
const EXTERNAL_SCOPES_TO_VALIDATE = ['@hkdigital'];
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Project aliases from svelte.config.js
|
|
17
|
+
* Loaded dynamically at startup
|
|
18
|
+
*
|
|
19
|
+
* @type {Record<string, string>}
|
|
20
|
+
*/
|
|
21
|
+
let PROJECT_ALIASES = {};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Load aliases from svelte.config.js
|
|
25
|
+
*
|
|
26
|
+
* @returns {Promise<Record<string, string>>} Alias mappings
|
|
27
|
+
*/
|
|
28
|
+
async function loadAliases() {
|
|
29
|
+
try {
|
|
30
|
+
const configPath = join(PROJECT_ROOT, 'svelte.config.js');
|
|
31
|
+
|
|
32
|
+
// Use dynamic import to load ES module
|
|
33
|
+
const config = await import(`file://${configPath}`);
|
|
34
|
+
const svelteConfig = config.default;
|
|
35
|
+
|
|
36
|
+
if (svelteConfig?.kit?.alias) {
|
|
37
|
+
return svelteConfig.kit.alias;
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// Config file doesn't exist or can't be loaded
|
|
41
|
+
// This is OK - not all projects will have aliases
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Resolve an alias path to its filesystem location
|
|
49
|
+
*
|
|
50
|
+
* @param {string} aliasPath - Import path using alias (e.g., $hklib-core/...)
|
|
51
|
+
*
|
|
52
|
+
* @returns {string|null} Resolved filesystem path or null
|
|
53
|
+
*/
|
|
54
|
+
function resolveAliasPath(aliasPath) {
|
|
55
|
+
for (const [alias, target] of Object.entries(PROJECT_ALIASES)) {
|
|
56
|
+
if (aliasPath === alias || aliasPath.startsWith(alias + '/')) {
|
|
57
|
+
const pathAfterAlias = aliasPath.slice(alias.length);
|
|
58
|
+
return join(PROJECT_ROOT, target, pathAfterAlias);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
15
64
|
/**
|
|
16
65
|
* Find all JS and Svelte files recursively
|
|
17
66
|
*
|
|
@@ -240,10 +289,145 @@ async function findExternalBarrelExport(importPath, targetName) {
|
|
|
240
289
|
|
|
241
290
|
if (!shouldCheck) return null;
|
|
242
291
|
|
|
292
|
+
// Read package.json to check for exports mapping
|
|
293
|
+
let exportsMapping = null;
|
|
294
|
+
try {
|
|
295
|
+
const pkgJsonPath = join(nodeModulesPath, 'package.json');
|
|
296
|
+
const pkgJsonContent = await readFile(pkgJsonPath, 'utf-8');
|
|
297
|
+
const pkgJson = JSON.parse(pkgJsonContent);
|
|
298
|
+
|
|
299
|
+
// Check if there's a "./*" export mapping
|
|
300
|
+
if (pkgJson.exports && pkgJson.exports['./*']) {
|
|
301
|
+
const mapping = pkgJson.exports['./*'];
|
|
302
|
+
const mappingStr = typeof mapping === 'string' ?
|
|
303
|
+
mapping : mapping.default;
|
|
304
|
+
|
|
305
|
+
// Extract prefix from mapping like "./dist/*" -> "dist/"
|
|
306
|
+
if (mappingStr && mappingStr.includes('*')) {
|
|
307
|
+
exportsMapping = mappingStr.replace(/\/?\*$/, '');
|
|
308
|
+
if (exportsMapping.startsWith('./')) {
|
|
309
|
+
exportsMapping = exportsMapping.slice(2);
|
|
310
|
+
}
|
|
311
|
+
if (exportsMapping && !exportsMapping.endsWith('/')) {
|
|
312
|
+
exportsMapping += '/';
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
// Could not read package.json, continue without mapping
|
|
318
|
+
}
|
|
319
|
+
|
|
243
320
|
// Try progressively higher-level barrel files
|
|
244
321
|
for (let i = 1; i < pathInPackage.length; i++) {
|
|
245
322
|
const barrelPath = pathInPackage.slice(0, i).join('/') + '.js';
|
|
246
|
-
|
|
323
|
+
|
|
324
|
+
// Try both with and without exports mapping
|
|
325
|
+
const pathsToTry = [
|
|
326
|
+
join(nodeModulesPath, barrelPath),
|
|
327
|
+
exportsMapping ?
|
|
328
|
+
join(nodeModulesPath, exportsMapping + barrelPath) : null
|
|
329
|
+
].filter(Boolean);
|
|
330
|
+
|
|
331
|
+
for (const fsBarrelPath of pathsToTry) {
|
|
332
|
+
try {
|
|
333
|
+
const stats = await stat(fsBarrelPath);
|
|
334
|
+
if (stats.isFile()) {
|
|
335
|
+
const content = await readFile(fsBarrelPath, 'utf-8');
|
|
336
|
+
|
|
337
|
+
// Check if this barrel exports our target
|
|
338
|
+
// Patterns to match:
|
|
339
|
+
// export { TextButton } from './path';
|
|
340
|
+
// export * from './path';
|
|
341
|
+
const exportPatterns = [
|
|
342
|
+
// Named export with exact name
|
|
343
|
+
new RegExp(
|
|
344
|
+
`export\\s+\\{[^}]*\\b${targetName}\\b[^}]*\\}`,
|
|
345
|
+
'm'
|
|
346
|
+
),
|
|
347
|
+
// Re-export all
|
|
348
|
+
/export\s+\*\s+from/,
|
|
349
|
+
// Default export
|
|
350
|
+
new RegExp(`export\\s+default\\s+${targetName}\\b`, 'm')
|
|
351
|
+
];
|
|
352
|
+
|
|
353
|
+
if (exportPatterns.some(pattern => pattern.test(content))) {
|
|
354
|
+
return `${pkgName}/${barrelPath}`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch {
|
|
358
|
+
// File doesn't exist, continue
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Find highest-level barrel export in alias path
|
|
368
|
+
*
|
|
369
|
+
* For $hklib-core/ui/primitives/buttons/index.js:
|
|
370
|
+
* - Check $hklib-core/ui/primitives.js
|
|
371
|
+
* - Check $hklib-core/ui.js
|
|
372
|
+
*
|
|
373
|
+
* @param {string} importPath - Alias import path
|
|
374
|
+
* @param {string} targetName - Name of export to find
|
|
375
|
+
*
|
|
376
|
+
* @returns {Promise<string|null>} Suggested barrel path or null
|
|
377
|
+
*/
|
|
378
|
+
async function findAliasBarrelExport(importPath, targetName) {
|
|
379
|
+
// Find the matching alias
|
|
380
|
+
let matchedAlias = null;
|
|
381
|
+
let pathAfterAlias = null;
|
|
382
|
+
|
|
383
|
+
for (const alias of Object.keys(PROJECT_ALIASES)) {
|
|
384
|
+
if (importPath === alias || importPath.startsWith(alias + '/')) {
|
|
385
|
+
matchedAlias = alias;
|
|
386
|
+
pathAfterAlias = importPath.slice(alias.length);
|
|
387
|
+
if (pathAfterAlias.startsWith('/')) {
|
|
388
|
+
pathAfterAlias = pathAfterAlias.slice(1);
|
|
389
|
+
}
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!matchedAlias || !pathAfterAlias) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const pathInAlias = pathAfterAlias.split('/');
|
|
399
|
+
|
|
400
|
+
// If no path in alias, nothing to suggest
|
|
401
|
+
if (pathInAlias.length === 0 || pathInAlias[0] === '') {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const aliasRootPath = resolveAliasPath(matchedAlias);
|
|
406
|
+
|
|
407
|
+
// Extract target to find (last part without extension)
|
|
408
|
+
const lastPart = pathInAlias[pathInAlias.length - 1];
|
|
409
|
+
const targetBase = lastPart.replace(/\.(js|svelte)$/, '');
|
|
410
|
+
|
|
411
|
+
// Only check for specific import types (matches internal logic)
|
|
412
|
+
// 1. Explicit index.js imports
|
|
413
|
+
// 2. Component files (.svelte)
|
|
414
|
+
// 3. Class files (capitalized .js)
|
|
415
|
+
let shouldCheck = false;
|
|
416
|
+
|
|
417
|
+
if (lastPart === 'index.js') {
|
|
418
|
+
shouldCheck = true;
|
|
419
|
+
} else if (lastPart.endsWith('.svelte')) {
|
|
420
|
+
shouldCheck = true;
|
|
421
|
+
} else if (lastPart.match(/^[A-Z][^/]*\.js$/)) {
|
|
422
|
+
shouldCheck = true;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!shouldCheck) return null;
|
|
426
|
+
|
|
427
|
+
// Try progressively higher-level barrel files
|
|
428
|
+
for (let i = 1; i < pathInAlias.length; i++) {
|
|
429
|
+
const barrelPath = pathInAlias.slice(0, i).join('/') + '.js';
|
|
430
|
+
const fsBarrelPath = join(aliasRootPath, barrelPath);
|
|
247
431
|
|
|
248
432
|
try {
|
|
249
433
|
const stats = await stat(fsBarrelPath);
|
|
@@ -267,7 +451,7 @@ async function findExternalBarrelExport(importPath, targetName) {
|
|
|
267
451
|
];
|
|
268
452
|
|
|
269
453
|
if (exportPatterns.some(pattern => pattern.test(content))) {
|
|
270
|
-
return `${
|
|
454
|
+
return `${matchedAlias}/${barrelPath}`;
|
|
271
455
|
}
|
|
272
456
|
}
|
|
273
457
|
} catch {
|
|
@@ -316,6 +500,36 @@ async function validateFile(filePath) {
|
|
|
316
500
|
// Strip query parameters (Vite asset imports like ?preset=render)
|
|
317
501
|
const importPath = importPathRaw.split('?')[0];
|
|
318
502
|
|
|
503
|
+
// Check if import uses a project alias
|
|
504
|
+
const isAliasImport = Object.keys(PROJECT_ALIASES).some(
|
|
505
|
+
alias => importPath === alias || importPath.startsWith(alias + '/')
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
if (isAliasImport) {
|
|
509
|
+
// Extract imported names from the import statement
|
|
510
|
+
const importedNames = extractImportNames(line);
|
|
511
|
+
|
|
512
|
+
// Check each imported name for barrel exports
|
|
513
|
+
for (const importedName of importedNames) {
|
|
514
|
+
const barrelPath = await findAliasBarrelExport(
|
|
515
|
+
importPath,
|
|
516
|
+
importedName
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
if (barrelPath) {
|
|
520
|
+
errors.push(
|
|
521
|
+
`${relativePath}:${lineNum}\n` +
|
|
522
|
+
` from '${importPath}'\n` +
|
|
523
|
+
` => from '${barrelPath}' (use barrel export)`
|
|
524
|
+
);
|
|
525
|
+
break; // Only report once per line
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Skip further validation for alias imports
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
|
|
319
533
|
// Check external packages from configured scopes
|
|
320
534
|
const isExternalPackage = !importPath.startsWith('./') &&
|
|
321
535
|
!importPath.startsWith('../') &&
|
|
@@ -662,6 +876,17 @@ async function validateFile(filePath) {
|
|
|
662
876
|
async function main() {
|
|
663
877
|
console.log('Validating import paths...\n');
|
|
664
878
|
|
|
879
|
+
// Load project aliases from svelte.config.js
|
|
880
|
+
PROJECT_ALIASES = await loadAliases();
|
|
881
|
+
|
|
882
|
+
if (Object.keys(PROJECT_ALIASES).length > 0) {
|
|
883
|
+
console.log('Found project aliases:');
|
|
884
|
+
for (const [alias, target] of Object.entries(PROJECT_ALIASES)) {
|
|
885
|
+
console.log(` ${alias} → ${target}`);
|
|
886
|
+
}
|
|
887
|
+
console.log();
|
|
888
|
+
}
|
|
889
|
+
|
|
665
890
|
const files = await findFiles(SRC_DIR);
|
|
666
891
|
const allErrors = [];
|
|
667
892
|
|