generator/utils.ts (166 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { spawn } from 'child_process'; import path from 'path'; import colors from 'colors'; import { series } from 'async'; import { existsSync } from 'fs'; import { readdir, stat, unlink, rmdir, readFile, writeFile, mkdir } from 'fs/promises'; export function executeCmd(cwd: string, cmd: string, args: string[]) : Promise<number> { return new Promise((resolve, reject) => { console.log(`[${cwd}] executing: ${cmd} ${args.join(' ')}`); const child = spawn(cmd, args, { cwd: cwd, windowsHide: true, shell: true, }); child.stdout.on('data', data => process.stdout.write(colors.grey(data.toString()))); child.stderr.on('data', data => process.stdout.write(colors.red(data.toString()))); child.on('error', err => { reject(err); }); child.on('exit', code => { if (code !== 0) { reject(`Exited with code ${code}`); } resolve(code ? code : 0); }); }); } export async function findDirRecursive(basePath: string, filter: (name: string) => boolean): Promise<string[]> { let results: string[] = []; for (const subPathName of await readdir(basePath)) { const subPath = path.resolve(`${basePath}/${subPathName}`); const fileStat = await stat(subPath); if (!fileStat.isDirectory()) { continue; } if (filter(subPath)) { results.push(subPath) } const pathResults = await findDirRecursive(subPath, filter); results = results.concat(pathResults); } return results; } export async function findRecursive(basePath: string, filter: (name: string) => boolean): Promise<string[]> { let results: string[] = []; for (const subPathName of await readdir(basePath)) { const subPath = path.resolve(`${basePath}/${subPathName}`); const fileStat = await stat(subPath); if (fileStat.isDirectory()) { const pathResults = await findRecursive(subPath, filter); results = results.concat(pathResults); continue; } if (!fileStat.isFile()) { continue; } if (!filter(subPath)) { continue; } results.push(subPath); } return results; } export async function rmdirRecursive(basePath: string) { if (!existsSync(basePath)) { return; } for (const subPathName of await readdir(basePath)) { const subPath = path.resolve(`${basePath}/${subPathName}`); const fileStat = await stat(subPath); if (fileStat.isDirectory()) { await rmdirRecursive(subPath); continue; } if (fileStat.isFile()) { await unlink(subPath); continue; } } await rmdir(basePath); } export function lowerCaseContains(list: string[], item: string): boolean { return list.findIndex(v => lowerCaseEquals(v, item)) > -1; } export function lowerCaseEquals(a: string, b: string): boolean { return a.toLowerCase() === b.toLowerCase(); } export function lowerCaseCompare(a: string, b: string) { const aLower = a.toLowerCase(); const bLower = b.toLowerCase(); if (aLower === bLower) { return 0; } return aLower < bLower ? -1 : 1; } export function lowerCaseStartsWith(a: string, b: string) { const aLower = a.toLowerCase(); const bLower = b.toLowerCase(); return aLower.startsWith(bLower); } export function lowerCaseCompareLists(listA: string[], listB: string[]) { for (let i = 0; i < listA.length; i++) { if (listB.length < i + 1) { return -1; } const compareResult = lowerCaseCompare(listA[i], listB[i]); if (compareResult !== 0) { return compareResult; } } if (listB.length > listA.length) { return 1; } return 0; } export function apiVersionCompare(a: string, b: string) { if (a.length === b.length) { return lowerCaseCompare(a, b); } else if (a.length < b.length) { const result = lowerCaseCompare(a, b.substr(0, a.length)); return result !== 0 ? result : 1; } else { const result = lowerCaseCompare(a.substr(0, b.length), b); return result !== 0 ? result : -1; } } export async function readJsonFile(filePath: string) { try { const rawContents = await readFile(filePath, { encoding: 'utf8' }); return JSON.parse(rawContents); } catch (err) { throw new Error(`Failed to read JSON file '${filePath}': ${err}`); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function writeJsonFile(filePath: string, json: any) { try { const rawContents = JSON.stringify(json, null, 2); await writeFile(filePath, rawContents, { encoding: 'utf8' }); } catch (err) { throw new Error(`Failed to read JSON file '${filePath}': ${err}`); } } export async function safeMkdir(filePath: string) { if (!existsSync(filePath)) { await mkdir(filePath, { recursive: true }); } } export async function safeUnlink(filePath: string) { if (existsSync(filePath)) { await unlink(filePath); } } export function fileExists(filePath: string) { return existsSync(filePath); } export function executeSynchronous<T>(asyncFunc: () => Promise<T>) { series( [asyncFunc], (error) => { if (error) { throw error; } }); } export function chunker<T>(input: T[], chunks: number): T[][] { const minChunkSize = Math.floor(input.length / chunks); let remainder = input.length - (minChunkSize * chunks); let position = 0; const output = []; for (let i = 0; i < chunks; i++) { let chunkSize = minChunkSize; if (remainder > 0) { remainder--; chunkSize++; } const chunk = input.slice(position, position + chunkSize); output.push(chunk); position += chunkSize; } return output; }