Skip to content

Commit f143555

Browse files
committed
fixup! feat(@angular/build): add library builder
1 parent 7928f11 commit f143555

6 files changed

Lines changed: 115 additions & 106 deletions

File tree

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

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,10 @@ import {
2222
loadPostcssConfiguration,
2323
} from '../../utils/postcss-configuration';
2424
import { getProjectRootPaths } from '../../utils/project-metadata';
25-
import { getEntryPointBundleName } from './pipeline/utils';
25+
import { type NormalizedEntryPoint, getEntryPointBundleName } from './pipeline/entry-points';
2626
import type { Schema as LibraryBuilderOptions } from './schema';
2727

28-
export interface NormalizedEntryPoint {
29-
/** The subpath in package.json exports (e.g. '.' or './testing'). */
30-
subpath: string;
31-
32-
/** Subpath name without leading './' (e.g. '.' or 'testing'). */
33-
name: string;
34-
35-
/** Display name of the entry point (e.g. '@my/lib' or '@my/lib/testing'). */
36-
displayName: string;
37-
38-
/** Base name of the output bundle (e.g. 'my-lib' or 'my-lib-testing'). */
39-
bundleName: string;
40-
41-
/** Absolute path to entry file. */
42-
entryFilePath: string;
43-
44-
/** Is this the primary entry point ('.')? */
45-
isPrimary: boolean;
46-
}
28+
export type { NormalizedEntryPoint } from './pipeline/entry-points';
4729

4830
export interface PackageJsonData {
4931
name: string;

‎packages/angular/build/src/builders/library/pipeline/build-action.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import type { NormalizedEntryPoint, NormalizedLibraryOptions } from '../options'
1515
import { collectAssetsToEmit } from './assets';
1616
import { type BundleEntryPointInput, type BundleResult, bundleEntryPoints } from './bundler';
1717
import { type SingleProgramCache, compileLibrary } from './compilation';
18+
import { type EntryPointLookup, createEntryDirectoryLookup } from './entry-points';
1819
import { generatePackageManifests } from './package-manifests';
1920
import type { createComponentStylesheetBundlerForLibrary } from './stylesheet-bundler';
20-
import { type EntryPointLookup, type OutputFile, createEntryDirectoryLookup } from './utils';
21+
import type { OutputFile } from './utils';
2122

2223
/**
2324
* State preserved across incremental builds in watch mode.

‎packages/angular/build/src/builders/library/pipeline/bundler.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ import {
1818
import { dts } from 'rolldown-plugin-dts';
1919
import { toPosixPath } from '../../../utils/path';
2020
import type { NormalizedEntryPoint, NormalizedLibraryOptions } from '../options';
21+
import { type EntryPointLookup, createEntryDirectoryLookup } from './entry-points';
2122
import {
22-
type EntryPointLookup,
2323
FESM_OUTPUT_DIR,
2424
type MemoryOutputFile,
2525
TYPES_OUTPUT_DIR,
26-
createEntryDirectoryLookup,
2726
createMemoryOutputFile,
2827
} from './utils';
2928

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import path from 'node:path';
10+
import { toPosixPath } from '../../../utils/path';
11+
12+
export interface NormalizedEntryPoint {
13+
/** The subpath in package.json exports (e.g. '.' or './testing'). */
14+
subpath: string;
15+
16+
/** Subpath name without leading './' (e.g. '.' or 'testing'). */
17+
name: string;
18+
19+
/** Display name of the entry point (e.g. '@my/lib' or '@my/lib/testing'). */
20+
displayName: string;
21+
22+
/** Base name of the output bundle (e.g. 'my-lib' or 'my-lib-testing'). */
23+
bundleName: string;
24+
25+
/** Absolute path to entry file. */
26+
entryFilePath: string;
27+
28+
/** Is this the primary entry point ('.')? */
29+
isPrimary: boolean;
30+
}
31+
32+
/**
33+
* Function that resolves a file path to its containing normalized library entry point, if any.
34+
*/
35+
export type EntryPointLookup = (filePath: string) => NormalizedEntryPoint | undefined;
36+
37+
/**
38+
* Creates an optimized, memoized lookup function that maps arbitrary file paths
39+
* to their closest containing library entry point.
40+
*
41+
* Entry point root directories are sorted in descending order of path length so that
42+
* more specific, nested sub-entry points take precedence over shallower or primary
43+
* entry points. Lookups are cached to avoid repeated path scanning.
44+
*
45+
* @example
46+
* Given two entry points:
47+
* - Primary entry point `.` at `/project/src/public-api.ts` (dir: `/project/src`)
48+
* - Secondary entry point `./testing` at `/project/src/testing/public-api.ts` (dir: `/project/src/testing`)
49+
*
50+
* ```ts
51+
* const findEntryPoint = createEntryDirectoryLookup(entryPoints);
52+
*
53+
* // Resolves to the 'testing' sub-entry point because /project/src/testing is the longest matching prefix:
54+
* findEntryPoint('/project/src/testing/test-bed.ts'); // -> NormalizedEntryPoint ('./testing')
55+
*
56+
* // Resolves to the primary entry point:
57+
* findEntryPoint('/project/src/button.ts'); // -> NormalizedEntryPoint ('.')
58+
*
59+
* // Returns undefined for files located outside any entry point directory:
60+
* findEntryPoint('/project/shared/utils.ts'); // -> undefined
61+
* ```
62+
*
63+
* @param entryPoints Iterable of normalized entry points.
64+
* @returns An {@link EntryPointLookup} function that returns the owning {@link NormalizedEntryPoint},
65+
* or `undefined` if the file does not belong to any entry point directory.
66+
*/
67+
export function createEntryDirectoryLookup(
68+
entryPoints: Iterable<NormalizedEntryPoint>,
69+
): EntryPointLookup {
70+
const dirs = Array.from(entryPoints, (ep) => {
71+
const dir = toPosixPath(path.dirname(ep.entryFilePath));
72+
73+
return {
74+
ep,
75+
dir,
76+
dirSlash: dir.endsWith('/') ? dir : `${dir}/`,
77+
};
78+
}).sort((a, b) => b.dir.length - a.dir.length);
79+
80+
const cache = new Map<string, NormalizedEntryPoint | undefined>();
81+
82+
return (filePath: string): NormalizedEntryPoint | undefined => {
83+
const posix = toPosixPath(filePath);
84+
const cached = cache.get(posix);
85+
if (cached !== undefined || cache.has(posix)) {
86+
return cached;
87+
}
88+
const found = dirs.find(({ dir, dirSlash }) => posix === dir || posix.startsWith(dirSlash))?.ep;
89+
cache.set(posix, found);
90+
91+
return found;
92+
};
93+
}
94+
95+
/**
96+
* Computes the base bundle file name for an entry point.
97+
*
98+
* @param packageName The package name from package.json.
99+
* @param entryPointName The entry point subpath name (defaults to '.').
100+
* @returns The sanitized bundle base name.
101+
*/
102+
export function getEntryPointBundleName(packageName: string, entryPointName = '.'): string {
103+
const isPrimary = !entryPointName || entryPointName === '.';
104+
const pkgName = packageName[0] === '@' ? packageName.slice(1) : packageName;
105+
const epName = isPrimary ? pkgName : `${pkgName}-${entryPointName}`;
106+
107+
return epName.replaceAll('/', '-');
108+
}

‎packages/angular/build/src/builders/library/pipeline/package-manifests_spec.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
import assert from 'node:assert';
1010
import { join } from 'node:path';
1111
import type { NormalizedEntryPoint, NormalizedLibraryOptions, PackageJsonData } from '../options';
12+
import { getEntryPointBundleName } from './entry-points';
1213
import { generatePackageManifests } from './package-manifests';
13-
import { type MemoryOutputFile, getEntryPointBundleName } from './utils';
14+
import type { MemoryOutputFile } from './utils';
1415

1516
describe('generatePackageManifests', () => {
1617
const tempDir = '/workspace/my-lib';

‎packages/angular/build/src/builders/library/pipeline/utils.ts‎

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import path from 'node:path';
10-
import { toPosixPath } from '../../../utils/path';
11-
import type { NormalizedEntryPoint } from '../options';
12-
139
const IS_DTS_FILE_REGEXP = /\.d\.[cm]?ts$/i;
1410
const IS_DTS_MAP_FILE_REGEXP = /\.d\.[cm]?ts\.map$/i;
1511

@@ -23,11 +19,6 @@ export const FESM_OUTPUT_DIR = 'fesm2022';
2319
*/
2420
export const TYPES_OUTPUT_DIR = 'types';
2521

26-
/**
27-
* Function that resolves a file path to its containing normalized library entry point, if any.
28-
*/
29-
export type EntryPointLookup = (filePath: string) => NormalizedEntryPoint | undefined;
30-
3122
/**
3223
* Represents an in-memory file to be emitted to disk.
3324
*/
@@ -114,76 +105,3 @@ export function isDeclarationFile(path: string): boolean {
114105
export function isDeclarationSourceMapFile(path: string): boolean {
115106
return IS_DTS_MAP_FILE_REGEXP.test(path);
116107
}
117-
118-
/**
119-
* Creates an optimized, memoized lookup function that maps arbitrary file paths
120-
* to their closest containing library entry point.
121-
*
122-
* Entry point root directories are sorted in descending order of path length so that
123-
* more specific, nested sub-entry points take precedence over shallower or primary
124-
* entry points. Lookups are cached to avoid repeated path scanning.
125-
*
126-
* @example
127-
* Given two entry points:
128-
* - Primary entry point `.` at `/project/src/public-api.ts` (dir: `/project/src`)
129-
* - Secondary entry point `./testing` at `/project/src/testing/public-api.ts` (dir: `/project/src/testing`)
130-
*
131-
* ```ts
132-
* const findEntryPoint = createEntryDirectoryLookup(entryPoints);
133-
*
134-
* // Resolves to the 'testing' sub-entry point because /project/src/testing is the longest matching prefix:
135-
* findEntryPoint('/project/src/testing/test-bed.ts'); // -> NormalizedEntryPoint ('./testing')
136-
*
137-
* // Resolves to the primary entry point:
138-
* findEntryPoint('/project/src/button.ts'); // -> NormalizedEntryPoint ('.')
139-
*
140-
* // Returns undefined for files located outside any entry point directory:
141-
* findEntryPoint('/project/shared/utils.ts'); // -> undefined
142-
* ```
143-
*
144-
* @param entryPoints Iterable of normalized entry points.
145-
* @returns An {@link EntryPointLookup} function that returns the owning {@link NormalizedEntryPoint},
146-
* or `undefined` if the file does not belong to any entry point directory.
147-
*/
148-
export function createEntryDirectoryLookup(
149-
entryPoints: Iterable<NormalizedEntryPoint>,
150-
): EntryPointLookup {
151-
const dirs = Array.from(entryPoints, (ep) => {
152-
const dir = toPosixPath(path.dirname(ep.entryFilePath));
153-
154-
return {
155-
ep,
156-
dir,
157-
dirSlash: dir.endsWith('/') ? dir : `${dir}/`,
158-
};
159-
}).sort((a, b) => b.dir.length - a.dir.length);
160-
161-
const cache = new Map<string, NormalizedEntryPoint | undefined>();
162-
163-
return (filePath: string): NormalizedEntryPoint | undefined => {
164-
const posix = toPosixPath(filePath);
165-
const cached = cache.get(posix);
166-
if (cached !== undefined || cache.has(posix)) {
167-
return cached;
168-
}
169-
const found = dirs.find(({ dir, dirSlash }) => posix === dir || posix.startsWith(dirSlash))?.ep;
170-
cache.set(posix, found);
171-
172-
return found;
173-
};
174-
}
175-
176-
/**
177-
* Computes the base bundle file name for an entry point.
178-
*
179-
* @param packageName The package name from package.json.
180-
* @param entryPointName The entry point subpath name (defaults to '.').
181-
* @returns The sanitized bundle base name.
182-
*/
183-
export function getEntryPointBundleName(packageName: string, entryPointName = '.'): string {
184-
const isPrimary = !entryPointName || entryPointName === '.';
185-
const pkgName = packageName[0] === '@' ? packageName.slice(1) : packageName;
186-
const epName = isPrimary ? pkgName : `${pkgName}-${entryPointName}`;
187-
188-
return epName.replaceAll('/', '-');
189-
}

0 commit comments

Comments
 (0)