mirror of
https://github.com/google/blockly.git
synced 2025-12-16 14:20:10 +01:00
* refactor(tests): Use shims instead of bootstrap to load Blockly
- Modify tests/generators/index.html to import the test shims
instead of using bootstrap.js to load Blockly.
- Modify test/generators/webdriver.js to have it wait for the
workspace to exist before calling loadSelected(). There was
previously a race which index.html had been winning, but
now webdriver.js is winning (and the tests failing because
there is no workspace yet when start() is called.
* chore(tests): Delete bootstrap.js etc.
- Delete bootstrap.js, bootstrap_helper.js, and bootstrap_done.mjs.
- Remove remaining references to bootstrap.js
* refactor(build): Remove deps npm script
buildDeps is now only needed by buildCompiled, not ever for
runnning in uncompressed mode, so:
- Remove the deps gulp task (and the deps npm script.
- Have the minify task run buildJavaScript and buildDeps directly.
Additionally, the buildAdvanceCompilationTest target hasn't
needed deps.js for some time (if ever), so skip having it run
buildDeps entirely.
* refactor(build): Repatriate DEPS_FILE to build_tasks.js
Since this is no longer used anywhere else it doesn't need to
live in common.js.
* fix(scripts): Remove vestigial references to deps.mocha.js
* docs(tests): Add additional explanatory note
159 lines
6.1 KiB
JavaScript
Executable File
159 lines
6.1 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)?\('([^']+)'\);/mg;
|
|
|
|
/** 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}.`);
|
|
}
|