88'use strict' ;
99
1010import { JsonObject } from '@angular-devkit/core' ;
11+ import * as crypto from 'crypto' ;
1112import * as fs from 'fs' ;
1213import * as path from 'path' ;
1314import * as ts from 'typescript' ;
1415
16+ const glob = require ( 'glob' ) ;
1517const distRoot = path . join ( __dirname , '../dist' ) ;
1618
1719
@@ -27,10 +29,44 @@ export interface PackageInfo {
2729 private : boolean ;
2830 packageJson : JsonObject ;
2931 dependencies : string [ ] ;
32+
33+ hash : string ;
3034}
3135export type PackageMap = { [ name : string ] : PackageInfo } ;
3236
3337
38+ const hashCache : { [ name : string ] : string | null } = { } ;
39+ function _getHashOf ( pkg : PackageInfo ) : string {
40+ if ( ! ( pkg . name in hashCache ) ) {
41+ hashCache [ pkg . name ] = null ;
42+ const md5Stream = crypto . createHash ( 'md5' ) ;
43+
44+ // Update the stream with all files content.
45+ const files : string [ ] = glob . sync ( path . join ( pkg . root , '**' ) , { nodir : true } ) ;
46+ files . forEach ( filePath => {
47+ md5Stream . write ( `\0${ filePath } \0` ) ;
48+ md5Stream . write ( fs . readFileSync ( filePath ) ) ;
49+ } ) ;
50+ // Update the stream with all versions of upstream dependencies.
51+ pkg . dependencies . forEach ( depName => {
52+ md5Stream . write ( `\0${ depName } \0${ _getHashOf ( packages [ depName ] ) } \0` ) ;
53+ } ) ;
54+
55+ md5Stream . end ( ) ;
56+
57+ hashCache [ pkg . name ] = ( md5Stream . read ( ) as Buffer ) . toString ( 'hex' ) ;
58+ }
59+
60+ if ( ! hashCache [ pkg . name ] ) {
61+ // Protect against circular dependency.
62+ throw new Error ( 'Circular dependency detected between the following packages: '
63+ + Object . keys ( hashCache ) . filter ( key => hashCache [ key ] == null ) . join ( ', ' ) ) ;
64+ }
65+
66+ return hashCache [ pkg . name ] ! ;
67+ }
68+
69+
3470function loadPackageJson ( p : string ) {
3571 const root = require ( '../package.json' ) ;
3672 const pkg = require ( p ) ;
@@ -108,8 +144,10 @@ const packageJsonPaths = _findAllPackageJson(path.join(__dirname, '..'), exclude
108144 // Remove the root package.json.
109145 . filter ( p => p != path . join ( __dirname , '../package.json' ) ) ;
110146
111- // All the supported packages. Go through the packages directory and create a _map of
112- // name => fullPath.
147+
148+ // All the supported packages. Go through the packages directory and create a map of
149+ // name => PackageInfo. This map is partial as it lacks some information that requires the
150+ // map itself to finish building.
113151export const packages : PackageMap =
114152 packageJsonPaths
115153 . map ( pkgPath => ( { root : path . dirname ( pkgPath ) } ) )
@@ -136,12 +174,14 @@ export const packages: PackageMap =
136174 root : pkgRoot ,
137175 relative : path . relative ( path . dirname ( __dirname ) , pkgRoot ) ,
138176 main : path . resolve ( pkgRoot , 'src/index.ts' ) ,
139- dependencies : [ ] ,
140177 private : packageJson . private ,
141178 tar : path . join ( distRoot , name . replace ( '/' , '_' ) + '.tgz' ) ,
142179 bin,
143180 name,
144181 packageJson,
182+
183+ dependencies : [ ] ,
184+ hash : '' ,
145185 } ;
146186
147187 return packages ;
@@ -158,3 +198,9 @@ for (const pkgName of Object.keys(packages)) {
158198 || name in ( pkgJson . peerDependencies || { } ) ;
159199 } ) ;
160200}
201+
202+
203+ // Update the hash values of each.
204+ for ( const pkgName of Object . keys ( packages ) ) {
205+ packages [ pkgName ] . hash = _getHashOf ( packages [ pkgName ] ) ;
206+ }
0 commit comments