66 * found in the LICENSE file at https://angular.dev/license
77 */
88
9- import assert from 'node:assert' ;
109import { statSync } from 'node:fs' ;
11- import * as path from 'node:path' ;
12- import { AssetPattern , AssetPatternClass } from '../builders/application/schema' ;
10+ import path from 'node:path' ;
11+ import type { AssetPattern , AssetPatternClass } from '../builders/application/schema' ;
1312import { isSubDirectory } from './path' ;
1413
14+ /**
15+ * Asset pattern configuration normalized into its object form with a resolved `output` directory.
16+ */
17+ export interface NormalizedAssetsPattern extends AssetPatternClass {
18+ /** Relative output directory within the build output path. */
19+ output : string ;
20+ }
21+
22+ /**
23+ * Normalizes raw string and object asset patterns into {@link NormalizedAssetsPattern} objects
24+ * and validates that all asset inputs and outputs stay within the workspace and output directories.
25+ *
26+ * @param assetPatterns Raw string or object asset patterns from builder options.
27+ * @param workspaceRoot Workspace root directory path.
28+ * @param projectRoot Project root directory path.
29+ * @param projectSourceRoot Optional project source root directory path.
30+ * @returns An array of normalized asset pattern configurations.
31+ */
1532export function normalizeAssetPatterns (
1633 assetPatterns : AssetPattern [ ] ,
1734 workspaceRoot : string ,
1835 projectRoot : string ,
1936 projectSourceRoot : string | undefined ,
20- ) : ( AssetPatternClass & { output : string } ) [ ] {
37+ ) : NormalizedAssetsPattern [ ] {
2138 if ( assetPatterns . length === 0 ) {
2239 return [ ] ;
2340 }
@@ -29,6 +46,8 @@ export function normalizeAssetPatterns(
2946 const resolvedProjectRoot = path . resolve ( resolvedWorkspaceRoot , projectRoot ) ;
3047
3148 return assetPatterns . map ( ( assetPattern ) => {
49+ let normalized : NormalizedAssetsPattern ;
50+
3251 // Normalize string asset patterns to objects.
3352 if ( typeof assetPattern === 'string' ) {
3453 const assetPath = path . normalize ( assetPattern ) ;
@@ -46,45 +65,30 @@ export function normalizeAssetPatterns(
4665 throw new Error ( `The ${ assetPattern } asset path must be within the workspace root.` ) ;
4766 }
4867
49- let glob : string , input : string ;
50- let isDirectory : boolean ;
51-
52- try {
53- isDirectory = statSync ( resolvedAssetPath ) . isDirectory ( ) ;
54- } catch {
55- isDirectory = true ;
56- }
57-
58- if ( isDirectory ) {
59- // Folders get a recursive star glob.
60- glob = '**/*' ;
61- // Input directory is their original path.
62- input = assetPath ;
63- } else {
64- // Files are their own glob.
65- glob = path . basename ( assetPath ) ;
66- // Input directory is their original dirname.
67- input = path . dirname ( assetPath ) ;
68- }
68+ const isDirectory =
69+ statSync ( resolvedAssetPath , { throwIfNoEntry : false } ) ?. isDirectory ( ) ?? true ;
70+ const glob = isDirectory ? '**/*' : path . basename ( assetPath ) ;
71+ const input = isDirectory ? assetPath : path . dirname ( assetPath ) ;
6972
7073 // Output directory for both is the relative path from the root to input.
7174 const output = path . relative ( root , path . resolve ( resolvedWorkspaceRoot , input ) ) ;
7275
73- assetPattern = { glob, input, output } ;
76+ normalized = { glob, input, output } ;
7477 } else {
7578 if ( ! isSubDirectory ( resolvedWorkspaceRoot , assetPattern . input ) ) {
7679 throw new Error ( `The ${ assetPattern . input } asset path must be within the workspace root.` ) ;
7780 }
7881
79- assetPattern . output = path . join ( '.' , assetPattern . output ?? '' ) ;
82+ normalized = {
83+ ...assetPattern ,
84+ output : path . join ( '.' , assetPattern . output ?? '' ) ,
85+ } ;
8086 }
8187
82- assert ( assetPattern . output !== undefined ) ;
83-
84- if ( assetPattern . output . startsWith ( '..' ) ) {
88+ if ( normalized . output . startsWith ( '..' ) ) {
8589 throw new Error ( 'An asset cannot be written to a location outside of the output path.' ) ;
8690 }
8791
88- return assetPattern as AssetPatternClass & { output : string } ;
92+ return normalized ;
8993 } ) ;
9094}
0 commit comments