Skip to content

Commit 7362e85

Browse files
committed
fixup: also reject names that collide only by case
1 parent 000ec67 commit 7362e85

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

‎packages/angular/build/src/builders/library/options.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ function normalizeEntryPoints(
296296

297297
const entryPoints = new Map<string, NormalizedEntryPoint>();
298298
// Bundle names flatten '/' to '-', so two distinct subpaths can produce one.
299+
// Keyed case-insensitively: names differing only in case are distinct keys in
300+
// the bundler input map but one file on a case-insensitive filesystem.
299301
const bundleNameOrigins = new Map<string, string>();
300302
let hasPrimary = false;
301303

@@ -348,15 +350,17 @@ function normalizeEntryPoints(
348350
);
349351
}
350352

351-
const collidingKey = bundleNameOrigins.get(entryPoint.bundleName);
353+
const bundleNameKey = entryPoint.bundleName.toLowerCase();
354+
const collidingKey = bundleNameOrigins.get(bundleNameKey);
352355
if (collidingKey !== undefined) {
353356
throw new Error(
354357
`Entry points '${collidingKey}' and '${key}' both produce the bundle name ` +
355-
`'${entryPoint.bundleName}'. Entry point subpaths must not differ only by '/' versus '-'.`,
358+
`'${entryPoint.bundleName}'. Entry point subpaths must not differ only by ` +
359+
`'/' versus '-', or by case.`,
356360
);
357361
}
358362

359-
bundleNameOrigins.set(entryPoint.bundleName, key);
363+
bundleNameOrigins.set(bundleNameKey, key);
360364
entryPoints.set(entryPoint.name, entryPoint);
361365

362366
if (entryPoint.isPrimary) {

‎packages/angular/build/src/builders/library/tests/options/entry-points_spec.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,33 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) =>
9898
);
9999
});
100100

101+
it('should fail when two entry points differ only by case', async () => {
102+
// Distinct keys in the bundler input map, but one file on a case-insensitive
103+
// filesystem, so the emitted bundle depends on which OS ran the build.
104+
await harness.writeFiles({
105+
'projects/lib/Zz/public-api.ts': 'export const UPPER = 42;\n',
106+
'projects/lib/zz/public-api.ts': 'export const LOWER = 7;\n',
107+
});
108+
await harness.modifyFile('projects/lib/package.json', (content) => {
109+
const pkg = JSON.parse(content);
110+
pkg.exports = {
111+
'.': './src/public-api.ts',
112+
'./Zz': './Zz/public-api.ts',
113+
'./zz': './zz/public-api.ts',
114+
};
115+
116+
return JSON.stringify(pkg, null, 2);
117+
});
118+
119+
const { result, error } = await harness.executeOnce({
120+
outputLogsOnException: false,
121+
outputLogsOnFailure: false,
122+
});
123+
expect(result).toBeUndefined();
124+
expect(error).toBeDefined();
125+
expect((error as Error).message).toMatch(/both produce the bundle name/);
126+
});
127+
101128
it('should fail when entry point is not a .ts or .mts file', async () => {
102129
await harness.modifyFile('projects/lib/package.json', (content) => {
103130
const pkg = JSON.parse(content);

0 commit comments

Comments
 (0)