license import * as fs from 'fs' ; import * as path from 'path' ; import * as shx from 'shelljs' ; function main ( args ) { shx . set ( '-e' ) ; let errorHasOccured = false ; const paramFilePath = args [ 0 ] ; function unquoteParameter ( s ) { return s . replace ( /^'(.*)'$/ , '$1' ) ; } const params = fs . readFileSync ( paramFilePath , 'utf-8' ) . split ( '\n' ) . map ( unquoteParameter ) ; const [ out , srcDir , binDir , genfilesDir , modulesManifestArg , readmeMd , fesm2015Arg , fesm5Arg , esm2015Arg , esm5Arg , bundlesArg , srcsArg , typeDefinitionsArg , dataArg , licenseFile , dtsBundleArg , dtsBundleFileSuffix , ] = params ; const fesm2015 = fesm2015Arg . split ( ',' ) . filter ( s => ! ! s ) ; const fesm5 = fesm5Arg . split ( ',' ) . filter ( s => ! ! s ) ; const esm2015 = esm2015Arg . split ( ',' ) . filter ( s => ! ! s ) ; const esm5 = esm5Arg . split ( ',' ) . filter ( s => ! ! s ) ; const bundles = bundlesArg . split ( ',' ) . filter ( s => ! ! s ) ; const typeDefinitions = typeDefinitionsArg . split ( ',' ) . filter ( s => ! ! s ) ; const srcs = srcsArg . split ( ',' ) . filter ( s => ! ! s ) ; const dataFiles = dataArg . split ( ',' ) . filter ( s => ! ! s ) ; const modulesManifest = JSON . parse ( modulesManifestArg ) ; const dtsBundles = dtsBundleArg . split ( ',' ) . filter ( s => ! ! s ) ; if ( readmeMd ) { copyFile ( readmeMd , out ) ; } param inputPath param fileContent function writeFileFromInputPath ( inputPath , fileContent ) { let rootDir ; if ( inputPath . includes ( binDir ) ) { rootDir = binDir ; } else if ( inputPath . includes ( genfilesDir ) ) { rootDir = genfilesDir ; } else { rootDir = srcDir ; } const outputPath = path . join ( out , path . relative ( rootDir , inputPath ) ) ; shx . mkdir ( '-p' , path . dirname ( outputPath ) ) ; fs . writeFileSync ( outputPath , fileContent , 'utf-8' ) ; } param inputPath function copyFileFromInputPath ( inputPath ) { writeFileFromInputPath ( inputPath , fs . readFileSync ( inputPath , 'utf-8' ) ) ; } param file param suffix param outDir function writeEsmFile ( file , suffix , outDir ) { const root = file . substr ( 0 , file . lastIndexOf ( `${ suffix }/` ) + suffix . length + 1 ) ; const rel = path . dirname ( path . relative ( path . join ( root , srcDir ) , file ) ) ; if ( ! rel . startsWith ( '..' ) ) { copyFile ( file , path . join ( out , outDir ) , rel ) ; } } esm2015 . forEach ( file => writeEsmFile ( file , '.es6' , 'esm2015' ) ) ; esm5 . forEach ( file => writeEsmFile ( file , '.esm5' , 'esm5' ) ) ; bundles . forEach ( bundle => { copyFile ( bundle , out , 'bundles' ) ; } ) ; fesm2015 . forEach ( file => { copyFile ( file , out , 'fesm2015' ) ; } ) ; fesm5 . forEach ( file => { copyFile ( file , out , 'fesm5' ) ; } ) ; typeDefinitions . forEach ( f => writeFileFromInputPath ( f , readTypingsAndStripAmdModule ( f ) ) ) ; dataFiles . forEach ( f => copyFileFromInputPath ( f ) ) ; Object . keys ( modulesManifest ) . forEach ( moduleName => { const moduleFiles = modulesManifest [ moduleName ] ; const relative = path . relative ( binDir , moduleFiles [ 'index' ] ) ; moduleFiles [ 'esm5_index' ] = path . join ( binDir , 'esm5' , relative ) ; moduleFiles [ 'esm2015_index' ] = path . join ( binDir , 'esm2015' , relative ) ; const metadataFile = moduleFiles [ 'metadata' ] ; const typingsOutFile = moduleFiles [ 'typings' ] ; if ( dtsBundles . length ) { const metadataContent = rewireMetadata ( metadataFile , typingsOutFile ) ; writeFileFromInputPath ( metadataFile , metadataContent ) ; } else { copyFileFromInputPath ( metadataFile ) ; } } ) ; const licenseBanner = licenseFile ? fs . readFileSync ( licenseFile , 'utf-8' ) : '' ; dtsBundles . forEach ( bundleFile => { const cleanDistPath = bundleFile . replace ( dtsBundleFileSuffix , '.d.ts' ) ; const content = licenseBanner + '\n' + readTypingsAndStripAmdModule ( bundleFile ) . replace ( /(\/\*\*\s+\*\s\@license(((?!\*\/).|\s)*)\*\/)/gm , '' ) ; writeFileFromInputPath ( cleanDistPath , content ) ; } ) ; let rootPackageName = '' ; const packagesWithExistingPackageJson = new Set < string > ( ) ; for ( const src of srcs ) { if ( src . includes ( binDir ) || src . includes ( genfilesDir ) ) { errorHasOccured = true ; console . error ( 'The "srcs" for ng_package should not include output of other rules. Found:\n' + `  ${ src }` ) ; } let content = fs . readFileSync ( src , 'utf-8' ) ; if ( path . basename ( src ) === 'package.json' ) { const packageJson = JSON . parse ( content ) ; content = amendPackageJson ( src , packageJson ) ; const packageName = packageJson [ 'name' ] ; packagesWithExistingPackageJson . add ( packageName ) ; if ( ! rootPackageName || packageName . length < rootPackageName . length ) { rootPackageName = packageJson [ 'name' ] ; } } writeFileFromInputPath ( src , content ) ; } Object . keys ( modulesManifest ) . forEach ( entryPointPackageName => { const entryPointName = entryPointPackageName . substr ( rootPackageName . length + 1 ) ; if ( ! entryPointName ) return ; createMetadataReexportFile ( entryPointName , modulesManifest [ entryPointPackageName ] [ 'metadata' ] , entryPointPackageName ) ; createTypingsReexportFile ( entryPointName , licenseBanner , modulesManifest [ entryPointPackageName ] [ 'typings' ] ) ; if ( ! packagesWithExistingPackageJson . has ( entryPointPackageName ) ) { createEntryPointPackageJson ( entryPointName , entryPointPackageName ) ; } } ) ; return errorHasOccured ? 1 : 0 ; param from param file function srcDirRelative ( from , file ) { const result = normalizeSeparators ( path . relative ( path . dirname ( from ) , path . join ( srcDir , path . relative ( binDir , file ) ) ) ) ; if ( result . startsWith ( '..' ) ) return result ; return `./${ result }` ; } function copyFile ( file , baseDir , relative = '.' ) { const dir = path . join ( baseDir , relative ) ; shx . mkdir ( '-p' , dir ) ; shx . cp ( file , dir ) ; if ( file . indexOf ( '__' ) >= 0 ) { const outputPath = path . join ( dir , ... path . basename ( file ) . split ( '__' ) ) ; shx . mkdir ( '-p' , path . dirname ( outputPath ) ) ; shx . mv ( path . join ( dir , path . basename ( file ) ) , outputPath ) ; if ( file . endsWith ( '.js' ) ) { shx . chmod ( '+w' , outputPath ) ; shx . sed ( '-i' , `${ path . basename ( file ) }.map` , `${ path . basename ( outputPath ) }.map` , outputPath ) ; } } } param packageJson param parsedPackage function amendPackageJson ( packageJson , parsedPackage ) { const packageName = parsedPackage [ 'name' ] ; const moduleFiles = modulesManifest [ packageName ] ; if ( ! moduleFiles ) { console . error ( 'WARNING: no module metadata for package' , packageName ) ; console . error ( '   Not updating the package.json file to point to it' ) ; console . error ( '   The ng_module for this package is possibly missing the module_name attribute ' ) ; return JSON . stringify ( parsedPackage , null , 2 ) ; } parsedPackage [ 'main' ] = getBundleName ( packageName , 'bundles' ) ; parsedPackage [ 'fesm5' ] = getBundleName ( packageName , 'fesm5' ) ; parsedPackage [ 'fesm2015' ] = getBundleName ( packageName , 'fesm2015' ) ; parsedPackage [ 'esm5' ] = srcDirRelative ( packageJson , moduleFiles [ 'esm5_index' ] ) ; parsedPackage [ 'esm2015' ] = srcDirRelative ( packageJson , moduleFiles [ 'esm2015_index' ] ) ; parsedPackage [ 'typings' ] = srcDirRelative ( packageJson , moduleFiles [ 'typings' ] ) ; parsedPackage [ 'module' ] = parsedPackage [ 'fesm5' ] ; parsedPackage [ 'es2015' ] = parsedPackage [ 'fesm2015' ] ; return JSON . stringify ( parsedPackage , null , 2 ) ; } function getBundleName ( packageName , dir ) { const parts = packageName . split ( '/' ) ; const nameParts = packageName . startsWith ( '@' ) ? parts . splice ( 1 ) : parts ; const relativePath = Array ( nameParts . length - 1 ) . fill ( '..' ) . join ( '/' ) || '.' ; let basename ; if ( dir === 'bundles' ) { basename = nameParts . join ( '-' ) + '.umd' ; } else if ( nameParts . length === 1 ) { basename = nameParts [ 0 ] ; } else { basename = nameParts . slice ( 1 ) . join ( '/' ) ; } return [ relativePath , dir , basename + '.js' ] . join ( '/' ) ; } /** Creates metadata re-export file for a secondary entry-point. */ function createMetadataReexportFile ( entryPointName , metadataFile , packageName ) { const inputPath = path . join ( srcDir , `${ entryPointName }.metadata.json` ) ; writeFileFromInputPath ( inputPath , JSON . stringify ( { '__symbolic' : 'module' , 'version' : 3 , 'metadata' : { } , 'exports' : [ { 'from' : `${ srcDirRelative ( inputPath , metadataFile . replace ( /.metadata.json$/ , '' ) ) }` } ] , 'flatModuleIndexRedirect' : true , 'importAs' : packageName } ) + '\n' ) ; } /**
     * Creates a typings (d.ts) re-export file for a secondary-entry point,
     * e.g., `export * from './common/common'`
     */ function createTypingsReexportFile ( entryPointName , license , typingsFile ) { const inputPath = path . join ( srcDir , `${ entryPointName }.d.ts` ) ; const content = `${ license }
export * from '${ srcDirRelative ( inputPath , typingsFile . replace ( /\.d\.tsx?$/ , '' ) ) }';
` ; writeFileFromInputPath ( inputPath , content ) ; } param dir param entryPointPackageName function createEntryPointPackageJson ( dir , entryPointPackageName ) { const pkgJson = path . join ( srcDir , dir , 'package.json' ) ; const content = amendPackageJson ( pkgJson , { name : entryPointPackageName } ) ; writeFileFromInputPath ( pkgJson , content ) ; } /**
     * Normalizes the specified path by replacing backslash separators with Posix
     * forward slash separators.
     */ function normalizeSeparators ( path ) { return path . replace ( /\\/g , '/' ) ; } param metadataPath param typingsPath function rewireMetadata ( metadataPath , typingsPath ) { const metadata = JSON . parse ( fs . readFileSync ( metadataPath , 'utf-8' ) ) ; let typingsRelativePath = normalizeSeparators ( path . relative ( path . dirname ( metadataPath ) , typingsPath ) ) ; if ( ! typingsRelativePath . startsWith ( '..' ) ) { typingsRelativePath = `./${ typingsRelativePath }` ; } typingsRelativePath = typingsRelativePath . replace ( '.d.ts' , '' ) ; const relativePathRegex = /\.?\.\/[\w\.\-_\/]+/g ; if ( metadata . exports ) { metadata . exports = metadata . exports . filter ( ( e ) => ! e . from . match ( relativePathRegex ) ) ; } return JSON . stringify ( metadata ) . replace ( relativePathRegex , typingsRelativePath ) ; } param filePath function readTypingsAndStripAmdModule ( filePath ) { return fs . readFileSync ( filePath , 'utf-8' ) . replace ( /^\/\/\/ <amd-module name=.*\/>[\r\n]+/gm , '' ) ; } } if ( require . main === module ) { process . exitCode = main ( process . argv . slice ( 2 ) ) ; }