angular-cli/lib/bootstrap-local.js
alkavats1 28721c3e64 refactor(@angular/cli): improved code quality
removed unused parameter and improved code quality
2022-03-30 17:17:27 +02:00

159 lines
5.5 KiB
JavaScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/* eslint-disable no-console */
'use strict';
const debug = require('debug');
const debugLocal = debug('ng:local');
const debugBuildEjs = debug('ng:local:build:ejs');
const debugBuildSchema = debug('ng:local:build:schema');
const debugBuildTs = debug('ng:local:build:ts');
const child_process = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const ts = require('typescript');
const tmpRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'angular-devkit-'));
debugLocal('starting bootstrap local');
// This processes any extended configs
const compilerOptions = ts.getParsedCommandLineOfConfigFile(
path.join(__dirname, '../tsconfig-test.json'),
{},
ts.sys,
).options;
if (process.env['DEVKIT_LONG_STACK_TRACE']) {
debugLocal('setup long stack trace');
Error.stackTraceLimit = Infinity;
}
global._DevKitIsLocal = true;
global._DevKitRoot = path.resolve(__dirname, '..');
const oldRequireTs = require.extensions['.ts'];
require.extensions['.ts'] = function (m, filename) {
// If we're in node module, either call the old hook or simply compile the
// file without transpilation. We do not touch node_modules/**.
// To account for Yarn workspaces symlinks, we much check the real path.
if (fs.realpathSync(filename).match(/node_modules/)) {
if (oldRequireTs) {
return oldRequireTs(m, filename);
}
return m._compile(fs.readFileSync(filename).toString(), filename);
}
debugBuildTs(filename);
// Node requires all require hooks to be sync.
const source = fs.readFileSync(filename).toString();
try {
let result = ts.transpile(source, compilerOptions, filename);
debugBuildTs('done');
// Send it to node to execute.
return m._compile(result, filename);
} catch (err) {
console.error('Error while running script "' + filename + '":');
console.error(err.stack);
throw err;
}
};
require.extensions['.ejs'] = function (m, filename) {
debugBuildEjs(filename);
const source = fs.readFileSync(filename).toString();
const template = require('@angular-devkit/core').template;
const result = template(source, { sourceURL: filename, sourceMap: true });
debugBuildEjs('done');
return m._compile(result.source.replace(/return/, 'module.exports.default = '), filename);
};
const builtinModules = Object.keys(process.binding('natives'));
const packages = require('./packages').packages;
// If we're running locally, meaning npm linked. This is basically "developer mode".
if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) {
// We mock the module loader so that we can fake our packages when running locally.
const Module = require('module');
const oldResolve = Module._resolveFilename;
Module._resolveFilename = function (request, parent) {
let resolved = null;
let exception;
try {
resolved = oldResolve.call(this, request, parent);
} catch (e) {
exception = e;
}
if (request in packages) {
return packages[request].main;
} else if (builtinModules.includes(request)) {
// It's a native Node module.
return oldResolve.call(this, request, parent);
} else if (resolved && resolved.match(/[\\\/]node_modules[\\\/]/)) {
return resolved;
} else {
const match = Object.keys(packages).find((pkgName) => request.startsWith(pkgName + '/'));
if (match) {
const p = path.join(packages[match].root, request.slice(match.length));
return oldResolve.call(this, p, parent);
} else if (!resolved) {
if (exception) {
throw exception;
} else {
return resolved;
}
} else {
// Because loading `.ts` ends up AFTER `.json` in the require() logic, requiring a file that has both `.json`
// and `.ts` versions will only get the `.json` content (which wouldn't happen if the .ts was compiled to
// JavaScript). We load `.ts` files first here to avoid this conflict. It's hacky, but so is the rest of this
// file.
const maybeTsPath = resolved.endsWith('.json') && resolved.replace(/\.json$/, '.ts');
if (maybeTsPath && !request.endsWith('.json')) {
// If the file exists, return its path. If it doesn't, run the quicktype runner on it and return the content.
if (fs.existsSync(maybeTsPath)) {
return maybeTsPath;
} else {
debugBuildSchema('%s', resolved);
// This script has the be synchronous, so we spawnSync instead of, say, requiring the runner and calling
// the method directly.
const tmpJsonSchemaPath = path.join(
tmpRoot,
maybeTsPath.replace(/[^0-9a-zA-Z.]/g, '_'),
);
try {
if (!fs.existsSync(tmpJsonSchemaPath)) {
const quicktypeRunnerPath = path.join(__dirname, '../tools/quicktype_runner.js');
child_process.spawnSync('node', [quicktypeRunnerPath, resolved, tmpJsonSchemaPath]);
}
debugBuildSchema('done');
return tmpJsonSchemaPath;
} catch (_) {
// Just return resolvedPath and let Node deals with it.
console.log(_);
process.exit(99);
}
}
}
return resolved;
}
}
};
}