UNPKG

chrome-devtools-frontend

Version:
130 lines (115 loc) 3.94 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview A quick and dirty search & replace script to aid in the * "*-legacy-ts" removal effort. * * It replaces each occurrence passed via "--from" to "--to" and adds the * import passed via "--import" if not already present in the web test. */ import * as fs from 'fs/promises'; import * as path from 'path'; import yargs from 'yargs'; const yargsObject = yargs(process.argv.slice(2), process.cwd()) .option('web-test-directory', { type: 'string', demandOption: true, }) .option('import', { type: 'string', demandOption: true, }) .option('from', { type: 'string', demandOption: true, }) .option('to', { type: 'string', demandOption: true, }) .strict() .parseSync(); // `createPlainTextSearchRegex` is stolen from string-utilities.ts. const SPECIAL_REGEX_CHARACTERS = '^[]{}()\\.^$*+?|-,'; const createPlainTextSearchRegex = function (query) { // This should be kept the same as the one in StringUtil.cpp. let regex = ''; for (let i = 0; i < query.length; ++i) { const c = query.charAt(i); if (SPECIAL_REGEX_CHARACTERS.indexOf(c) !== -1) { regex += '\\'; } regex += c; } return new RegExp(regex, 'g'); }; /** * Returns all the *.js web tests in a directory (recursively). * Skips over 'resources' directories which contain text fixtures. */ async function findWebTests(dir) { const entries = await fs.readdir(dir, { withFileTypes: true }); const pathPromises = entries.map(async entry => { const p = path.resolve(dir, entry.name); if (entry.isDirectory() && entry.name !== 'resources') { return findWebTests(p); } if (entry.isFile() && entry.name.endsWith('.js')) { return [p]; } return []; }); return (await Promise.all(pathPromises)).flat(); } /** * Inserts `importLine` at the beginning of `content` if not already present. * It has some smartness to either start a new 'import * as' block or append * it to an existing one. */ function addImportIfNecessary(content, importLine) { if (content.includes(importLine)) { return content; } // Find where to insert `importLine`. We'll add it either to // an existing import * as block or start a new one below the import {TestRunner} block. const lines = content.split('\n'); let lastImportIndex = 0; let onlyHasTestRunnerImports = true; for (const [index, line] of lines.entries()) { if (line.startsWith('import {')) { lastImportIndex = index; } else if (line.startsWith('import * as')) { lastImportIndex = index; onlyHasTestRunnerImports = false; } } const linesToInsert = onlyHasTestRunnerImports ? ['', importLine] : [importLine]; lines.splice(lastImportIndex + 1, 0, ...linesToInsert); return lines.join('\n'); } const fromRegex = createPlainTextSearchRegex(yargsObject.from); const webTestPaths = await findWebTests(yargsObject.webTestDirectory); for (const filePath of webTestPaths) { const content = await fs.readFile(filePath, { encoding: 'utf-8' }); let replacedContent = content; if (yargsObject.from === yargsObject.to && !content.match(fromRegex)) { // If the before/after are the same, we only check for the presence // and add the import if needed. continue; } else if (yargsObject.from !== yargsObject.to) { replacedContent = content.replaceAll(fromRegex, yargsObject.to); if (replacedContent === content) { continue; } } replacedContent = addImportIfNecessary(replacedContent, yargsObject.import); await fs.writeFile(filePath, replacedContent, { encoding: 'utf-8' }); } const suggestedCommitMessage = ` [DevTools] Replace \`${yargsObject.from}\` global with import Bug: chromium:1442410 `.trim(); console.log(suggestedCommitMessage);