2017-04-16 21:40:47 +00:00
// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes
2021-07-22 11:38:18 +00:00
import archiver from 'archiver' ;
import path from 'canonical-path' ;
import fs from 'fs-extra' ;
2021-07-22 05:15:58 +00:00
import { globbySync } from 'globby' ;
2021-07-22 11:38:18 +00:00
import { fileURLToPath } from 'url' ;
2017-04-16 21:40:47 +00:00
2022-06-27 21:41:05 +00:00
import regionExtractor from '../transforms/examples-package/services/region-parser.js' ;
2017-04-16 21:40:47 +00:00
2021-07-22 11:38:18 +00:00
const _ _dirname = path . dirname ( fileURLToPath ( import . meta . url ) ) ;
2017-08-22 19:31:15 +00:00
const EXAMPLE _CONFIG _NAME = 'example-config.json' ;
2021-07-22 11:38:18 +00:00
export class ExampleZipper {
2022-06-02 22:18:34 +00:00
constructor ( exampleDirName , outputDirName ) {
2017-04-16 21:40:47 +00:00
this . examplesPackageJson = path . join ( _ _dirname , '../examples/shared/package.json' ) ;
2017-08-22 19:31:15 +00:00
this . examplesSystemjsConfig = path . join ( _ _dirname , '../examples/shared/boilerplate/systemjs/src/systemjs.config.js' ) ;
this . examplesSystemjsLoaderConfig = path . join ( _ _dirname , '../examples/shared/boilerplate/systemjs/src/systemjs-angular-loader.js' ) ;
this . exampleTsconfig = path . join ( _ _dirname , '../examples/shared/boilerplate/systemjs/src/tsconfig.json' ) ;
2017-04-16 21:40:47 +00:00
2022-06-02 22:18:34 +00:00
const configFileNames = this . _findConfigurationFileNames ( exampleDirName ) ;
if ( configFileNames . length == 0 ) {
throw new Error ( ` Missing zip configuration file(s) from example directory ${ this . examplePath } . Did you forget to include a stackblitz.json/zipper.json? ` ) ;
}
configFileNames . forEach ( ( configFileName ) => {
this . _zipExample ( configFileName , exampleDirName , outputDirName ) ;
} ) ;
}
_findConfigurationFileNames ( exampleDirName ) {
const gpathStackblitz = path . join ( exampleDirName , '*stackblitz.json' ) ;
const gpathZipper = path . join ( exampleDirName , 'zipper.json' ) ;
const configFileNames = globbySync ( [ gpathStackblitz , gpathZipper ] , {
2022-04-05 19:59:52 +00:00
dot : true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
} ) ;
2022-06-02 22:18:34 +00:00
return configFileNames ;
2017-04-16 21:40:47 +00:00
}
_changeTypeRoots ( tsconfig ) {
return tsconfig . replace ( '../../../' , '../' ) ;
}
_createZipArchive ( zipFileName ) {
let dirName = path . dirname ( zipFileName ) ;
fs . ensureDirSync ( dirName ) ;
let output = fs . createWriteStream ( zipFileName ) ;
let archive = archiver ( 'zip' ) ;
archive . on ( 'error' , function ( err ) {
throw err ;
} ) ;
archive . pipe ( output ) ;
return archive ;
}
2023-01-09 10:16:13 +00:00
_getExampleType ( exampleDirName ) {
const filePath = path . join ( exampleDirName , EXAMPLE _CONFIG _NAME ) ;
2017-08-22 19:31:15 +00:00
try {
2021-07-22 11:38:18 +00:00
return this . _loadJson ( filePath ) . projectType || 'cli' ;
2017-08-22 19:31:15 +00:00
} catch ( err ) { // empty file, so it is cli
return 'cli' ;
}
}
2021-07-22 11:38:18 +00:00
_loadJson ( filePath ) {
return JSON . parse ( fs . readFileSync ( filePath , 'utf8' ) ) ;
}
2017-12-14 14:02:49 +00:00
// rename a custom main.ts or index.html file
2018-05-02 12:13:32 +00:00
_renameFile ( file , exampleType ) {
2023-10-26 16:17:34 +00:00
if ( /src\/main[-.]\w+\.ts$/ . test ( file ) && exampleType !== 'ssr' ) {
2017-12-14 14:02:49 +00:00
return 'src/main.ts' ;
}
if ( /src\/index[-.]\w+\.html$/ . test ( file ) ) {
return 'src/index.html' ;
}
return file ;
}
2017-04-16 21:40:47 +00:00
_zipExample ( configFileName , sourceDirName , outputDirName ) {
2021-07-22 11:38:18 +00:00
let json = this . _loadJson ( configFileName ) ;
2017-04-16 21:40:47 +00:00
const basePath = json . basePath || '' ;
const jsonFileName = configFileName . replace ( /^.*[\\\/]/ , '' ) ;
2022-06-02 22:18:34 +00:00
let relativeDirName = path . basename ( sourceDirName ) ;
2017-04-16 21:40:47 +00:00
let exampleZipName ;
if ( relativeDirName . indexOf ( '/' ) !== - 1 ) { // Special example
2017-11-22 13:58:21 +00:00
exampleZipName = relativeDirName . split ( '/' ) . join ( '-' ) ;
2017-04-16 21:40:47 +00:00
} else {
2017-11-03 17:08:28 +00:00
exampleZipName = jsonFileName . replace ( /(stackblitz|zipper).json/ , relativeDirName ) ;
2017-04-16 21:40:47 +00:00
}
const exampleDirName = path . dirname ( configFileName ) ;
2023-01-09 10:16:13 +00:00
const exampleType = this . _getExampleType ( exampleDirName ) ;
2022-06-02 22:18:34 +00:00
const outputFileName = path . join ( outputDirName , exampleZipName + '.zip' ) ;
2019-07-15 17:37:25 +00:00
let defaultIncludes = [ '**/*.ts' , '**/*.js' , '**/*.es6' , '**/*.css' , '**/*.html' , '**/*.md' , '**/*.json' , '**/*.png' , '**/*.svg' ] ;
2017-08-22 19:31:15 +00:00
let alwaysIncludes = [
'.editorconfig' ,
'.gitignore' ,
2019-07-31 21:10:52 +00:00
'angular.json' ,
'browserslist' ,
'bs-config.json' ,
'karma.conf.js' ,
2017-08-22 19:31:15 +00:00
'karma-test-shim.js' ,
2020-07-22 19:23:55 +00:00
'package.json' ,
2019-07-31 21:10:52 +00:00
'tsconfig.*' ,
'e2e/protractor.conf.js' ,
'e2e/tsconfig.json' ,
2017-08-22 19:31:15 +00:00
'src/favicon.ico' ,
2017-12-14 14:02:49 +00:00
'src/polyfills.ts' ,
2018-05-16 20:30:39 +00:00
'src/test.ts' ,
2017-12-14 14:02:49 +00:00
'src/environments/**/*' ,
2019-07-31 21:10:52 +00:00
'src/testing/**/*' ,
2017-08-22 19:31:15 +00:00
] ;
2017-12-14 14:02:49 +00:00
var alwaysExcludes = [
2017-04-16 21:40:47 +00:00
'!**/bs-config.e2e.json' ,
2017-11-03 17:08:28 +00:00
'!**/*stackblitz.*' ,
2017-04-16 21:40:47 +00:00
'!**/*zipper.*' ,
'!**/systemjs.config.js' ,
'!**/npm-debug.log' ,
'!**/example-config.json' ,
'!**/wallaby.js' ,
2022-07-06 23:16:50 +00:00
'!**/e2e/protractor-bazel.conf.js' ,
2020-02-03 01:49:28 +00:00
// AOT related files
2017-04-16 21:40:47 +00:00
'!**/aot/**/*.*' ,
'!**/*-aot.*'
] ;
if ( json . files ) {
if ( json . files . length > 0 ) {
json . files = json . files . map ( file => {
if ( file . startsWith ( '!' ) ) {
if ( file . startsWith ( '!**' ) ) {
return file ;
}
2022-03-20 10:23:47 +00:00
return '!' + basePath + file . slice ( 1 ) ;
2017-04-16 21:40:47 +00:00
}
return basePath + file ;
} ) ;
2020-03-19 14:17:32 +00:00
if ( json . files [ 0 ] [ 0 ] === '!' ) {
2017-04-16 21:40:47 +00:00
json . files = defaultIncludes . concat ( json . files ) ;
}
}
} else {
json . files = defaultIncludes ;
}
json . files = json . files . concat ( alwaysIncludes ) ;
let gpaths = json . files . map ( ( fileName ) => {
fileName = fileName . trim ( ) ;
2020-03-19 14:17:32 +00:00
if ( fileName [ 0 ] === '!' ) {
2022-03-20 10:23:47 +00:00
return '!' + path . join ( exampleDirName , fileName . slice ( 1 ) ) ;
2017-04-16 21:40:47 +00:00
} else {
return path . join ( exampleDirName , fileName ) ;
}
} ) ;
2020-03-19 14:17:32 +00:00
gpaths . push ( ... alwaysExcludes ) ;
2017-04-16 21:40:47 +00:00
2022-04-05 19:59:52 +00:00
let fileNames = globbySync ( gpaths , {
ignore : [ '**/node_modules/**' ] ,
dot : true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
} ) ;
2017-04-16 21:40:47 +00:00
let zip = this . _createZipArchive ( outputFileName ) ;
fileNames . forEach ( ( fileName ) => {
let relativePath = path . relative ( exampleDirName , fileName ) ;
2018-05-02 12:13:32 +00:00
relativePath = this . _renameFile ( relativePath , exampleType ) ;
2017-04-16 21:40:47 +00:00
let content = fs . readFileSync ( fileName , 'utf8' ) ;
2022-03-20 10:23:47 +00:00
let extn = path . extname ( fileName ) . slice ( 1 ) ;
2017-04-16 21:40:47 +00:00
// if we don't need to clean up the file then we can do the following.
// zip.append(fs.createReadStream(fileName), { name: relativePath });
let output = regionExtractor ( ) ( content , extn ) . contents ;
2022-12-25 20:57:43 +00:00
appendToZip ( zip , output , { name : relativePath } ) ;
2017-04-16 21:40:47 +00:00
} ) ;
// also a systemjs config
2017-08-22 19:31:15 +00:00
if ( exampleType === 'systemjs' ) {
2022-12-25 20:57:43 +00:00
appendToZip ( zip , fs . readFileSync ( this . examplesSystemjsConfig , 'utf8' ) , { name : 'src/systemjs.config.js' } ) ;
appendToZip ( zip , fs . readFileSync ( this . examplesSystemjsLoaderConfig , 'utf8' ) , { name : 'src/systemjs-angular-loader.js' } ) ;
2017-08-22 19:31:15 +00:00
// a modified tsconfig
let tsconfig = fs . readFileSync ( this . exampleTsconfig , 'utf8' ) ;
2022-12-25 20:57:43 +00:00
appendToZip ( zip , this . _changeTypeRoots ( tsconfig ) , { name : 'src/tsconfig.json' } ) ;
2017-04-16 21:40:47 +00:00
}
zip . finalize ( ) ;
}
}
2022-12-25 20:57:43 +00:00
// Fix the timestamp on zip entries in order create reproducible zip
// files, which improves remote Bazel cache performance.
function appendToZip ( zip , source , data ) {
const FIXED _DATE = new Date ( 0 ) ;
zip . append ( source , { ... data , date : FIXED _DATE } ) ;
}