feat(bazel): prefix private-export (barred-latin-o) symbols (#23007)
This allows a bundle index to be re-exported by a higher-level module without fear of collisions. Under bazel, we always set the prefix to be underscore-joined workspace, package, label PR Close #23007
This commit is contained in:
parent
7a406a32fa
commit
27e14b2fb3
|
@ -280,6 +280,7 @@ def _write_bundle_index(ctx):
|
|||
tsconfig = dict(tsc_wrapped_tsconfig(ctx, ctx.files.srcs, ctx.files.srcs), **{
|
||||
"angularCompilerOptions": {
|
||||
"flatModuleOutFile": flat_module_out_file,
|
||||
"flatModulePrivateSymbolPrefix": "_".join([ctx.workspace_name] + ctx.label.package.split("/") + [ctx.label.name, ""]),
|
||||
},
|
||||
})
|
||||
if not ctx.attr.module_name:
|
||||
|
|
|
@ -15,7 +15,8 @@ describe('flat module index', () => {
|
|||
require.resolve(`${PKG}/flat_module_filename.metadata.json`), {encoding: 'utf-8'});
|
||||
expect(metadata).toContain('"__symbolic":"module"');
|
||||
expect(metadata).toContain('"__symbolic":"reference","module":"@angular/core"');
|
||||
expect(metadata).toContain('"origins":{"Child":"./child","ɵa":"./parent"}');
|
||||
expect(metadata).toContain(
|
||||
'"origins":{"Child":"./child","ɵangular_packages_compiler_cli_integrationtest_bazel_ng_module_test_module_a":"./parent"}');
|
||||
expect(metadata).toContain('"importAs":"some_npm_module"');
|
||||
});
|
||||
});
|
||||
|
@ -25,7 +26,8 @@ describe('flat module index', () => {
|
|||
fs.readFileSync(require.resolve(`${PKG}/flat_module_filename.d.ts`), {encoding: 'utf-8'});
|
||||
|
||||
expect(dts).toContain('export * from \'./index\';');
|
||||
expect(dts).toContain('export { Parent as ɵa } from \'./parent\';');
|
||||
expect(dts).toContain(
|
||||
'export { Parent as ɵangular_packages_compiler_cli_integrationtest_bazel_ng_module_test_module_a } from \'./parent\';');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -77,8 +77,9 @@ export function createBundleIndexHost<H extends ts.CompilerHost>(
|
|||
}
|
||||
const file = files[0];
|
||||
const indexModule = file.replace(/\.ts$/, '');
|
||||
const bundler =
|
||||
new MetadataBundler(indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host));
|
||||
const bundler = new MetadataBundler(
|
||||
indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host),
|
||||
ngOptions.flatModulePrivateSymbolPrefix);
|
||||
const metadataBundle = bundler.getMetadataBundle();
|
||||
const metadata = JSON.stringify(metadataBundle.metadata);
|
||||
const name =
|
||||
|
|
|
@ -83,11 +83,14 @@ export class MetadataBundler {
|
|||
private metadataCache = new Map<string, ModuleMetadata|undefined>();
|
||||
private exports = new Map<string, Symbol[]>();
|
||||
private rootModule: string;
|
||||
private privateSymbolPrefix: string;
|
||||
private exported: Set<Symbol>;
|
||||
|
||||
constructor(
|
||||
private root: string, private importAs: string|undefined, private host: MetadataBundlerHost) {
|
||||
private root: string, private importAs: string|undefined, private host: MetadataBundlerHost,
|
||||
privateSymbolPrefix?: string) {
|
||||
this.rootModule = `./${path.basename(root)}`;
|
||||
this.privateSymbolPrefix = (privateSymbolPrefix || '').replace(/\W/g, '_');
|
||||
}
|
||||
|
||||
getMetadataBundle(): BundledModule {
|
||||
|
@ -244,7 +247,7 @@ export class MetadataBundler {
|
|||
const exportedNames = new Set(exportedSymbols.map(s => s.name));
|
||||
let privateName = 0;
|
||||
|
||||
function newPrivateName(): string {
|
||||
function newPrivateName(prefix: string): string {
|
||||
while (true) {
|
||||
let digits: string[] = [];
|
||||
let index = privateName++;
|
||||
|
@ -253,8 +256,7 @@ export class MetadataBundler {
|
|||
digits.unshift(base[index % base.length]);
|
||||
index = Math.floor(index / base.length);
|
||||
}
|
||||
digits.unshift('\u0275');
|
||||
const result = digits.join('');
|
||||
const result = `\u0275${prefix}${digits.join('')}`;
|
||||
if (!exportedNames.has(result)) return result;
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +269,7 @@ export class MetadataBundler {
|
|||
let name = symbol.name;
|
||||
const identifier = `${symbol.declaration!.module}:${symbol.declaration !.name}`;
|
||||
if (symbol.isPrivate && !symbol.privateName) {
|
||||
name = newPrivateName();
|
||||
name = newPrivateName(this.privateSymbolPrefix);
|
||||
symbol.privateName = name;
|
||||
}
|
||||
if (symbolsMap.has(identifier)) {
|
||||
|
|
|
@ -99,6 +99,10 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
|||
// meaningful when `flatModuleOutFile` is also supplied. It is otherwise ignored.
|
||||
flatModuleId?: string;
|
||||
|
||||
// A prefix to insert in generated private symbols, e.g. for "my_prefix_" we
|
||||
// would generate private symbols named like `ɵmy_prefix_a`.
|
||||
flatModulePrivateSymbolPrefix?: string;
|
||||
|
||||
// Whether to generate code for library code.
|
||||
// If true, produce .ngfactory.ts and .ngstyle.ts files for .d.ts inputs.
|
||||
// Default is true.
|
||||
|
|
|
@ -19,10 +19,10 @@ describe('metadata bundler', () => {
|
|||
|
||||
it('should be able to bundle a simple library', () => {
|
||||
const host = new MockStringBundlerHost('/', SIMPLE_LIBRARY);
|
||||
const bundler = new MetadataBundler('/lib/index', undefined, host);
|
||||
const bundler = new MetadataBundler('/lib/index', undefined, host, 'prfx_');
|
||||
const result = bundler.getMetadataBundle();
|
||||
expect(Object.keys(result.metadata.metadata).sort()).toEqual([
|
||||
'ONE_CLASSES', 'One', 'OneMore', 'TWO_CLASSES', 'Two', 'TwoMore', 'ɵa', 'ɵb'
|
||||
'ONE_CLASSES', 'One', 'OneMore', 'TWO_CLASSES', 'Two', 'TwoMore', 'ɵprfx_a', 'ɵprfx_b'
|
||||
]);
|
||||
|
||||
const originalOne = './src/one';
|
||||
|
@ -34,11 +34,11 @@ describe('metadata bundler', () => {
|
|||
{name: 'ONE_CLASSES', value: originalOne}, {name: 'One', value: originalOne},
|
||||
{name: 'OneMore', value: originalOne}, {name: 'TWO_CLASSES', value: originalTwo},
|
||||
{name: 'Two', value: originalTwo}, {name: 'TwoMore', value: originalTwo},
|
||||
{name: 'ɵa', value: originalOne}, {name: 'ɵb', value: originalTwo}
|
||||
{name: 'ɵprfx_a', value: originalOne}, {name: 'ɵprfx_b', value: originalTwo}
|
||||
]);
|
||||
expect(result.privates).toEqual([
|
||||
{privateName: 'ɵa', name: 'PrivateOne', module: originalOne},
|
||||
{privateName: 'ɵb', name: 'PrivateTwo', module: originalTwo}
|
||||
{privateName: 'ɵprfx_a', name: 'PrivateOne', module: originalOne},
|
||||
{privateName: 'ɵprfx_b', name: 'PrivateTwo', module: originalTwo}
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue