| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Canonical path provides a consistent path (i.e. always forward slashes) across different OSes
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  | const path = require('canonical-path'); | 
					
						
							|  |  |  | const fs = require('fs-extra'); | 
					
						
							|  |  |  | const globby = require('globby'); | 
					
						
							|  |  |  | const jsdom = require('jsdom'); | 
					
						
							| 
									
										
										
										
											2021-02-20 16:23:46 +00:00
										 |  |  | const json5 = require('json5'); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  | const regionExtractor = require('../transforms/examples-package/services/region-parser'); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  | class StackblitzBuilder { | 
					
						
							|  |  |  |   constructor(basePath, destPath) { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     this.basePath = basePath; | 
					
						
							|  |  |  |     this.destPath = destPath; | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     this.copyrights = this._buildCopyrightStrings(); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:33 +02:00
										 |  |  |     this._boilerplatePackageJsons = {}; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |   build() { | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  |     this._checkForOutdatedConfig(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |     // When testing it sometimes helps to look a just one example directory like so:
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     // const stackblitzPaths = path.join(this.basePath, '**/testing/*stackblitz.json');
 | 
					
						
							|  |  |  |     const stackblitzPaths = path.join(this.basePath, '**/*stackblitz.json'); | 
					
						
							|  |  |  |     const fileNames = globby.sync(stackblitzPaths, { ignore: ['**/node_modules/**'] }); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     fileNames.forEach((configFileName) => { | 
					
						
							|  |  |  |       try { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |         // console.log('***'+configFileName)
 | 
					
						
							|  |  |  |         this._buildStackblitzFrom(configFileName); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       } catch (e) { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |         console.log(e); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:33 +02:00
										 |  |  |   _addDependencies(config, postData) { | 
					
						
							|  |  |  |     // Extract npm package dependencies
 | 
					
						
							|  |  |  |     const exampleType = this._getExampleType(config.basePath); | 
					
						
							|  |  |  |     const packageJson = this._getBoilerplatePackageJson(exampleType) || this._getBoilerplatePackageJson('cli'); | 
					
						
							|  |  |  |     const exampleDependencies = packageJson.dependencies; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Add unit test packages from devDependencies for unit test examples
 | 
					
						
							|  |  |  |     const devDependencies = packageJson.devDependencies; | 
					
						
							|  |  |  |     ['jasmine-core', 'jasmine-marbles'].forEach(dep => exampleDependencies[dep] = devDependencies[dep]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     postData.dependencies = JSON.stringify(exampleDependencies); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _getExampleType(exampleDir) { | 
					
						
							|  |  |  |     const configPath = `${exampleDir}/example-config.json`; | 
					
						
							|  |  |  |     const configSrc = fs.existsSync(configPath) && fs.readFileSync(configPath, 'utf-8').trim(); | 
					
						
							|  |  |  |     const config = configSrc ? JSON.parse(configSrc) : {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return config.projectType || 'cli'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _getBoilerplatePackageJson(exampleType) { | 
					
						
							|  |  |  |     if (!this._boilerplatePackageJsons.hasOwnProperty(exampleType)) { | 
					
						
							|  |  |  |       const pkgJsonPath = `${__dirname}/../examples/shared/boilerplate/${exampleType}/package.json`; | 
					
						
							|  |  |  |       this._boilerplatePackageJsons[exampleType] = fs.existsSync(pkgJsonPath) ? require(pkgJsonPath) : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return this._boilerplatePackageJsons[exampleType]; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _buildCopyrightStrings() { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const copyright = 'Copyright Google LLC. All Rights Reserved.\n' + | 
					
						
							| 
									
										
										
										
											2019-01-01 02:02:15 -05:00
										 |  |  |         'Use of this source code is governed by an MIT-style license that\n' + | 
					
						
							| 
									
										
										
										
											2020-11-16 22:37:09 +01:00
										 |  |  |         'can be found in the LICENSE file at https://angular.io/license'; | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const pad = '\n\n'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       jsCss: `${pad}/*\n${copyright}\n*/`, | 
					
						
							|  |  |  |       html: `${pad}<!-- \n${copyright}\n-->`, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |   // Build stackblitz from JSON configuration file (e.g., stackblitz.json):
 | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   // all properties are optional
 | 
					
						
							|  |  |  |   //   files: string[] - array of globs - defaults to all js, ts, html, json, css and md files (with certain files removed)
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |   //   description: string - description of this stackblitz - defaults to the title in the index.html page.
 | 
					
						
							|  |  |  |   //   tags: string[] - optional array of stackblitz tags (for searchability)
 | 
					
						
							|  |  |  |   //   main: string - name of file that will become index.html in the stackblitz - defaults to index.html
 | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  |   //   file: string - name of file to display within the stackblitz (e.g. `"file": "app/app.module.ts"`)
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |   _buildStackblitzFrom(configFileName) { | 
					
						
							|  |  |  |     // replace ending 'stackblitz.json' with 'stackblitz.no-link.html' to create output file name;
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const outputFileName = configFileName.replace(/stackblitz\.json$/, 'stackblitz.no-link.html'); | 
					
						
							|  |  |  |     let altFileName; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     if (this.destPath && this.destPath.length > 0) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       const partPath = path.dirname(path.relative(this.basePath, outputFileName)); | 
					
						
							|  |  |  |       altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       const config = this._initConfigAndCollectFileNames(configFileName); | 
					
						
							|  |  |  |       const postData = this._createPostData(config, configFileName); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:33 +02:00
										 |  |  |       this._addDependencies(config, postData); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       const html = this._createStackblitzHtml(config, postData); | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |       fs.writeFileSync(outputFileName, html, 'utf-8'); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       if (altFileName) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |         const altDirName = path.dirname(altFileName); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         fs.ensureDirSync(altDirName); | 
					
						
							|  |  |  |         fs.writeFileSync(altFileName, html, 'utf-8'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       // if we fail delete the outputFile if it exists because it is an old one.
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (fs.existsSync(outputFileName)) { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         fs.unlinkSync(outputFileName); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (altFileName && fs.existsSync(altFileName)) { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         fs.unlinkSync(altFileName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       throw e; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  |   _checkForOutdatedConfig() { | 
					
						
							|  |  |  |     // Ensure that nobody is trying to use the old config filenames (i.e. `plnkr.json`).
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); | 
					
						
							|  |  |  |     const fileNames = globby.sync(plunkerPaths, { ignore: ['**/node_modules/**'] }); | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (fileNames.length) { | 
					
						
							|  |  |  |       const readmePath = path.join(__dirname, 'README.md'); | 
					
						
							|  |  |  |       const errorMessage = | 
					
						
							|  |  |  |           'One or more examples are still trying to use \'plnkr.json\' files for configuring ' + | 
					
						
							|  |  |  |           'live examples. This is not supported any more. \'stackblitz.json\' should be used ' + | 
					
						
							|  |  |  |           'instead.\n' + | 
					
						
							|  |  |  |           `(Slight modifications may be required. See '${readmePath}' for more info.\n\n` + | 
					
						
							|  |  |  |           fileNames.map(name => `- ${name}`).join('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       throw Error(errorMessage); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 21:54:14 -05:00
										 |  |  |   _getPrimaryFile(config) { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |     if (config.file) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (!fs.existsSync(path.join(config.basePath, config.file))) { | 
					
						
							| 
									
										
										
										
											2020-01-09 21:54:14 -05:00
										 |  |  |         throw new Error(`The specified primary file (${config.file}) does not exist in '${config.basePath}'.`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return config.file; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       const defaultPrimaryFiles = ['src/app/app.component.html', 'src/app/app.component.ts', 'src/app/main.ts']; | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       const primaryFile = defaultPrimaryFiles.find(fileName =>  fs.existsSync(path.join(config.basePath, fileName))); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 21:54:14 -05:00
										 |  |  |       if (!primaryFile) { | 
					
						
							|  |  |  |         throw new Error(`None of the default primary files (${defaultPrimaryFiles.join(', ')}) exists in '${config.basePath}'.`); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 21:54:14 -05:00
										 |  |  |       return primaryFile; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-09 21:54:14 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _createBaseStackblitzHtml(config) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const file = `?file=${this._getPrimaryFile(config)}`; | 
					
						
							|  |  |  |     const action = `https://run.stackblitz.com/api/angular/v1${file}`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return `
 | 
					
						
							|  |  |  |       <!DOCTYPE html><html lang="en"><body> | 
					
						
							|  |  |  |         <form id="mainForm" method="post" action="${action}" target="_self"></form> | 
					
						
							|  |  |  |         <script> | 
					
						
							|  |  |  |           var embedded = 'ctl=1'; | 
					
						
							|  |  |  |           var isEmbedded = window.location.search.indexOf(embedded) > -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (isEmbedded) { | 
					
						
							|  |  |  |             var form = document.getElementById('mainForm'); | 
					
						
							|  |  |  |             var action = form.action; | 
					
						
							|  |  |  |             var actionHasParams = action.indexOf('?') > -1; | 
					
						
							|  |  |  |             var symbol = actionHasParams ? '&' : '?' | 
					
						
							|  |  |  |             form.action = form.action + symbol + embedded; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           document.getElementById("mainForm").submit(); | 
					
						
							|  |  |  |         </script> | 
					
						
							|  |  |  |       </body></html> | 
					
						
							|  |  |  |     `.trim();
 | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  |   _createPostData(config, configFileName) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const postData = {}; | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // If `config.main` is specified, ensure that it points to an existing file.
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     if (config.main && !fs.existsSync(path.join(config.basePath, config.main))) { | 
					
						
							| 
									
										
										
										
											2018-01-22 14:42:59 +02:00
										 |  |  |       throw Error(`The main file ('${config.main}') specified in '${configFileName}' does not exist.`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     config.fileNames.forEach((fileName) => { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       let content; | 
					
						
							|  |  |  |       const extn = path.extname(fileName); | 
					
						
							|  |  |  |       if (extn === '.png') { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         content = this._encodeBase64(fileName); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |         fileName = `${fileName.slice(0, -extn.length)}.base64${extn}`; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         content = fs.readFileSync(fileName, 'utf-8'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (extn === '.js' || extn === '.ts' || extn === '.css') { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         content = content + this.copyrights.jsCss; | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       } else if (extn === '.html') { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         content = content + this.copyrights.html; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       // const escapedValue = escapeHtml(content);
 | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       let relativeFileName = path.relative(config.basePath, fileName); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |       // Is the main a custom index-xxx.html file? Rename it
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (relativeFileName === config.main) { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |         relativeFileName = 'src/index.html'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // A custom main.ts file? Rename it
 | 
					
						
							|  |  |  |       if (/src\/main[-.]\w+\.ts$/.test(relativeFileName)) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |         relativeFileName = 'src/main.ts'; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (relativeFileName === 'index.html') { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |         if (config.description == null) { | 
					
						
							|  |  |  |           // set config.description to title from index.html
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |           const matches = /<title>(.*)<\/title>/.exec(content); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |           if (matches) { | 
					
						
							|  |  |  |             config.description = matches[1]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       content = regionExtractor()(content, extn.substr(1)).contents; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |       postData[`files[${relativeFileName}]`] = content; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-20 16:23:46 +00:00
										 |  |  |     // Stackblitz defaults to ViewEngine unless `"enableIvy": true`
 | 
					
						
							|  |  |  |     // So if there is a tsconfig.json file and there is no `enableIvy` property, we need to
 | 
					
						
							|  |  |  |     // explicitly set it.
 | 
					
						
							|  |  |  |     const tsConfigJSON = postData['files[tsconfig.json]']; | 
					
						
							|  |  |  |     if (tsConfigJSON !== undefined) { | 
					
						
							|  |  |  |       const tsConfig = json5.parse(tsConfigJSON); | 
					
						
							|  |  |  |       if (tsConfig.angularCompilerOptions.enableIvy === undefined) { | 
					
						
							|  |  |  |         tsConfig.angularCompilerOptions.enableIvy = true; | 
					
						
							|  |  |  |         postData['files[tsconfig.json]'] = JSON.stringify(tsConfig, null, 2); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const tags = ['angular', 'example', ...config.tags || []]; | 
					
						
							|  |  |  |     tags.forEach((tag, ix) => postData[`tags[${ix}]`] = tag); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     postData.description = `Angular Example - ${config.description}`; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return postData; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |   _createStackblitzHtml(config, postData) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const baseHtml = this._createBaseStackblitzHtml(config); | 
					
						
							|  |  |  |     const doc = jsdom.jsdom(baseHtml); | 
					
						
							|  |  |  |     const form = doc.querySelector('form'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for(const [key, value] of Object.entries(postData)) { | 
					
						
							|  |  |  |       const ele = this._htmlToElement(doc, `<input type="hidden" name="${key}">`); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       ele.setAttribute('value', value); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       form.appendChild(ele); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     return doc.documentElement.outerHTML; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _encodeBase64(file) { | 
					
						
							|  |  |  |     // read binary data
 | 
					
						
							| 
									
										
										
										
											2019-05-11 20:21:48 +05:30
										 |  |  |     return fs.readFileSync(file, { encoding: 'base64' }); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _htmlToElement(document, html) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const div = document.createElement('div'); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     div.innerHTML = html; | 
					
						
							|  |  |  |     return div.firstChild; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _initConfigAndCollectFileNames(configFileName) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const config = this._parseConfig(configFileName); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg']; | 
					
						
							| 
									
										
										
										
											2021-02-20 16:23:46 +00:00
										 |  |  |     const boilerplateIncludes = ['src/environments/*.*', 'angular.json', 'src/polyfills.ts', 'tsconfig.json']; | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     if (config.files) { | 
					
						
							|  |  |  |       if (config.files.length > 0) { | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |         if (config.files[0][0] === '!') { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |           config.files = defaultIncludes.concat(config.files); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       config.files = defaultIncludes; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |     config.files = config.files.concat(boilerplateIncludes); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     let includeSpec = false; | 
					
						
							|  |  |  |     const gpaths = config.files.map((fileName) => { | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       fileName = fileName.trim(); | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |       if (fileName[0] === '!') { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |         return '!' + path.join(config.basePath, fileName.substr(1)); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         includeSpec = includeSpec || /\.spec\.(ts|js)$/.test(fileName); | 
					
						
							|  |  |  |         return path.join(config.basePath, fileName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     const defaultExcludes = [ | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |       '!**/e2e/**/*.*', | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |       '!**/package.json', | 
					
						
							|  |  |  |       '!**/example-config.json', | 
					
						
							|  |  |  |       '!**/tslint.json', | 
					
						
							|  |  |  |       '!**/.editorconfig', | 
					
						
							|  |  |  |       '!**/wallaby.js', | 
					
						
							|  |  |  |       '!**/karma-test-shim.js', | 
					
						
							|  |  |  |       '!**/karma.conf.js', | 
					
						
							| 
									
										
										
										
											2017-08-22 21:31:15 +02:00
										 |  |  |       '!**/test.ts', | 
					
						
							|  |  |  |       '!**/tsconfig.app.json', | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  |       '!**/*stackblitz.*' | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // exclude all specs if no spec is mentioned in `files[]`
 | 
					
						
							|  |  |  |     if (!includeSpec) { | 
					
						
							|  |  |  |       defaultExcludes.push('!**/*.spec.*','!**/spec.js'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gpaths.push(...defaultExcludes); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  |     config.fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**'] }); | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return config; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-19 16:17:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _parseConfig(configFileName) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       const configSrc = fs.readFileSync(configFileName, 'utf-8'); | 
					
						
							|  |  |  |       const config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; | 
					
						
							|  |  |  |       config.basePath = path.dirname(configFileName); // assumes 'stackblitz.json' is at `/src` level.
 | 
					
						
							|  |  |  |       return config; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-28 19:29:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 18:08:28 +01:00
										 |  |  | module.exports = StackblitzBuilder; |