Source: utils/ts-runner.js
/**
* This is the Typescript loader.
*
* Each script inside the DOM that has 'language=typescript' will be asynchronously loaded
* and transpiled.
*
* It requires typescriptServices.js and tslib.js to be present.
*
* If you want to be called back when all Typescripts have been loaded and transpiled
* add a function: globalThis.onTypescriptsLoaded(boolean).
*
* @author Ikaros Kappler
* @date 2020-03-18
* @version 1.0.0
**/
(function(_context) {
// Expose the runner to the global context
_context.TSRunner = _context.TSRunner || function( onTypescriptsLoaded, onTypescriptsCompiled, onTypescriptsExecuted, concatCodes ) {
// Register a pseudo-hidden global callback.
// The callback will be appended to the end of the transpiled JS code.
var callbackName = 'tsRunner_'+Math.floor(Math.random()*65535)+'_callback';
globalThis[callbackName] = onTypescriptsExecuted;
/**
* Request to load the given resource (specified by 'path', relative or absolute)
* with an asynchronous XHR request.
*
* @param {string} path - The resoruce's path. Should be a text file.
* @param {function(string)} success - A success callback (accepting the file contents as a string).
* @param {function(number)} reject - A failure callback (accepting the error code).
* @return {void}
**/
var requestResource = function(path,success,reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', path);
xhr.onload = function() {
if (xhr.status === 200)
success(xhr.responseText);
else
reject(xhr.status);
};
xhr.send();
};
/**
* Transpile a batch of loaded Typescript codes.
*
* Each successfully transpiled code (result is a JS code) will be attached to the
* DOM's header as a <script> tag.
*
* @param {Array<string>} tsCodes - The actual ts codes in an array.
* @param {Array<string>} pathNames - The resource names; used for proper error messages.
* @return {number} errorCount
**/
var transpileCodes = function( tsCodes, pathNames ) {
const head = document.getElementsByTagName('head')[0];
const jsCodes = [];
var errorCount = 0;
for( var i = 0; i < tsCodes.length; i++ ) {
try {
let jsCode = globalThis.ts.transpile(tsCodes[i]);
if( !concatCodes ) {
var scriptNode = document.createElement('script');
scriptNode.setAttribute('id','ts-transpiled-'+i);
scriptNode.innerHTML = jsCode;
head.appendChild(scriptNode);
console.log( jsCode );
}
jsCodes[i] = jsCode;
} catch( e ) {
errorCount++;
console.warn("Failed to transpile code "+i+" ("+pathNames[i]+")");
console.error(e);
onTypescriptsCompiled(false);
}
}
onTypescriptsCompiled(true);
if( concatCodes ) {
var scriptNode = document.createElement('script');
scriptNode.setAttribute('id','ts-transpiled-concat');
var finalCode =
jsCodes.join(' ') +
"globalThis."+callbackName+"("+(errorCount==0)+")";
scriptNode.innerHTML = finalCode;
head.appendChild(scriptNode);
}
return errorCount;
};
/**
* This triggers the process.
**/
this.processTypescript = function() {
var scriptNodes = document.querySelectorAll('script[language=typescript]');
var resourcesLoaded = 0;
var tsCodes = new Array(scriptNodes.length);
var pathNames = new Array(scriptNodes.length);
var checkComplete = function() {
// If all n resources have been loaded, transpile them
// in exact the original order.
if( resourcesLoaded == scriptNodes.length ) {
var errorCount = transpileCodes( tsCodes, pathNames );
if( typeof onTypescriptsLoaded === "function" )
onTypescriptsLoaded(errorCount==0);
}
};
// Handle all typescripts
for( var i = 0; i < scriptNodes.length; i++ ) {
var src = scriptNodes[i].getAttribute('src');
if( src == null || typeof src === "undefined" ) {
// This is an inline-script
pathNames[i] = "[inline]";
tsCodes[i] = scriptNodes[i].innerHTML;
resourcesLoaded++;
checkComplete();
} else {
// This is a remote resource
pathNames[i] = src;
// Call this inside a closure to avoid collisions.
(function(path,index) {
requestResource( path,
function(result) {
// Resource has been loaded.
tsCodes[index] = result;
resourcesLoaded++;
checkComplete();
},
function(errorCode) {
console.warn("Failed to load source '"+path+"'. Error code "+errorCode+".")
}
);
})(src,i);
}
}
}
}; // END constructor
}(globalThis ? globalThis : module.exports));