@softarc/native-federation 4.1.2 → 4.2.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.
- package/LICENSE.md +7 -0
- package/README.md +638 -0
- package/dist/config.js +17 -0
- package/dist/domain.js +2 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +21 -0
- package/{src → dist}/internal.d.ts +6 -7
- package/dist/internal.js +26 -0
- package/dist/lib/config/configuration-context.js +15 -0
- package/dist/lib/config/default-skip-list.js +36 -0
- package/dist/lib/config/get-external-imports.d.ts +2 -0
- package/dist/lib/config/get-external-imports.js +60 -0
- package/dist/lib/config/get-used-dependencies.d.ts +24 -0
- package/dist/lib/config/get-used-dependencies.js +126 -0
- package/{src/lib/utils → dist/lib/config}/mapped-paths.d.ts +2 -2
- package/dist/lib/config/mapped-paths.js +31 -0
- package/dist/lib/config/remove-unused-deps.js +11 -0
- package/dist/lib/config/share-utils.d.ts +20 -0
- package/dist/lib/config/share-utils.js +344 -0
- package/dist/lib/config/with-native-federation.js +80 -0
- package/{src/lib/core → dist/lib/core/build}/build-adapter.d.ts +1 -1
- package/dist/lib/core/build/build-adapter.js +16 -0
- package/dist/lib/core/build/build-for-federation.d.ts +4 -0
- package/dist/lib/core/build/build-for-federation.js +207 -0
- package/{src/lib/utils → dist/lib/core/build}/build-result-map.d.ts +1 -1
- package/dist/lib/core/build/build-result-map.js +39 -0
- package/dist/lib/core/build/bundle-exposed-and-mappings.d.ts +13 -0
- package/dist/lib/core/build/bundle-exposed-and-mappings.js +178 -0
- package/dist/lib/core/build/bundle-shared.d.ts +34 -0
- package/dist/lib/core/build/bundle-shared.js +261 -0
- package/dist/lib/core/build/compute-integrity.d.ts +11 -0
- package/dist/lib/core/build/compute-integrity.js +20 -0
- package/dist/lib/core/build/default-external-list.js +32 -0
- package/dist/lib/core/build/get-externals.d.ts +2 -0
- package/dist/lib/core/build/get-externals.js +9 -0
- package/dist/lib/core/build/rebuild-for-federation.d.ts +4 -0
- package/dist/lib/core/build/rebuild-for-federation.js +52 -0
- package/dist/lib/core/build/rewrite-chunk-imports.d.ts +5 -0
- package/dist/lib/core/build/rewrite-chunk-imports.js +74 -0
- package/dist/lib/core/cache/cache-persistence.d.ts +22 -0
- package/dist/lib/core/cache/cache-persistence.js +63 -0
- package/{src/lib/core → dist/lib/core/cache}/federation-cache.d.ts +2 -2
- package/dist/lib/core/cache/federation-cache.js +22 -0
- package/dist/lib/core/federation-builder.js +53 -0
- package/{src → dist}/lib/core/normalize-options.d.ts +13 -1
- package/dist/lib/core/normalize-options.js +67 -0
- package/dist/lib/core/output/write-federation-info.d.ts +5 -0
- package/dist/lib/core/output/write-federation-info.js +17 -0
- package/dist/lib/core/output/write-import-map.d.ts +11 -0
- package/dist/lib/core/output/write-import-map.js +42 -0
- package/dist/lib/core/rebuild-queue.js +61 -0
- package/{src → dist}/lib/domain/config/external-config.contract.d.ts +2 -2
- package/dist/lib/domain/config/external-config.contract.js +0 -0
- package/{src → dist}/lib/domain/config/federation-config.contract.d.ts +6 -2
- package/dist/lib/domain/config/federation-config.contract.js +0 -0
- package/dist/lib/domain/config/index.js +0 -0
- package/dist/lib/domain/config/skip-list.contract.js +0 -0
- package/dist/lib/domain/core/build-adapter.contract.js +0 -0
- package/dist/lib/domain/core/build-notification-options.contract.js +9 -0
- package/dist/lib/domain/core/chunk.js +12 -0
- package/dist/lib/domain/core/federation-cache.contract.js +0 -0
- package/{src → dist}/lib/domain/core/federation-info.contract.d.ts +1 -0
- package/dist/lib/domain/core/federation-info.contract.js +0 -0
- package/dist/lib/domain/core/federation-options.contract.js +0 -0
- package/{src → dist}/lib/domain/core/index.d.ts +1 -0
- package/dist/lib/domain/core/index.js +9 -0
- package/dist/lib/domain/core/manifest.contract.d.ts +5 -0
- package/dist/lib/domain/core/manifest.contract.js +0 -0
- package/dist/lib/domain/utils/file-watcher.contract.js +0 -0
- package/dist/lib/domain/utils/io-port.contract.d.ts +45 -0
- package/dist/lib/domain/utils/io-port.contract.js +0 -0
- package/dist/lib/domain/utils/keyvaluepair.contract.js +0 -0
- package/dist/lib/domain/utils/mapped-path.contract.js +0 -0
- package/dist/lib/domain/utils/package-json.contract.d.ts +27 -0
- package/dist/lib/domain/utils/package-json.contract.js +0 -0
- package/dist/lib/domain/utils/used-dependencies.contract.js +0 -0
- package/dist/lib/utils/errors.js +10 -0
- package/{src → dist}/lib/utils/file-watcher.d.ts +2 -0
- package/dist/lib/utils/file-watcher.js +51 -0
- package/dist/lib/utils/hash-file.d.ts +7 -0
- package/dist/lib/utils/hash-file.js +15 -0
- package/dist/lib/utils/io/node-io-adapter.d.ts +2 -0
- package/dist/lib/utils/io/node-io-adapter.js +68 -0
- package/dist/lib/utils/io/package-json-repository.d.ts +5 -0
- package/dist/lib/utils/io/package-json-repository.js +79 -0
- package/dist/lib/utils/logger.js +29 -0
- package/dist/lib/utils/normalize.js +22 -0
- package/dist/lib/utils/package/entry-point-resolver.d.ts +2 -0
- package/dist/lib/utils/package/entry-point-resolver.js +78 -0
- package/dist/lib/utils/package/esm-detection.d.ts +5 -0
- package/dist/lib/utils/package/esm-detection.js +10 -0
- package/dist/lib/utils/package/exports-resolver.d.ts +13 -0
- package/dist/lib/utils/package/exports-resolver.js +55 -0
- package/dist/lib/utils/package/package-info.d.ts +7 -0
- package/dist/lib/utils/package/package-info.js +31 -0
- package/dist/lib/utils/package/resolve-wildcard-keys.d.ts +3 -0
- package/dist/lib/utils/package/resolve-wildcard-keys.js +22 -0
- package/dist/lib/utils/package/version-maps.d.ts +3 -0
- package/dist/lib/utils/package/version-maps.js +8 -0
- package/dist/lib/utils/path-patterns.d.ts +14 -0
- package/dist/lib/utils/path-patterns.js +28 -0
- package/package.json +45 -22
- package/src/config.js +0 -4
- package/src/domain.js +0 -2
- package/src/index.d.ts +0 -10
- package/src/index.js +0 -10
- package/src/internal.js +0 -11
- package/src/lib/config/configuration-context.js +0 -10
- package/src/lib/config/default-skip-list.js +0 -31
- package/src/lib/config/remove-unused-deps.js +0 -10
- package/src/lib/config/share-utils.d.ts +0 -10
- package/src/lib/config/share-utils.js +0 -302
- package/src/lib/config/with-native-federation.js +0 -71
- package/src/lib/core/build-adapter.js +0 -12
- package/src/lib/core/build-for-federation.d.ts +0 -4
- package/src/lib/core/build-for-federation.js +0 -173
- package/src/lib/core/bundle-exposed-and-mappings.d.ts +0 -7
- package/src/lib/core/bundle-exposed-and-mappings.js +0 -174
- package/src/lib/core/bundle-shared.d.ts +0 -13
- package/src/lib/core/bundle-shared.js +0 -222
- package/src/lib/core/default-external-list.js +0 -29
- package/src/lib/core/federation-builder.js +0 -45
- package/src/lib/core/federation-cache.js +0 -16
- package/src/lib/core/get-externals.d.ts +0 -2
- package/src/lib/core/get-externals.js +0 -6
- package/src/lib/core/normalize-options.js +0 -58
- package/src/lib/core/rebuild-for-federation.d.ts +0 -4
- package/src/lib/core/rebuild-for-federation.js +0 -43
- package/src/lib/core/write-federation-info.d.ts +0 -3
- package/src/lib/core/write-federation-info.js +0 -6
- package/src/lib/core/write-import-map.d.ts +0 -6
- package/src/lib/core/write-import-map.js +0 -33
- package/src/lib/domain/config/external-config.contract.js +0 -1
- package/src/lib/domain/config/federation-config.contract.js +0 -1
- package/src/lib/domain/config/index.js +0 -1
- package/src/lib/domain/config/skip-list.contract.js +0 -1
- package/src/lib/domain/config/with-native-federation.contract.d.ts +0 -2
- package/src/lib/domain/config/with-native-federation.contract.js +0 -1
- package/src/lib/domain/core/build-adapter.contract.js +0 -1
- package/src/lib/domain/core/build-notification-options.contract.js +0 -6
- package/src/lib/domain/core/chunk.js +0 -8
- package/src/lib/domain/core/federation-cache.contract.js +0 -1
- package/src/lib/domain/core/federation-info.contract.js +0 -1
- package/src/lib/domain/core/federation-options.contract.js +0 -1
- package/src/lib/domain/core/index.js +0 -2
- package/src/lib/domain/utils/file-watcher.contract.js +0 -1
- package/src/lib/domain/utils/index.d.ts +0 -2
- package/src/lib/domain/utils/index.js +0 -1
- package/src/lib/domain/utils/keyvaluepair.contract.js +0 -1
- package/src/lib/domain/utils/mapped-path.contract.js +0 -5
- package/src/lib/domain/utils/used-dependencies.contract.js +0 -1
- package/src/lib/utils/build-result-map.js +0 -29
- package/src/lib/utils/cache-persistence.d.ts +0 -19
- package/src/lib/utils/cache-persistence.js +0 -66
- package/src/lib/utils/errors.js +0 -7
- package/src/lib/utils/file-watcher.js +0 -51
- package/src/lib/utils/get-external-imports.d.ts +0 -1
- package/src/lib/utils/get-external-imports.js +0 -80
- package/src/lib/utils/get-used-dependencies.d.ts +0 -7
- package/src/lib/utils/get-used-dependencies.js +0 -123
- package/src/lib/utils/hash-file.d.ts +0 -3
- package/src/lib/utils/hash-file.js +0 -13
- package/src/lib/utils/logger.js +0 -27
- package/src/lib/utils/mapped-paths.js +0 -33
- package/src/lib/utils/normalize.js +0 -17
- package/src/lib/utils/package-info.d.ts +0 -30
- package/src/lib/utils/package-info.js +0 -268
- package/src/lib/utils/rebuild-queue.js +0 -63
- package/src/lib/utils/resolve-glob.d.ts +0 -1
- package/src/lib/utils/resolve-glob.js +0 -29
- package/src/lib/utils/resolve-wildcard-keys.d.ts +0 -29
- package/src/lib/utils/resolve-wildcard-keys.js +0 -126
- package/src/lib/utils/rewrite-chunk-imports.d.ts +0 -2
- package/src/lib/utils/rewrite-chunk-imports.js +0 -48
- /package/{src → dist}/config.d.ts +0 -0
- /package/{src → dist}/domain.d.ts +0 -0
- /package/{src → dist}/lib/config/configuration-context.d.ts +0 -0
- /package/{src → dist}/lib/config/default-skip-list.d.ts +0 -0
- /package/{src → dist}/lib/config/remove-unused-deps.d.ts +0 -0
- /package/{src → dist}/lib/config/with-native-federation.d.ts +0 -0
- /package/{src/lib/core → dist/lib/core/build}/default-external-list.d.ts +0 -0
- /package/{src → dist}/lib/core/federation-builder.d.ts +0 -0
- /package/{src/lib/utils → dist/lib/core}/rebuild-queue.d.ts +0 -0
- /package/{src → dist}/lib/domain/config/index.d.ts +0 -0
- /package/{src → dist}/lib/domain/config/skip-list.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/core/build-adapter.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/core/build-notification-options.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/core/chunk.d.ts +0 -0
- /package/{src → dist}/lib/domain/core/federation-cache.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/core/federation-options.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/utils/file-watcher.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/utils/keyvaluepair.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/utils/mapped-path.contract.d.ts +0 -0
- /package/{src → dist}/lib/domain/utils/used-dependencies.contract.d.ts +0 -0
- /package/{src → dist}/lib/utils/errors.d.ts +0 -0
- /package/{src → dist}/lib/utils/logger.d.ts +0 -0
- /package/{src → dist}/lib/utils/normalize.d.ts +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PackageInfo {
|
|
2
|
+
packageName: string;
|
|
3
|
+
entryPoint: string;
|
|
4
|
+
version: string;
|
|
5
|
+
esm: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface PartialPackageJson {
|
|
8
|
+
module: string;
|
|
9
|
+
main: string;
|
|
10
|
+
}
|
|
11
|
+
export type VersionMap = Record<string, string>;
|
|
12
|
+
export type PackageJsonInfo = {
|
|
13
|
+
content: any;
|
|
14
|
+
directory: string;
|
|
15
|
+
};
|
|
16
|
+
export interface PackageJsonRepository {
|
|
17
|
+
/** package.json files between `project` and `workspace`, nearest first. */
|
|
18
|
+
getPackageJsonFiles(project: string, workspace: string): PackageJsonInfo[];
|
|
19
|
+
/** Nearest `node_modules/<pkg>/package.json` walking up from `projectRoot`. */
|
|
20
|
+
findDepPackageJson(packageName: string, projectRoot: string): string | null;
|
|
21
|
+
readJson(filePath: string): any;
|
|
22
|
+
exists(filePath: string): boolean;
|
|
23
|
+
}
|
|
24
|
+
export type ExportCondition = 'import' | 'require' | 'node' | 'cjs' | 'esm' | 'default' | 'types' | 'browser' | (string & {});
|
|
25
|
+
export type ExportEntry = string | undefined | {
|
|
26
|
+
[key in ExportCondition]?: ExportEntry;
|
|
27
|
+
} | ExportEntry[];
|
|
File without changes
|
|
File without changes
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { WatchPort, FileReaderPort } from '../domain/utils/io-port.contract.js';
|
|
1
2
|
import type { NfFileWatcher, NfFileWatcherOptions } from '../domain/utils/file-watcher.contract.js';
|
|
2
3
|
export declare function createNfWatcher(options?: NfFileWatcherOptions): NfFileWatcher;
|
|
4
|
+
export declare function createNfWatcherCore(io: WatchPort & FileReaderPort, options?: NfFileWatcherOptions): NfFileWatcher;
|
|
3
5
|
export declare function syncNfFileWatcher(watcher: NfFileWatcher, bundlerCache: {
|
|
4
6
|
keys(): IterableIterator<string>;
|
|
5
7
|
}): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { nodeIo } from "./io/node-io-adapter.js";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
4
|
+
import { toPosix } from "./path-patterns.js";
|
|
5
|
+
function createNfWatcher(options = {}) {
|
|
6
|
+
return createNfWatcherCore(nodeIo, options);
|
|
7
|
+
}
|
|
8
|
+
function createNfWatcherCore(io, options = {}) {
|
|
9
|
+
const { onChange } = options;
|
|
10
|
+
const watchers = /* @__PURE__ */ new Map();
|
|
11
|
+
const dirtyPaths = /* @__PURE__ */ new Set();
|
|
12
|
+
const notify = (path) => {
|
|
13
|
+
if (onChange) onChange(path);
|
|
14
|
+
else dirtyPaths.add(path);
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
addPaths(paths) {
|
|
18
|
+
const list = typeof paths === "string" ? [paths] : [...paths];
|
|
19
|
+
for (const p of list) {
|
|
20
|
+
if (watchers.has(p)) continue;
|
|
21
|
+
try {
|
|
22
|
+
const isDir = io.isDirectory(p);
|
|
23
|
+
const handle = isDir ? io.watch(p, { recursive: true }, (filename) => {
|
|
24
|
+
if (filename) notify(toPosix(join(p, filename)));
|
|
25
|
+
}) : io.watch(p, { recursive: false }, () => notify(toPosix(p)));
|
|
26
|
+
watchers.set(p, handle);
|
|
27
|
+
} catch {
|
|
28
|
+
logger.debug(`Could not watch path '${p}'.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
get: () => dirtyPaths,
|
|
33
|
+
clear: () => dirtyPaths.clear(),
|
|
34
|
+
mutate: (fn) => fn(dirtyPaths),
|
|
35
|
+
async close() {
|
|
36
|
+
for (const handle of watchers.values()) {
|
|
37
|
+
handle.close();
|
|
38
|
+
}
|
|
39
|
+
watchers.clear();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function syncNfFileWatcher(watcher, bundlerCache) {
|
|
44
|
+
const files = [...bundlerCache.keys()].filter((k) => !k.includes("node_modules"));
|
|
45
|
+
if (files.length) watcher.addPaths(files);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
createNfWatcher,
|
|
49
|
+
createNfWatcherCore,
|
|
50
|
+
syncNfFileWatcher
|
|
51
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FileReaderPort, HashPort } from '../domain/utils/io-port.contract.js';
|
|
2
|
+
export type SriAlgorithm = 'sha256' | 'sha384' | 'sha512';
|
|
3
|
+
type HashDeps = FileReaderPort & HashPort;
|
|
4
|
+
export declare function hashFile(fileName: string): string;
|
|
5
|
+
export declare function hashFileCore(io: HashDeps, fileName: string): string;
|
|
6
|
+
export declare function integrityForFileCore(io: HashDeps, fileName: string, algorithm?: SriAlgorithm): string;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { nodeIo } from "./io/node-io-adapter.js";
|
|
2
|
+
function hashFile(fileName) {
|
|
3
|
+
return hashFileCore(nodeIo, fileName);
|
|
4
|
+
}
|
|
5
|
+
function hashFileCore(io, fileName) {
|
|
6
|
+
return io.hash("md5", io.readBytes(fileName)).hex();
|
|
7
|
+
}
|
|
8
|
+
function integrityForFileCore(io, fileName, algorithm = "sha384") {
|
|
9
|
+
return `${algorithm}-${io.hash(algorithm, io.readBytes(fileName)).base64()}`;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
hashFile,
|
|
13
|
+
hashFileCore,
|
|
14
|
+
integrityForFileCore
|
|
15
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as crypto from "crypto";
|
|
3
|
+
import fg from "fast-glob";
|
|
4
|
+
const nodeIo = {
|
|
5
|
+
readText(path) {
|
|
6
|
+
return fs.readFileSync(path, "utf-8");
|
|
7
|
+
},
|
|
8
|
+
readBytes(path) {
|
|
9
|
+
return fs.readFileSync(path);
|
|
10
|
+
},
|
|
11
|
+
exists(path) {
|
|
12
|
+
return fs.existsSync(path);
|
|
13
|
+
},
|
|
14
|
+
isFile(path) {
|
|
15
|
+
try {
|
|
16
|
+
return fs.statSync(path).isFile();
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
isDirectory(path) {
|
|
22
|
+
try {
|
|
23
|
+
return fs.statSync(path).isDirectory();
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
readDir(path) {
|
|
29
|
+
try {
|
|
30
|
+
return fs.readdirSync(path);
|
|
31
|
+
} catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
writeText(path, data) {
|
|
36
|
+
fs.writeFileSync(path, data, "utf-8");
|
|
37
|
+
},
|
|
38
|
+
mkdirp(path) {
|
|
39
|
+
fs.mkdirSync(path, { recursive: true });
|
|
40
|
+
},
|
|
41
|
+
copyFile(from, to) {
|
|
42
|
+
fs.copyFileSync(from, to);
|
|
43
|
+
},
|
|
44
|
+
remove(path) {
|
|
45
|
+
fs.unlinkSync(path);
|
|
46
|
+
},
|
|
47
|
+
globFiles(pattern, opts) {
|
|
48
|
+
return fg.sync(pattern, { cwd: opts.cwd, onlyFiles: true, deep: Infinity });
|
|
49
|
+
},
|
|
50
|
+
hash(algorithm, data) {
|
|
51
|
+
const sum = crypto.createHash(algorithm).update(data);
|
|
52
|
+
return {
|
|
53
|
+
hex: () => sum.digest("hex"),
|
|
54
|
+
base64: () => sum.digest("base64")
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
watch(path, opts, onEvent) {
|
|
58
|
+
const watcher = opts.recursive ? fs.watch(
|
|
59
|
+
path,
|
|
60
|
+
{ recursive: true },
|
|
61
|
+
(_event, filename) => onEvent(filename ? filename.toString() : null)
|
|
62
|
+
) : fs.watch(path, () => onEvent(path));
|
|
63
|
+
return { close: () => watcher.close() };
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
export {
|
|
67
|
+
nodeIo
|
|
68
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FileReaderPort } from '../../domain/utils/io-port.contract.js';
|
|
2
|
+
import type { PackageJsonRepository } from '../../domain/utils/package-json.contract.js';
|
|
3
|
+
export declare function getPkgFolder(packageName: string): string;
|
|
4
|
+
export declare function createPackageJsonRepository(io?: FileReaderPort): PackageJsonRepository;
|
|
5
|
+
export declare const sharedPackageJsonRepository: PackageJsonRepository;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { nodeIo } from "./node-io-adapter.js";
|
|
3
|
+
import { normalize } from "../normalize.js";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
function getPkgFolder(packageName) {
|
|
6
|
+
const parts = packageName.split("/");
|
|
7
|
+
let folder = parts[0];
|
|
8
|
+
if (folder.startsWith("@")) {
|
|
9
|
+
folder += "/" + parts[1];
|
|
10
|
+
}
|
|
11
|
+
return folder;
|
|
12
|
+
}
|
|
13
|
+
function createPackageJsonRepository(io = nodeIo) {
|
|
14
|
+
const cache = /* @__PURE__ */ new Map();
|
|
15
|
+
const readJson = (filePath) => JSON.parse(io.readText(filePath));
|
|
16
|
+
function expandFolders(child, parent) {
|
|
17
|
+
const result = [];
|
|
18
|
+
parent = normalize(parent, true);
|
|
19
|
+
child = normalize(child, true);
|
|
20
|
+
if (!child.startsWith(parent)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Workspace folder ${parent} needs to be a parent of the project folder ${child}`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
let current = child;
|
|
26
|
+
while (current !== parent) {
|
|
27
|
+
result.push(current);
|
|
28
|
+
const cand = normalize(path.dirname(current), true);
|
|
29
|
+
if (cand === current) break;
|
|
30
|
+
current = cand;
|
|
31
|
+
}
|
|
32
|
+
result.push(parent);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function findPackageJsonFiles(project, workspace) {
|
|
36
|
+
return expandFolders(project, workspace).map((f) => path.join(f, "package.json")).filter((f) => io.exists(f));
|
|
37
|
+
}
|
|
38
|
+
function getPackageJsonFiles(project, workspace) {
|
|
39
|
+
const cacheKey = `${project}**${workspace}`;
|
|
40
|
+
const cached = cache.get(cacheKey);
|
|
41
|
+
if (cached) return cached;
|
|
42
|
+
const maps = findPackageJsonFiles(project, workspace).map((f) => ({
|
|
43
|
+
content: readJson(f),
|
|
44
|
+
directory: normalize(path.dirname(f), true)
|
|
45
|
+
}));
|
|
46
|
+
cache.set(cacheKey, maps);
|
|
47
|
+
return maps;
|
|
48
|
+
}
|
|
49
|
+
function findDepPackageJson(packageName, projectRoot) {
|
|
50
|
+
const mainPkgName = getPkgFolder(packageName);
|
|
51
|
+
if (!mainPkgName) throw new Error(`Package.json "${packageName}" is missing`);
|
|
52
|
+
let directory = projectRoot;
|
|
53
|
+
let mainPkgJsonPath = path.join(directory, "node_modules", mainPkgName, "package.json");
|
|
54
|
+
while (path.dirname(directory) !== directory) {
|
|
55
|
+
if (io.exists(mainPkgJsonPath)) break;
|
|
56
|
+
directory = normalize(path.dirname(directory), true);
|
|
57
|
+
mainPkgJsonPath = path.join(directory, "node_modules", mainPkgName, "package.json");
|
|
58
|
+
}
|
|
59
|
+
if (!io.exists(mainPkgJsonPath)) {
|
|
60
|
+
logger.verbose(
|
|
61
|
+
"No package.json found for " + packageName + " in " + path.dirname(mainPkgJsonPath)
|
|
62
|
+
);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return mainPkgJsonPath;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
getPackageJsonFiles,
|
|
69
|
+
findDepPackageJson,
|
|
70
|
+
readJson,
|
|
71
|
+
exists: (filePath) => io.exists(filePath)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const sharedPackageJsonRepository = createPackageJsonRepository();
|
|
75
|
+
export {
|
|
76
|
+
createPackageJsonRepository,
|
|
77
|
+
getPkgFolder,
|
|
78
|
+
sharedPackageJsonRepository
|
|
79
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
let verbose = false;
|
|
3
|
+
const debug = (msg) => verbose && console.log(chalk.bgGreen.ansi256(15)(" DBG! "), msg);
|
|
4
|
+
const logger = {
|
|
5
|
+
warn: (msg) => console.warn(chalk.bgYellow.ansi256(15)(" WARN "), msg),
|
|
6
|
+
error: (msg) => console.error(chalk.bgRed.ansi256(15)(" ERRR "), msg),
|
|
7
|
+
notice: (msg) => console.log(chalk.bgYellowBright.black(" NOTE "), msg),
|
|
8
|
+
info: (msg) => console.log(chalk.bgGreen.ansi256(15)(" INFO "), msg),
|
|
9
|
+
verbose: debug,
|
|
10
|
+
// public alias, kept for backwards compatibility
|
|
11
|
+
debug,
|
|
12
|
+
measure: (start, milestone) => {
|
|
13
|
+
if (!verbose) return;
|
|
14
|
+
const [totalSeconds, nanoseconds] = process.hrtime(start);
|
|
15
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
16
|
+
const seconds = totalSeconds % 60;
|
|
17
|
+
const milliseconds = nanoseconds / 1e6;
|
|
18
|
+
const msFormatted = milliseconds.toFixed(3);
|
|
19
|
+
const timeStr = `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}:${msFormatted.padStart(7, "0")}ms`;
|
|
20
|
+
console.log(chalk.bgGreen.ansi256(15)(" DBG! "), `${timeStr} - ${milestone}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const setLogLevel = (level) => {
|
|
24
|
+
verbose = level === "verbose";
|
|
25
|
+
};
|
|
26
|
+
export {
|
|
27
|
+
logger,
|
|
28
|
+
setLogLevel
|
|
29
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { toPosix } from "./path-patterns.js";
|
|
2
|
+
function normalize(path, trailingSlash) {
|
|
3
|
+
let cand = toPosix(path);
|
|
4
|
+
if (typeof trailingSlash === "undefined") {
|
|
5
|
+
return cand;
|
|
6
|
+
}
|
|
7
|
+
while (cand.endsWith("/")) {
|
|
8
|
+
cand = cand.substring(0, cand.length - 1);
|
|
9
|
+
}
|
|
10
|
+
if (trailingSlash) {
|
|
11
|
+
return cand + "/";
|
|
12
|
+
}
|
|
13
|
+
return cand;
|
|
14
|
+
}
|
|
15
|
+
function normalizePackageName(fileName) {
|
|
16
|
+
const sanitized = fileName.replace(/[^A-Za-z0-9]/g, "_");
|
|
17
|
+
return sanitized.startsWith("_") ? sanitized.slice(1) : sanitized;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
normalize,
|
|
21
|
+
normalizePackageName
|
|
22
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { logger } from "../logger.js";
|
|
3
|
+
import { findOptimalExport, resolveExportsEntry } from "./exports-resolver.js";
|
|
4
|
+
import { getPkgFolder } from "../io/package-json-repository.js";
|
|
5
|
+
const base = (ctx, entryPoint, esm) => ({
|
|
6
|
+
entryPoint,
|
|
7
|
+
packageName: ctx.packageName,
|
|
8
|
+
version: ctx.version,
|
|
9
|
+
esm
|
|
10
|
+
});
|
|
11
|
+
const STRATEGIES = [
|
|
12
|
+
(ctx) => {
|
|
13
|
+
const entry = resolveExportsEntry(ctx.mainPkgJson?.exports, ctx.relSecondaryPath);
|
|
14
|
+
if (!entry) return null;
|
|
15
|
+
return findOptimalExport(entry, base(ctx, ctx.mainPkgPath, ctx.esm)) ?? null;
|
|
16
|
+
},
|
|
17
|
+
(ctx) => ctx.mainPkgJson["module"] && ctx.relSecondaryPath === "." ? base(ctx, path.join(ctx.mainPkgPath, ctx.mainPkgJson["module"]), true) : null,
|
|
18
|
+
(ctx) => ctx.secondaryPkgJson?.module ? base(ctx, path.join(ctx.secondaryPkgPath, ctx.secondaryPkgJson.module), true) : null,
|
|
19
|
+
(ctx) => {
|
|
20
|
+
const cand = path.join(ctx.secondaryPkgPath, "index.mjs");
|
|
21
|
+
return ctx.repo.exists(cand) ? base(ctx, cand, true) : null;
|
|
22
|
+
},
|
|
23
|
+
(ctx) => ctx.secondaryPkgJson?.main ? base(ctx, path.join(ctx.secondaryPkgPath, ctx.secondaryPkgJson.main), ctx.esm) : null,
|
|
24
|
+
(ctx) => {
|
|
25
|
+
const cand = path.join(ctx.secondaryPkgPath, "index.js");
|
|
26
|
+
return ctx.repo.exists(cand) ? base(ctx, cand, ctx.esm) : null;
|
|
27
|
+
},
|
|
28
|
+
(ctx) => {
|
|
29
|
+
const cand = ctx.secondaryPkgPath + ".js";
|
|
30
|
+
return ctx.repo.exists(cand) ? base(ctx, cand, ctx.esm) : null;
|
|
31
|
+
},
|
|
32
|
+
(ctx) => {
|
|
33
|
+
const cand = ctx.secondaryPkgPath + ".mjs";
|
|
34
|
+
return ctx.repo.exists(cand) ? base(ctx, cand, ctx.esm) : null;
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
function resolvePackageInfo(repo, packageName, directory) {
|
|
38
|
+
const mainPkgName = getPkgFolder(packageName);
|
|
39
|
+
if (!mainPkgName) throw new Error(`Could not resolve "${packageName}" in "${directory}`);
|
|
40
|
+
const mainPkgJsonPath = repo.findDepPackageJson(packageName, directory);
|
|
41
|
+
if (!mainPkgJsonPath) return null;
|
|
42
|
+
const mainPkgPath = path.dirname(mainPkgJsonPath);
|
|
43
|
+
const mainPkgJson = repo.readJson(mainPkgJsonPath);
|
|
44
|
+
const version = mainPkgJson["version"];
|
|
45
|
+
const esm = mainPkgJson["type"] === "module";
|
|
46
|
+
if (!version) {
|
|
47
|
+
logger.warn("No version found for " + packageName);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const pathToSecondary = path.relative(mainPkgName, packageName);
|
|
51
|
+
const relSecondaryPath = !pathToSecondary ? "." : "./" + pathToSecondary.replace(/\\/g, "/");
|
|
52
|
+
const secondaryPkgPath = path.join(mainPkgPath, relSecondaryPath);
|
|
53
|
+
const secondaryPkgJsonPath = path.join(secondaryPkgPath, "package.json");
|
|
54
|
+
const secondaryPkgJson = repo.exists(secondaryPkgJsonPath) ? repo.readJson(secondaryPkgJsonPath) : null;
|
|
55
|
+
const ctx = {
|
|
56
|
+
packageName,
|
|
57
|
+
version,
|
|
58
|
+
esm,
|
|
59
|
+
mainPkgPath,
|
|
60
|
+
mainPkgJson,
|
|
61
|
+
relSecondaryPath,
|
|
62
|
+
secondaryPkgPath,
|
|
63
|
+
secondaryPkgJson,
|
|
64
|
+
repo
|
|
65
|
+
};
|
|
66
|
+
for (const strategy of STRATEGIES) {
|
|
67
|
+
const result = strategy(ctx);
|
|
68
|
+
if (result) return result;
|
|
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
|
+
);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
resolvePackageInfo
|
|
78
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const isESMExport = (e) => {
|
|
2
|
+
if (e === "import" || e === "module-sync") return true;
|
|
3
|
+
if (e === "module" || e === "esm" || /^es20\d{2}$/.test(e)) return true;
|
|
4
|
+
if (e === "require") return false;
|
|
5
|
+
if (e === "cjs" || e === "commonjs") return false;
|
|
6
|
+
return void 0;
|
|
7
|
+
};
|
|
8
|
+
export {
|
|
9
|
+
isESMExport
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ExportEntry, PackageInfo } from '../../domain/utils/package-json.contract.js';
|
|
2
|
+
export declare function replaceGlob(target: ExportEntry, replacement: string): ExportEntry;
|
|
3
|
+
/**
|
|
4
|
+
* Walk an `exports` entry (string, conditions object, or array) to the single
|
|
5
|
+
* best target, preferring ESM. Returns a {@link PackageInfo} with `entryPoint`
|
|
6
|
+
* resolved relative to `info.entryPoint`, or `undefined` when nothing resolves.
|
|
7
|
+
*/
|
|
8
|
+
export declare function findOptimalExport(target: ExportEntry, info: PackageInfo, isESM?: boolean | undefined): PackageInfo | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Find the `exports` field entry matching a secondary subpath (e.g. `./sub`),
|
|
11
|
+
* expanding subpath-pattern (`*`) entries. Returns `undefined` when no key matches.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveExportsEntry(exports: Record<string, ExportEntry> | undefined, relSecondaryPath: string): ExportEntry;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { isESMExport } from "./esm-detection.js";
|
|
3
|
+
function replaceGlob(target, replacement) {
|
|
4
|
+
if (!target) return void 0;
|
|
5
|
+
if (typeof target === "string") return target.replace("*", replacement);
|
|
6
|
+
return Object.entries(target).reduce(
|
|
7
|
+
(a, [k, v]) => ({
|
|
8
|
+
...a,
|
|
9
|
+
[k]: replaceGlob(v, replacement)
|
|
10
|
+
}),
|
|
11
|
+
{}
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
function findOptimalExport(target, info, isESM = void 0) {
|
|
15
|
+
if (typeof target === "string") {
|
|
16
|
+
return {
|
|
17
|
+
...info,
|
|
18
|
+
entryPoint: path.join(info.entryPoint, target),
|
|
19
|
+
esm: isESM ?? info.esm
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (!target) return void 0;
|
|
23
|
+
if (Array.isArray(target)) return findOptimalExport(target[0], info, isESM);
|
|
24
|
+
const exportTypes = Object.keys(target);
|
|
25
|
+
if (typeof isESM === "undefined") {
|
|
26
|
+
const esmExport = exportTypes.find((e) => isESMExport(e));
|
|
27
|
+
if (esmExport) {
|
|
28
|
+
return findOptimalExport(target[esmExport], info, true);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const secondBestEntry = "default" in target && target["default"] ? "default" : exportTypes.filter((e) => e !== "types")[0];
|
|
32
|
+
const secondBestExport = target[secondBestEntry];
|
|
33
|
+
return findOptimalExport(secondBestExport, info, isESM ?? isESMExport(secondBestEntry));
|
|
34
|
+
}
|
|
35
|
+
function resolveExportsEntry(exports, relSecondaryPath) {
|
|
36
|
+
const exportsKey = Object.keys(exports ?? {}).find((e) => {
|
|
37
|
+
if (e === relSecondaryPath) return true;
|
|
38
|
+
if (e === "./*") return true;
|
|
39
|
+
if (!e.endsWith("*")) return false;
|
|
40
|
+
const globPath = e.substring(0, e.length - 1);
|
|
41
|
+
return relSecondaryPath.startsWith(globPath);
|
|
42
|
+
});
|
|
43
|
+
if (!exportsKey || !exports) return void 0;
|
|
44
|
+
let entry = exports[exportsKey];
|
|
45
|
+
if (exportsKey.endsWith("*")) {
|
|
46
|
+
const replacement = relSecondaryPath.substring(exportsKey.length - 1);
|
|
47
|
+
entry = replaceGlob(entry, replacement);
|
|
48
|
+
}
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
findOptimalExport,
|
|
53
|
+
replaceGlob,
|
|
54
|
+
resolveExportsEntry
|
|
55
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PackageInfo, PackageJsonRepository, VersionMap } from '../../domain/utils/package-json.contract.js';
|
|
2
|
+
export { sharedPackageJsonRepository } from '../io/package-json-repository.js';
|
|
3
|
+
export type { PackageInfo, VersionMap, ExportCondition, ExportEntry, } from '../../domain/utils/package-json.contract.js';
|
|
4
|
+
export { isESMExport } from './esm-detection.js';
|
|
5
|
+
export declare function getPackageInfo(packageName: string, workspaceRoot: string, repo?: PackageJsonRepository): PackageInfo | null;
|
|
6
|
+
export declare function getVersionMaps(project: string, workspace: string, repo?: PackageJsonRepository): VersionMap[];
|
|
7
|
+
export declare function findDepPackageJson(packageName: string, projectRoot: string, repo?: PackageJsonRepository): string | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { logger } from "../logger.js";
|
|
2
|
+
import { normalize } from "../normalize.js";
|
|
3
|
+
import { sharedPackageJsonRepository } from "../io/package-json-repository.js";
|
|
4
|
+
import { resolvePackageInfo } from "./entry-point-resolver.js";
|
|
5
|
+
import { getVersionMaps as getVersionMapsFromRepo } from "./version-maps.js";
|
|
6
|
+
import { sharedPackageJsonRepository as sharedPackageJsonRepository2 } from "../io/package-json-repository.js";
|
|
7
|
+
import { isESMExport } from "./esm-detection.js";
|
|
8
|
+
function getPackageInfo(packageName, workspaceRoot, repo = sharedPackageJsonRepository) {
|
|
9
|
+
workspaceRoot = normalize(workspaceRoot, true);
|
|
10
|
+
for (const info of repo.getPackageJsonFiles(workspaceRoot, workspaceRoot)) {
|
|
11
|
+
const cand = resolvePackageInfo(repo, packageName, info.directory);
|
|
12
|
+
if (cand) {
|
|
13
|
+
return cand;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
logger.warn("No meta data found for shared lib " + packageName);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function getVersionMaps(project, workspace, repo = sharedPackageJsonRepository) {
|
|
20
|
+
return getVersionMapsFromRepo(repo, project, workspace);
|
|
21
|
+
}
|
|
22
|
+
function findDepPackageJson(packageName, projectRoot, repo = sharedPackageJsonRepository) {
|
|
23
|
+
return repo.findDepPackageJson(packageName, projectRoot);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
findDepPackageJson,
|
|
27
|
+
getPackageInfo,
|
|
28
|
+
getVersionMaps,
|
|
29
|
+
isESMExport,
|
|
30
|
+
sharedPackageJsonRepository2 as sharedPackageJsonRepository
|
|
31
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { GlobPort } from '../../domain/utils/io-port.contract.js';
|
|
2
|
+
import type { KeyValuePair } from '../../domain/utils/keyvaluepair.contract.js';
|
|
3
|
+
export declare function resolvePackageJsonExportsWildcardCore(io: GlobPort, keyPattern: string, valuePattern: string, cwd: string): KeyValuePair[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { captureWildcard, parseWildcard, substituteWildcard, toPosix } from "../path-patterns.js";
|
|
2
|
+
function resolvePackageJsonExportsWildcardCore(io, keyPattern, valuePattern, cwd) {
|
|
3
|
+
const pattern = parseWildcard(valuePattern.replace(/^\.?\/+/, ""));
|
|
4
|
+
if (!pattern.hasWildcard) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
const files = io.globFiles(pattern.prefix + "**/*" + pattern.suffix, { cwd });
|
|
8
|
+
const keys = [];
|
|
9
|
+
for (const file of files) {
|
|
10
|
+
const relPath = toPosix(file).replace(/^\.\//, "");
|
|
11
|
+
const captured = captureWildcard(relPath, pattern);
|
|
12
|
+
if (captured === null) continue;
|
|
13
|
+
keys.push({
|
|
14
|
+
key: substituteWildcard(keyPattern, captured),
|
|
15
|
+
value: relPath
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return keys;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
resolvePackageJsonExportsWildcardCore
|
|
22
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PackageJsonRepository, VersionMap } from '../../domain/utils/package-json.contract.js';
|
|
2
|
+
/** Extract a `{ name: version }` map from every package.json's `dependencies`. */
|
|
3
|
+
export declare function getVersionMaps(repo: PackageJsonRepository, project: string, workspace: string): VersionMap[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const toPosix: (p: string) => string;
|
|
2
|
+
export interface WildcardPattern {
|
|
3
|
+
prefix: string;
|
|
4
|
+
suffix: string;
|
|
5
|
+
hasWildcard: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseWildcard(pattern: string): WildcardPattern;
|
|
8
|
+
export declare function matchesWildcard(value: string, pattern: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* End-anchored capture of the substring matched by `*` (which may span path
|
|
11
|
+
* separators). Returns `null` when `value` does not fit the pattern.
|
|
12
|
+
*/
|
|
13
|
+
export declare function captureWildcard(value: string, pattern: WildcardPattern): string | null;
|
|
14
|
+
export declare function substituteWildcard(template: string, captured: string): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
2
|
+
function parseWildcard(pattern) {
|
|
3
|
+
const i = pattern.indexOf("*");
|
|
4
|
+
if (i === -1) return { prefix: pattern, suffix: "", hasWildcard: false };
|
|
5
|
+
return { prefix: pattern.slice(0, i), suffix: pattern.slice(i + 1), hasWildcard: true };
|
|
6
|
+
}
|
|
7
|
+
function matchesWildcard(value, pattern) {
|
|
8
|
+
const { prefix, suffix, hasWildcard } = parseWildcard(pattern);
|
|
9
|
+
if (!hasWildcard) return value === pattern;
|
|
10
|
+
return value.startsWith(prefix) && (suffix === "" || value.endsWith(suffix));
|
|
11
|
+
}
|
|
12
|
+
function captureWildcard(value, pattern) {
|
|
13
|
+
const { prefix, suffix, hasWildcard } = pattern;
|
|
14
|
+
if (!hasWildcard) return value === prefix ? "" : null;
|
|
15
|
+
if (!value.startsWith(prefix)) return null;
|
|
16
|
+
if (suffix && !value.endsWith(suffix)) return null;
|
|
17
|
+
return suffix ? value.slice(prefix.length, value.length - suffix.length) : value.slice(prefix.length);
|
|
18
|
+
}
|
|
19
|
+
function substituteWildcard(template, captured) {
|
|
20
|
+
return template.replace("*", captured);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
captureWildcard,
|
|
24
|
+
matchesWildcard,
|
|
25
|
+
parseWildcard,
|
|
26
|
+
substituteWildcard,
|
|
27
|
+
toPosix
|
|
28
|
+
};
|