@softarc/native-federation 4.3.2 → 4.4.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 (41) hide show
  1. package/README.md +71 -1
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.js +2 -0
  4. package/dist/internal.d.ts +3 -2
  5. package/dist/internal.js +5 -1
  6. package/dist/lib/config/expand-mappings.d.ts +24 -0
  7. package/dist/lib/config/expand-mappings.js +88 -0
  8. package/dist/lib/config/get-used-dependencies.d.ts +0 -2
  9. package/dist/lib/config/get-used-dependencies.js +4 -40
  10. package/dist/lib/config/mapped-paths.d.ts +7 -2
  11. package/dist/lib/config/mapped-paths.js +21 -4
  12. package/dist/lib/config/mapping-utils.d.ts +32 -0
  13. package/dist/lib/config/mapping-utils.js +68 -0
  14. package/dist/lib/config/match-mapping.d.ts +9 -0
  15. package/dist/lib/config/match-mapping.js +46 -0
  16. package/dist/lib/config/remove-unused-deps.d.ts +2 -1
  17. package/dist/lib/config/remove-unused-deps.js +35 -2
  18. package/dist/lib/config/validate-mappings.d.ts +15 -0
  19. package/dist/lib/config/validate-mappings.js +28 -0
  20. package/dist/lib/config/with-native-federation.js +18 -6
  21. package/dist/lib/core/build/bundle-exposed-and-mappings.js +21 -8
  22. package/dist/lib/core/build/bundle-shared.js +9 -3
  23. package/dist/lib/core/build/resolve-shared-dirs.d.ts +16 -0
  24. package/dist/lib/core/build/resolve-shared-dirs.js +8 -4
  25. package/dist/lib/core/cache/cache-persistence.d.ts +4 -2
  26. package/dist/lib/core/cache/cache-persistence.js +27 -8
  27. package/dist/lib/core/normalize-options.d.ts +2 -2
  28. package/dist/lib/core/normalize-options.js +15 -9
  29. package/dist/lib/domain/config/federation-config.contract.d.ts +27 -2
  30. package/dist/lib/domain/utils/file-watcher.contract.d.ts +12 -0
  31. package/dist/lib/domain/utils/io-port.contract.d.ts +6 -3
  32. package/dist/lib/utils/file-watcher.d.ts +15 -4
  33. package/dist/lib/utils/file-watcher.js +112 -19
  34. package/dist/lib/utils/io/node-io-adapter.js +10 -5
  35. package/dist/lib/utils/package/entry-point-resolver.js +2 -5
  36. package/dist/lib/utils/package/package-info.d.ts +13 -0
  37. package/dist/lib/utils/package/package-info.js +30 -4
  38. package/dist/lib/utils/package/resolve-wildcard-keys.js +8 -2
  39. package/dist/lib/utils/path-patterns.d.ts +14 -0
  40. package/dist/lib/utils/path-patterns.js +12 -0
  41. package/package.json +5 -5
@@ -43,7 +43,7 @@ const nodeIo = {
43
43
  stat(path2) {
44
44
  try {
45
45
  const s = fs.lstatSync(path2);
46
- return { mtimeMs: s.mtimeMs, isSymbolicLink: s.isSymbolicLink() };
46
+ return { mtimeMs: s.mtimeMs, size: s.size, isSymbolicLink: s.isSymbolicLink() };
47
47
  } catch {
48
48
  return null;
49
49
  }
@@ -61,7 +61,12 @@ const nodeIo = {
61
61
  fs.unlinkSync(path2);
62
62
  },
63
63
  globFiles(pattern, opts) {
64
- return fg.sync(pattern, { cwd: opts.cwd, onlyFiles: true, deep: Infinity });
64
+ return fg.sync(pattern, {
65
+ cwd: opts.cwd,
66
+ ignore: opts.ignore,
67
+ onlyFiles: true,
68
+ deep: Infinity
69
+ });
65
70
  },
66
71
  hash(algorithm, data) {
67
72
  const sum = crypto.createHash(algorithm).update(data);
@@ -72,11 +77,11 @@ const nodeIo = {
72
77
  },
73
78
  watch(watchPath, opts, onEvent) {
74
79
  if (opts.poll) return pollWatch(watchPath, opts.recursive, opts.poll.intervalMs, onEvent);
75
- const watcher = opts.recursive ? fs.watch(
80
+ const watcher = fs.watch(
76
81
  watchPath,
77
- { recursive: true },
82
+ { recursive: opts.recursive },
78
83
  (_event, filename) => onEvent(filename ? filename.toString() : null)
79
- ) : fs.watch(watchPath, () => onEvent(watchPath));
84
+ );
80
85
  return { close: () => watcher.close() };
81
86
  }
82
87
  };
@@ -44,7 +44,7 @@ function resolvePackageInfo(repo, packageName, directory) {
44
44
  const version = mainPkgJson["version"];
45
45
  const esm = mainPkgJson["type"] === "module";
46
46
  if (!version) {
47
- logger.warn("No version found for " + packageName);
47
+ logger.debug("No version found for " + packageName + " in " + directory);
48
48
  return null;
49
49
  }
50
50
  const pathToSecondary = path.relative(mainPkgName, packageName);
@@ -67,10 +67,7 @@ function resolvePackageInfo(repo, packageName, directory) {
67
67
  const result = strategy(ctx);
68
68
  if (result) return result;
69
69
  }
70
- logger.warn("No entry point found for " + packageName);
71
- logger.warn(
72
- "If you don't need this package, skip it in your federation.config.js or consider moving it into depDependencies in your package.json"
73
- );
70
+ logger.debug("No entry point found for " + packageName + " in " + directory);
74
71
  return null;
75
72
  }
76
73
  export {
@@ -2,6 +2,19 @@ import type { PackageInfo, PackageJsonRepository, VersionMap } from '../../domai
2
2
  export { sharedPackageJsonRepository } from '../io/package-json-repository.js';
3
3
  export type { PackageInfo, VersionMap, ExportCondition, ExportEntry, } from '../../domain/utils/package-json.contract.js';
4
4
  export { isESMExport } from './esm-detection.js';
5
+ export declare function tryGetPackageInfo(packageName: string, workspaceRoot: string, repo?: PackageJsonRepository): PackageInfo | null;
6
+ /**
7
+ * Resolve a package that is expected to be resolvable, warning once if it is not.
8
+ * Only use this where a failure is genuinely actionable, i.e. for packages the user
9
+ * asked to share.
10
+ */
5
11
  export declare function getPackageInfo(packageName: string, workspaceRoot: string, repo?: PackageJsonRepository): PackageInfo | null;
12
+ /**
13
+ * Installed version per key, from each key's package root. Resolution is deduped by root:
14
+ * `findDepPackageJson` trims to the root anyway, and that root package.json is also where
15
+ * `resolvePackageInfo` reads the `version` it records as `PackageInfo.version`, so a secondary
16
+ * yields the same string as its main entry point. Unresolvable keys map to ''.
17
+ */
18
+ export declare function installedVersions(packageNames: string[], workspaceRoot: string, repo?: PackageJsonRepository): Record<string, string>;
6
19
  export declare function getVersionMaps(project: string, workspace: string, repo?: PackageJsonRepository): VersionMap[];
7
20
  export declare function findDepPackageJson(packageName: string, projectRoot: string, repo?: PackageJsonRepository): string | null;
@@ -1,11 +1,11 @@
1
1
  import { logger } from "../logger.js";
2
2
  import { normalize } from "../normalize.js";
3
- import { sharedPackageJsonRepository } from "../io/package-json-repository.js";
3
+ import { getPkgFolder, sharedPackageJsonRepository } from "../io/package-json-repository.js";
4
4
  import { resolvePackageInfo } from "./entry-point-resolver.js";
5
5
  import { getVersionMaps as getVersionMapsFromRepo } from "./version-maps.js";
6
6
  import { sharedPackageJsonRepository as sharedPackageJsonRepository2 } from "../io/package-json-repository.js";
7
7
  import { isESMExport } from "./esm-detection.js";
8
- function getPackageInfo(packageName, workspaceRoot, repo = sharedPackageJsonRepository) {
8
+ function tryGetPackageInfo(packageName, workspaceRoot, repo = sharedPackageJsonRepository) {
9
9
  workspaceRoot = normalize(workspaceRoot, true);
10
10
  for (const info of repo.getPackageJsonFiles(workspaceRoot, workspaceRoot)) {
11
11
  const cand = resolvePackageInfo(repo, packageName, info.directory);
@@ -13,9 +13,33 @@ function getPackageInfo(packageName, workspaceRoot, repo = sharedPackageJsonRepo
13
13
  return cand;
14
14
  }
15
15
  }
16
- logger.warn("No meta data found for shared lib " + packageName);
17
16
  return null;
18
17
  }
18
+ function getPackageInfo(packageName, workspaceRoot, repo = sharedPackageJsonRepository) {
19
+ const info = tryGetPackageInfo(packageName, workspaceRoot, repo);
20
+ if (!info) {
21
+ logger.warn("No meta data found for shared lib " + packageName);
22
+ logger.warn(
23
+ "If you don't need this package, skip it in your federation.config.js or consider moving it into depDependencies in your package.json"
24
+ );
25
+ }
26
+ return info;
27
+ }
28
+ function installedVersions(packageNames, workspaceRoot, repo = sharedPackageJsonRepository) {
29
+ workspaceRoot = normalize(workspaceRoot, true);
30
+ const byRoot = /* @__PURE__ */ new Map();
31
+ const result = {};
32
+ for (const packageName of packageNames) {
33
+ const root = getPkgFolder(packageName);
34
+ if (!byRoot.has(root)) {
35
+ const pkgJsonPath = repo.findDepPackageJson(root, workspaceRoot);
36
+ const version = pkgJsonPath ? repo.readJson(pkgJsonPath)["version"] : "";
37
+ byRoot.set(root, version ?? "");
38
+ }
39
+ result[packageName] = byRoot.get(root);
40
+ }
41
+ return result;
42
+ }
19
43
  function getVersionMaps(project, workspace, repo = sharedPackageJsonRepository) {
20
44
  return getVersionMapsFromRepo(repo, project, workspace);
21
45
  }
@@ -26,6 +50,8 @@ export {
26
50
  findDepPackageJson,
27
51
  getPackageInfo,
28
52
  getVersionMaps,
53
+ installedVersions,
29
54
  isESMExport,
30
- sharedPackageJsonRepository2 as sharedPackageJsonRepository
55
+ sharedPackageJsonRepository2 as sharedPackageJsonRepository,
56
+ tryGetPackageInfo
31
57
  };
@@ -1,10 +1,16 @@
1
- import { captureWildcard, parseWildcard, substituteWildcard, toPosix } from "../path-patterns.js";
1
+ import {
2
+ captureWildcard,
3
+ parseWildcard,
4
+ substituteWildcard,
5
+ toGlobPattern,
6
+ toPosix
7
+ } from "../path-patterns.js";
2
8
  function resolvePackageJsonExportsWildcardCore(io, keyPattern, valuePattern, cwd) {
3
9
  const pattern = parseWildcard(valuePattern.replace(/^\.?\/+/, ""));
4
10
  if (!pattern.hasWildcard) {
5
11
  return [];
6
12
  }
7
- const files = io.globFiles(pattern.prefix + "**/*" + pattern.suffix, { cwd });
13
+ const files = io.globFiles(toGlobPattern(pattern), { cwd, ignore: ["**/node_modules/**"] });
8
14
  const keys = [];
9
15
  for (const file of files) {
10
16
  const relPath = toPosix(file).replace(/^\.\//, "");
@@ -1,4 +1,11 @@
1
1
  export declare const toPosix: (p: string) => string;
2
+ /**
3
+ * True when `file` is `dir` itself or lives under it. Both sides are normalized, so a
4
+ * caller cannot splice in `path.sep` and get a predicate that is silently always-false
5
+ * on Windows -- `linkedSharedDirs` and the file watcher both emit posix paths.
6
+ */
7
+ export declare function isUnderDir(file: string, dir: string): boolean;
8
+ export declare const isUnderAnyDir: (file: string, dirs: readonly string[]) => boolean;
2
9
  export interface WildcardPattern {
3
10
  prefix: string;
4
11
  suffix: string;
@@ -12,3 +19,10 @@ export declare function matchesWildcard(value: string, pattern: string): boolean
12
19
  */
13
20
  export declare function captureWildcard(value: string, pattern: WildcardPattern): string | null;
14
21
  export declare function substituteWildcard(template: string, captured: string): string;
22
+ /**
23
+ * A glob that is a superset of the pattern, for callers that re-check the match themselves
24
+ * (`captureWildcard`, `matchMapping`). `**` only acts as a globstar on a segment of its own,
25
+ * so a prefix stopping mid-segment (`libs/ui-`) has to be widened back to its directory --
26
+ * `libs/ui-**` reads as `libs/ui-*` and silently matches nothing one level down.
27
+ */
28
+ export declare function toGlobPattern({ prefix, suffix }: WildcardPattern): string;
@@ -1,4 +1,10 @@
1
1
  const toPosix = (p) => p.replace(/\\/g, "/");
2
+ function isUnderDir(file, dir) {
3
+ const f = toPosix(file);
4
+ const d = toPosix(dir).replace(/\/+$/, "");
5
+ return f === d || f.startsWith(d + "/");
6
+ }
7
+ const isUnderAnyDir = (file, dirs) => dirs.some((d) => isUnderDir(file, d));
2
8
  function parseWildcard(pattern) {
3
9
  const i = pattern.indexOf("*");
4
10
  if (i === -1) return { prefix: pattern, suffix: "", hasWildcard: false };
@@ -19,10 +25,16 @@ function captureWildcard(value, pattern) {
19
25
  function substituteWildcard(template, captured) {
20
26
  return template.replace("*", captured);
21
27
  }
28
+ function toGlobPattern({ prefix, suffix }) {
29
+ return prefix.slice(0, prefix.lastIndexOf("/") + 1) + "**/*" + suffix;
30
+ }
22
31
  export {
23
32
  captureWildcard,
33
+ isUnderAnyDir,
34
+ isUnderDir,
24
35
  matchesWildcard,
25
36
  parseWildcard,
26
37
  substituteWildcard,
38
+ toGlobPattern,
27
39
  toPosix
28
40
  };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@softarc/native-federation",
3
- "version": "4.3.2",
3
+ "version": "4.4.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
- "packageManager": "pnpm@11.11.0",
6
+ "packageManager": "pnpm@11.18.0",
7
7
  "scripts": {
8
8
  "build": "node esbuild.config.mjs && tsc -p tsconfig.build.json",
9
9
  "lint": "eslint src",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@softarc/sheriff-core": "^0.19.6",
16
- "chalk": "^5.6.2",
16
+ "chalk": "^6.0.0",
17
17
  "esbuild": "^0.28.0",
18
18
  "fast-glob": "^3.3.3",
19
19
  "json5": "^2.2.3"
@@ -27,12 +27,12 @@
27
27
  "globals": "^17.3.0",
28
28
  "jiti": "^2.6.1",
29
29
  "jsdom": "^29.0.0",
30
- "knip": "^6.20.0",
30
+ "knip": "^6.26.0",
31
31
  "prettier": "^3.9.4",
32
32
  "tslib": "^2.3.0",
33
33
  "typescript": "~6.0.0",
34
34
  "typescript-eslint": "^8.61.0",
35
- "vite": "^8.1.3",
35
+ "vite": "^8.2.0",
36
36
  "vitest": "^4.0.0"
37
37
  },
38
38
  "exports": {