packages.ts (4077B)
1 /** 2 * @license 3 * Copyright 2022 Google Inc. 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 import {get} from 'node:https'; 8 9 import type {Tree} from '@angular-devkit/schematics'; 10 11 import {getNgCommandName} from './files.js'; 12 import { 13 getAngularConfig, 14 getApplicationProjects, 15 getJsonFileAsObject, 16 getObjectAsJson, 17 } from './json.js'; 18 import {type SchematicsOptions, TestRunner} from './types.js'; 19 export interface NodePackage { 20 name: string; 21 version: string; 22 } 23 export interface NodeScripts { 24 name: string; 25 script: string; 26 } 27 28 export enum DependencyType { 29 Default = 'dependencies', 30 Dev = 'devDependencies', 31 Peer = 'peerDependencies', 32 Optional = 'optionalDependencies', 33 } 34 35 export function getPackageLatestNpmVersion(name: string): Promise<NodePackage> { 36 return new Promise(resolve => { 37 let version = 'latest'; 38 39 return get(`https://registry.npmjs.org/${name}`, res => { 40 let data = ''; 41 42 res.on('data', chunk => { 43 data += chunk; 44 }); 45 res.on('end', () => { 46 try { 47 const response = JSON.parse(data); 48 version = response?.['dist-tags']?.latest ?? version; 49 } catch { 50 } finally { 51 resolve({ 52 name, 53 version, 54 }); 55 } 56 }); 57 }).on('error', () => { 58 resolve({ 59 name, 60 version, 61 }); 62 }); 63 }); 64 } 65 66 function updateJsonValues( 67 json: Record<string, any>, 68 target: string, 69 updates: Array<{name: string; value: any}>, 70 overwrite = false, 71 ) { 72 updates.forEach(({name, value}) => { 73 if (!json[target][name] || overwrite) { 74 json[target] = { 75 ...json[target], 76 [name]: value, 77 }; 78 } 79 }); 80 } 81 82 export function addPackageJsonDependencies( 83 tree: Tree, 84 packages: NodePackage[], 85 type: DependencyType, 86 overwrite?: boolean, 87 fileLocation = './package.json', 88 ): Tree { 89 const packageJson = getJsonFileAsObject(tree, fileLocation); 90 91 updateJsonValues( 92 packageJson, 93 type, 94 packages.map(({name, version}) => { 95 return {name, value: version}; 96 }), 97 overwrite, 98 ); 99 100 tree.overwrite(fileLocation, getObjectAsJson(packageJson)); 101 102 return tree; 103 } 104 105 export function getDependenciesFromOptions( 106 options: SchematicsOptions, 107 ): string[] { 108 const dependencies = ['puppeteer']; 109 110 switch (options.testRunner) { 111 case TestRunner.Jasmine: 112 dependencies.push('jasmine'); 113 break; 114 case TestRunner.Jest: 115 dependencies.push('jest', '@types/jest'); 116 break; 117 case TestRunner.Mocha: 118 dependencies.push('mocha', '@types/mocha'); 119 break; 120 case TestRunner.Node: 121 dependencies.push('@types/node'); 122 break; 123 } 124 125 return dependencies; 126 } 127 128 export function addPackageJsonScripts( 129 tree: Tree, 130 scripts: NodeScripts[], 131 overwrite?: boolean, 132 fileLocation = './package.json', 133 ): Tree { 134 const packageJson = getJsonFileAsObject(tree, fileLocation); 135 136 updateJsonValues( 137 packageJson, 138 'scripts', 139 scripts.map(({name, script}) => { 140 return {name, value: script}; 141 }), 142 overwrite, 143 ); 144 145 tree.overwrite(fileLocation, getObjectAsJson(packageJson)); 146 147 return tree; 148 } 149 150 export function updateAngularJsonScripts( 151 tree: Tree, 152 options: SchematicsOptions, 153 overwrite = true, 154 ): Tree { 155 const angularJson = getAngularConfig(tree); 156 const projects = getApplicationProjects(tree); 157 const name = getNgCommandName(projects); 158 159 Object.keys(projects).forEach(project => { 160 const e2eScript = [ 161 { 162 name, 163 value: { 164 builder: '@puppeteer/ng-schematics:puppeteer', 165 options: { 166 devServerTarget: `${project}:serve`, 167 testRunner: options.testRunner, 168 }, 169 configurations: { 170 production: { 171 devServerTarget: `${project}:serve:production`, 172 }, 173 }, 174 }, 175 }, 176 ]; 177 178 updateJsonValues( 179 angularJson['projects'][project]!, 180 'architect', 181 e2eScript, 182 overwrite, 183 ); 184 }); 185 186 tree.overwrite('./angular.json', getObjectAsJson(angularJson as any)); 187 188 return tree; 189 }