Files
blockly/scripts/migration/js2ts
dependabot[bot] 80be8bc04c chore(deps): Bump prettier from 3.0.3 to 3.1.0 (#7658)
* chore(deps): Bump prettier from 3.0.3 to 3.1.0

Bumps [prettier](https://github.com/prettier/prettier) from 3.0.3 to 3.1.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.0.3...3.1.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: format

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Beka Westberg <bwestberg@google.com>
2023-11-27 13:25:51 -08:00

169 lines
6.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const filenames = process.argv.slice(2); // Trim off node and script name.
//////////////////////////////////////////////////////////////////////
// Load deps files via require (since they're executalbe .js files).
//////////////////////////////////////////////////////////////////////
/**
* Dictionary mapping goog.module ID to absolute pathname of the file
* containing the goog.declareModuleId for that ID.
* @type {!Object<string, string>}
*/
const modulePaths = {};
/** Absolute path of repository root. */
const repoPath = path.resolve(__dirname, '..', '..');
/**
* Absolute path of directory containing base.js (the version used as
* input to tsc, not the one output by it).
* @type {string}
*/
const closurePath = path.resolve(repoPath, 'closure', 'goog');
globalThis.goog = {};
/**
* Stub version of addDependency that store mappings in modulePaths.
* @param {string} relPath The path to the js file.
* @param {!Array<string>} provides An array of strings with
* the names of the objects this file provides.
* @param {!Array<string>} _requires An array of strings with
* the names of the objects this file requires (unused).
* @param {boolean|!Object<string>=} opt_loadFlags Parameters indicating
* how the file must be loaded. The boolean 'true' is equivalent
* to {'module': 'goog'} for backwards-compatibility. Valid properties
* and values include {'module': 'goog'} and {'lang': 'es6'}.
*/
goog.addDependency = function (relPath, provides, _requires, opt_loadFlags) {
// Ignore any non-ESM files, as they can't be imported.
if (opt_loadFlags?.module !== 'es6') return;
// There should be only one "provide" from an ESM, but...
for (const moduleId of provides) {
// Store absolute path to source file (i.e., treating relPath
// relative to closure/goog/, not build/src/closure/goog/).
modulePaths[moduleId] = path.resolve(closurePath, relPath);
}
};
// Load deps files relative to this script's location.
require(path.resolve(__dirname, '../../build/deps.js'));
//////////////////////////////////////////////////////////////////////
// Process files mentioned on the command line.
//////////////////////////////////////////////////////////////////////
/** RegExp matching goog.require statements. */
const requireRE =
/(?:const\s+(?:([$\w]+)|(\{[^}]*\}))\s+=\s+)?goog.require(Type)?\('([^']+)'\);/gm;
/** RegExp matching key: value pairs in destructuring assignments. */
const keyValueRE = /([$\w]+)\s*:\s*([$\w]+)\s*(?=,|})/g;
for (const filename of filenames) {
let contents = null;
try {
contents = String(fs.readFileSync(filename));
} catch (e) {
console.error(`error while reading ${filename}: ${e.message}`);
continue;
}
console.log(`Converting ${filename} to TypeScript...`);
// Remove "use strict".
contents = contents.replace(/^\s*["']use strict["']\s*; *\n/m, '');
// Migrate from goog.module to goog.declareModuleId.
const closurePathRelative = path.relative(
path.dirname(path.resolve(filename)),
closurePath,
);
contents = contents.replace(
/^goog.module\('([$\w.]+)'\);$/m,
`import * as goog from '${closurePathRelative}/goog.js';\n` +
`goog.declareModuleId('$1');`,
);
// Migrate from goog.require to import.
contents = contents.replace(
requireRE,
function (
orig, // Whole statement to be replaced.
name, // Name of named import of whole module (if applicable).
names, // {}-enclosed list of destructured imports.
type, // If truthy, it is a requireType not require.
moduleId, // goog.module ID that was goog.require()d.
) {
const importPath = modulePaths[moduleId];
type = type ? ' type' : '';
if (!importPath) {
console.warn(
`Unable to migrate goog.require('${moduleId}') as no ES module path known.`,
);
return orig;
}
let relativePath = path.relative(
path.dirname(path.resolve(filename)),
importPath,
);
if (relativePath[0] !== '.') relativePath = './' + relativePath;
if (name) {
return `import${type} * as ${name} from '${relativePath}';`;
} else if (names) {
names = names.replace(keyValueRE, '$1 as $2');
return `import${type} ${names} from '${relativePath}';`;
} else {
// Side-effect only require.
return `import${type} '${relativePath}';`;
}
},
);
// Find and update or remove old-style export assignemnts.
/** @type {!Array<{name: string, re: RegExp>}>} */
const easyExports = [];
contents = contents.replace(
/^\s*exports\.([$\w]+)\s*=\s*([$\w]+)\s*;\n/gm,
function (
orig, // Whole statement to be replaced.
exportName, // Name to export item as.
declName, // Already-declared name for item being exported.
) {
// Renamed exports have to be transalted as-is.
if (exportName !== declName) {
return `export {${declName} as ${exportName}};\n`;
}
// OK, we're doing "export.foo = foo;". Can we update the
// declaration? We can't actualy modify it yet as we're in
// the middle of a search-and-replace on contents already, but
// we can delete the old export and later update the
// declaration into an export.
const declRE = new RegExp(
`^(\\s*)((?:const|let|var|function|class)\\s+${declName})\\b`,
'gm',
);
if (contents.match(declRE)) {
easyExports.push({exportName, declRE});
return ''; // Delete existing export assignment.
} else {
return `export ${exportName};\n`; // Safe fallback.
}
},
);
// Add 'export' to existing declarations where appropriate.
for (const {exportName, declRE} of easyExports) {
contents = contents.replace(declRE, '$1export $2');
}
// Write converted file with new extension.
const newFilename = filename.replace(/.js$/, '.ts');
fs.writeFileSync(newFilename, contents);
console.log(`Wrote ${newFilename}.`);
}