Files
blockly/tests/bootstrap.js
Christopher Allen dba4dd29cc refactor(tests): Use bootstrap instead of uncompressed in Mocha tests
Use tests/bootstrap.js instead of blockly_uncompressed.js to load
blockly in uncompressed mode in the Mocha tests.

This entails adding a new item, despFiles, to BLOCKLY_BOOTSTRAP_OPTIONS,
to allow tests/deps.mocha.js to be loaded at the appropriate point.

Mention of blockly_uncompressed.js is removed from
tests/mocah/.mocharc.js; it's not clear to me what effect the "file:"
directive in this file might have previously had and I was not able to
find documentation for it on mochajs.org, but in any case removing it
appears to have had no ill effect.
2022-06-14 23:35:46 +01:00

205 lines
7.5 KiB
JavaScript

/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Bootstrap code to load Blockly, typically in
* uncompressed mode.
*
* Load this file in a <script> tag in a web page to use the
* Closure Library debug module loader to load Blockly in
* uncompressed mode.
*
* You must use a <script> tag to load this script first, then
* import blockly.mjs in a <script type=module> to obtain the
* loaded module.
*
* See tests/playground.html for example usage.
*
* Exception: for speed and compatibility reasons, if this is
* script is loaded in Internet Explorer or from a host other than
* localhost, blockly_compressed.js (et al.) will be loaded
* instead. IE 11 doesn't understand modern JavaScript, and
* because of the sequential module loading carried out by the
*
* (Note also that this file eschews certain modern JS constructs,
* like template literals, for compatibility with IE 11.)
*
* The bootstrap code will consult a BLOCKLY_BOOTSTRAP_OPTIONS
* global variable to determine what to load. See further
* documentation inline.
*
*/
'use strict';
(function() {
// Values usedd to compute default bootstrap options.
const isIe = navigator.userAgent.indexOf('MSIE') !== -1 ||
navigator.appVersion.indexOf('Trident/') > -1;
const localhosts = ['localhost', '127.0.0.1', '[::1]'];
// Default bootstrap options.
const options = {
// Decide whether to use compmiled mode or not. Please see issue
// #5557 for more information.
loadCompressed: isIe || !localhosts.includes(location.hostname),
// URL of the blockly repository. This is needed for a few reasons:
//
// - We need an absolute path instead of relative path because the
// advanced_playground the and regular playground are in
// different folders.
// - We need to get the root directory for blockly because it is
// different for github.io, appspot and local.
//
// Default value will work so long as top-level page is loaded
// from somewhere in tests/.
root: window.location.href.replace(/\/tests\/.*$/, '/'),
// List of deps files to load. Paths relative to root.
depsFiles: [
'build/deps.js',
],
// List of goog.modules to goog.require.
requires: [
'Blockly',
'Blockly.libraryBlocks',
'Blockly.Dart.all',
'Blockly.JavaScript.all',
'Blockly.Lua.all',
'Blockly.PHP.all',
'Blockly.Python.all',
],
// List of scripts to load in compressed mode, instead of
// requires. Paths relative to root.
compressedScripts: [
'blockly_compressed.js',
'blocks_compressed.js',
'dart_compressed.js',
'javascript_compressed.js',
'lua_compressed.js',
'php_compressed.js',
'python_compressed.js',
],
// Additional scripts to be loaded after Blockly is loaded,
// whether Blockly is loaded from compressed or uncompressed.
// Paths relative to root.
additionalScripts: [
'msg/messages.js',
],
};
if (typeof window.BLOCKLY_BOOTSTRAP_OPTIONS === 'object') {
Object.assign(options, window.BLOCKLY_BOOTSTRAP_OPTIONS);
}
/* eslint-disable-next-line no-undef */
if (typeof module === 'object' && typeof module.exports === 'object') {
// Running in node.js. Maybe we wish to support this.
// blockly_uncompressed formerly did, though it appears that the
// code had not been working for some time (at least since PR
// #5718 back in December 2021. For now just throw an error.
throw new Error('Bootstrapping in node.js not implemented.');
}
if (!options.loadCompressed) {
// We can load Blockly in uncompressed mode. Note that this section
// needs to parse in IE11 (mostly ES5.1, but allowing e.g. const),
// but it does not need to be _executable_ in IE11 - it is safe to
// use ES6 builtins.
// Disable loading of closure/goog/deps.js (which doesn't exist).
window.CLOSURE_NO_DEPS = true;
// Load the Closure Library's base.js (the only part of the
// libary we use, mainly for goog.require / goog.provide /
// goog.module).
document.write(
'<script src="' + options.root + '/closure/goog/base.js"></script>');
// Load dependency graph info from the specified deps files -
// typically just build/deps.js. To update deps after changing
// any module's goog.requires / imports, run `npm run build:deps`.
for (let i = 0; i < options.depsFiles.length; i++) {
document.write(
'<script src="' + options.root + options.depsFiles[i] + '">' +
'</script>');
}
const requiresString = options.requires.map(quote).join();
const scriptsString = options.additionalScripts.map(quote).join();
document.write(
'<script>\n' +
' let requires = [' + requiresString + '];\n' +
' let scripts = [' + scriptsString + '];\n' +
' for (const script of scripts) {\n' +
' const fakeModuleName = \n' +
' "script." + script.replace(/[./]/g, "-");\n' +
' goog.addDependency("../../" + script, [fakeModuleName], \n' +
' requires, {"lang": "es6"});\n' +
' requires = [fakeModuleName];\n' +
' }\n' +
' window.BlocklyLoader = new Promise((resolve, reject) => {\n' +
' goog.bootstrap(requires, resolve);\n' +
' }).then(() => {\n' +
' return goog.module.get(\'Blockly\');\n' +
' });\n' +
'</script>\n');
} else {
// We need to load Blockly in compressed mode. Load
// blockly_compressed.js et al. using <script> tags.
const scripts =
options.compressedScripts.concat(options.additionalScripts);
for (let i = 0; i < scripts.length; i++) {
document.write(
'<script src="' + options.root + scripts[i] + '"></script>');
}
}
return; // All done. Only helper functions after this point.
/**
* Convert a string into a string literal. Strictly speaking we
* only need to escape backslash, \r, \n, \u2028 (line separator),
* \u2029 (paragraph separator) and whichever quote character we're
* using, but for simplicity we escape all the control characters.
*
* Based on https://github.com/google/CodeCity/blob/master/server/code.js
*
* @param {string} str The string to convert.
* @return {string} The value s as a eval-able string literal.
*/
function quote(str) {
/* eslint-disable no-control-regex, no-multi-spaces */
/** Regexp for characters to be escaped in a single-quoted string. */
const singleRE = /[\x00-\x1f\\\u2028\u2029']/g;
/** Map of control character replacements. */
const replacements = {
'\x00': '\\0', '\x01': '\\x01', '\x02': '\\x02', '\x03': '\\x03',
'\x04': '\\x04', '\x05': '\\x05', '\x06': '\\x06', '\x07': '\\x07',
'\x08': '\\b', '\x09': '\\t', '\x0a': '\\n', '\x0b': '\\v',
'\x0c': '\\f', '\x0d': '\\r', '\x0e': '\\x0e', '\x0f': '\\x0f',
'"': '\\"', "'": "\\'", '\\': '\\\\',
'\u2028': '\\u2028', '\u2029': '\\u2029',
};
/* eslint-enable no-control-regex, no-multi-spaces */
/**
* Replacer function.
* @param {string} c Single UTF-16 code unit ("character") string to
* be replaced.
* @return {string} Multi-character string containing escaped
* representation of c.
*/
function replace(c) {
return replacements[c];
}
return "'" + str.replace(singleRE, replace) + "'";
}
})();