blob: 70136e806d327f5f91c61cce59681c3aacdeab25 [file] [log] [blame]
// Copyright 2021 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.
const {Project, ts, SyntaxKind, StructureKind} = require('ts-morph');
const path = require('path');
  const project = new Project({
tsConfigFilePath: '../devtools-frontend/tsconfig.json',
});
function isWithinContructor(classNode, reference) {
const constructors = classNode.getConstructors();
if (!constructors.length) {
return false;
}
if (constructors.length !== 1) {
throw new Error('More than one constructor');
}
return reference.getAncestors().includes(constructors[0]);
}
const files = project.getSourceFiles();
for (const file of files) {
const filePath = file.getFilePath();
if (!filePath.startsWith(
path.normalize(path.join(process.cwd(), '..', 'devtools-frontend', 'front_end', process.argv[2])))) {
continue;
}
console.log(filePath);
if (filePath.includes('third_party') || filePath.includes('generated') || filePath.endsWith('.d.ts')) {
continue;
}
const classNodes = file.getClasses();
for (const classNode of classNodes) {
for (const property of classNode.getInstanceMembers()) {
const name = property.getStructure().name;
console.log(name);
if (name.startsWith('#') || !property.hasModifier(SyntaxKind.PrivateKeyword)) {
continue;
}
if (isWithinContructor(classNode, property)) {
continue;
}
const newName = `#${name}`;
property.toggleModifier('private', false);
property.rename(newName);
for (const reference of property.findReferencesAsNodes()) {
// The first ancestor is the property access on `this.`.
const containingNode = reference.getAncestors()[1];
// Replace all `delete this.#somePrivateVariable;` (since that is illegal on private class fields)
// and replace it with an assignment to `undefined`.
if (containingNode.getKind() === SyntaxKind.DeleteExpression) {
console.log(`Replacing delete statement on line ${reference.getStartLineNumber()}`);
// We should replace the statement, not the expression itself.
containingNode.getFirstAncestor().replaceWithText(`this.${newName} = undefined;`);
}
}
}
}
file.saveSync();
}
// project.save();