@esmx/core 3.0.0-rc.69 → 3.0.0-rc.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.
@@ -22,7 +22,7 @@ export interface GetImportMapOptions {
22
22
  getFile: (name: string, file: string) => string;
23
23
  }
24
24
 
25
- export function buildImportsMap(
25
+ export function createImportsMap(
26
26
  manifests: readonly ImportMapManifest[],
27
27
  getFile: (name: string, file: string) => string
28
28
  ): SpecifierMap {
@@ -40,7 +40,7 @@ export function buildImportsMap(
40
40
  return imports;
41
41
  }
42
42
 
43
- export function buildScopesMap(
43
+ export function createScopesMap(
44
44
  imports: SpecifierMap,
45
45
  manifests: readonly ImportMapManifest[],
46
46
  getScope: (name: string, scope: string) => string
@@ -73,18 +73,19 @@ export function buildScopesMap(
73
73
  return scopes;
74
74
  }
75
75
  /**
76
- * Fixes Chrome's nested scope resolution bug in import maps.
76
+ * Fixes the nested scope resolution issue in import maps across all browsers.
77
77
  *
78
- * Chrome has a bug where nested scopes in import maps are not resolved correctly.
78
+ * Import Maps have a cross-browser issue where nested scopes are not resolved correctly.
79
79
  * For example, when you have both "/shared-modules/" and "/shared-modules/vue2/" scopes,
80
- * Chrome fails to properly apply the more specific nested scope.
80
+ * browsers fail to properly apply the more specific nested scope.
81
81
  *
82
- * This function works around the bug by:
82
+ * This function works around the issue by:
83
83
  * 1. Sorting scopes by path depth (shallow paths first, deeper paths last)
84
84
  * 2. Manually applying scopes to matching imports in the correct order
85
+ * 3. Converting pattern-based scopes to concrete path scopes
85
86
  *
86
87
  * @example
87
- * Problematic import map that fails in Chrome:
88
+ * Problematic import map that fails in browsers:
88
89
  * ```json
89
90
  * {
90
91
  * "scopes": {
@@ -101,7 +102,7 @@ export function buildScopesMap(
101
102
  * @see https://github.com/guybedford/es-module-shims/issues/529
102
103
  * @see https://issues.chromium.org/issues/453147451
103
104
  */
104
- export function fixNestedScopesResolution(
105
+ export function fixImportMapNestedScopes(
105
106
  importMap: Required<ImportMap>
106
107
  ): Required<ImportMap> {
107
108
  Object.entries(importMap.scopes)
@@ -125,16 +126,77 @@ export function fixNestedScopesResolution(
125
126
  return importMap;
126
127
  }
127
128
 
128
- export function getImportMap({
129
+ export function compressImportMap(importMap: Required<ImportMap>): ImportMap {
130
+ const compressed: Required<ImportMap> = {
131
+ imports: { ...importMap.imports },
132
+ scopes: {}
133
+ };
134
+
135
+ const counts: Record<string, Record<string, number>> = {};
136
+ Object.values(importMap.scopes).forEach((scopeMappings) => {
137
+ Object.entries(scopeMappings).forEach(([specifier, target]) => {
138
+ if (Object.hasOwn(importMap.imports, specifier)) return;
139
+ counts[specifier] ??= {};
140
+ counts[specifier][target] = (counts[specifier][target] ?? 0) + 1;
141
+ });
142
+ });
143
+
144
+ Object.entries(counts).forEach(([specifier, targetCounts]) => {
145
+ const entries = Object.entries(targetCounts);
146
+
147
+ let best: [string, number] | null = null;
148
+ let secondBestCount = 0;
149
+ for (const [t, c] of entries) {
150
+ if (!best || c > best[1]) {
151
+ secondBestCount = best
152
+ ? Math.max(secondBestCount, best[1])
153
+ : secondBestCount;
154
+ best = [t, c];
155
+ } else {
156
+ secondBestCount = Math.max(secondBestCount, c);
157
+ }
158
+ }
159
+ if (best && best[1] > secondBestCount) {
160
+ compressed.imports[specifier] = best[0];
161
+ }
162
+ });
163
+
164
+ Object.entries(importMap.scopes).forEach(([scopePath, scopeMappings]) => {
165
+ const filtered: SpecifierMap = {};
166
+
167
+ Object.entries(scopeMappings).forEach(([specifier, target]) => {
168
+ const globalTarget = compressed.imports[specifier];
169
+ if (globalTarget === target) {
170
+ return;
171
+ }
172
+ filtered[specifier] = target;
173
+ });
174
+
175
+ if (Object.keys(filtered).length > 0) {
176
+ compressed.scopes[scopePath] = filtered;
177
+ }
178
+ });
179
+
180
+ const hasScopes = Object.keys(compressed.scopes).length > 0;
181
+ return hasScopes ? compressed : { imports: compressed.imports };
182
+ }
183
+
184
+ export function createImportMap({
129
185
  manifests,
130
186
  getFile,
131
187
  getScope
132
188
  }: GetImportMapOptions): Required<ImportMap> {
133
- const imports = buildImportsMap(manifests, getFile);
189
+ const imports = createImportsMap(manifests, getFile);
134
190
 
135
- const scopes = buildScopesMap(imports, manifests, getScope);
191
+ const scopes = createScopesMap(imports, manifests, getScope);
136
192
  return {
137
193
  imports,
138
194
  scopes
139
195
  };
140
196
  }
197
+
198
+ export function createClientImportMap(options: GetImportMapOptions): ImportMap {
199
+ const base = createImportMap(options);
200
+ const fixed = fixImportMapNestedScopes(base);
201
+ return compressImportMap(fixed);
202
+ }