feat(dev-infra): register ts-node when reading configuration (#37196)
`ts-node` is now an optional peer dependency of the shared dev-infra package. Whenever a `ng-dev` command runs, and a TypeScript-based configuration file exists, `ts-node` is set up if available. That allows consumers of the package (as the components repo) to more conveniently use a TypeScript-based configuration for dev-infra. Currently, commands would need to be proxied through `ts-node` which rather complicates the setup: ``` NG_DEV_COMMAND="ts-node ./node_modules/@angular/dev-infra-private/cli.js" ``` I'm thinking that it should be best-practice to use TypeScript for writing the configuration files. Given that the tool is used primarily in Angular projects (for which most sources are TypeScript), this should be acceptable. PR Close #37196
This commit is contained in:
parent
4e96cdc23f
commit
383f04b96d
|
@ -24,7 +24,13 @@
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@bazel/buildifier": "<from-root>",
|
"@bazel/buildifier": "<from-root>",
|
||||||
"clang-format": "<from-root>",
|
"clang-format": "<from-root>",
|
||||||
|
"ts-node": "<from-root>",
|
||||||
"tslib": "<from-root>",
|
"tslib": "<from-root>",
|
||||||
"typescript": "<from-root>"
|
"typescript": "<from-root>"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ts-node": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {existsSync} from 'fs';
|
||||||
import {join} from 'path';
|
import {join} from 'path';
|
||||||
import {exec} from 'shelljs';
|
import {exec} from 'shelljs';
|
||||||
|
import {isTsNodeAvailable} from './ts-node';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the Github configuration for dev-infra. This configuration is
|
* Describes the Github configuration for dev-infra. This configuration is
|
||||||
|
@ -41,17 +43,16 @@ const CONFIG_FILE_NAME = '.ng-dev-config';
|
||||||
let CONFIG: {}|null = null;
|
let CONFIG: {}|null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the configuration from the file system, returning the already loaded copy if it
|
* Get the configuration from the file system, returning the already loaded
|
||||||
* is defined.
|
* copy if it is defined.
|
||||||
*/
|
*/
|
||||||
export function getConfig(): NgDevConfig {
|
export function getConfig(): NgDevConfig {
|
||||||
// If the global config is not defined, load it from the file system.
|
// If the global config is not defined, load it from the file system.
|
||||||
if (CONFIG === null) {
|
if (CONFIG === null) {
|
||||||
// The full path to the configuration file.
|
// The full path to the configuration file.
|
||||||
const configPath = join(getRepoBaseDir(), CONFIG_FILE_NAME);
|
const configPath = join(getRepoBaseDir(), CONFIG_FILE_NAME);
|
||||||
// Set the global config object to a clone of the configuration loaded through default exports
|
// Set the global config object.
|
||||||
// from the config file.
|
CONFIG = readConfigFile(configPath);
|
||||||
CONFIG = {...require(configPath)};
|
|
||||||
}
|
}
|
||||||
// Return a clone of the global config to ensure that a new instance of the config is returned
|
// Return a clone of the global config to ensure that a new instance of the config is returned
|
||||||
// each time, preventing unexpected effects of modifications to the config object.
|
// each time, preventing unexpected effects of modifications to the config object.
|
||||||
|
@ -72,10 +73,28 @@ function validateCommonConfig(config: Partial<NgDevConfig>) {
|
||||||
errors.push(`"github.owner" is not defined`);
|
errors.push(`"github.owner" is not defined`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assertNoErrors(errors);
|
||||||
return config as NgDevConfig;
|
return config as NgDevConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolves and reads the specified configuration file. */
|
||||||
|
function readConfigFile(configPath: string): object {
|
||||||
|
// If the the `.ts` extension has not been set up already, and a TypeScript based
|
||||||
|
// version of the given configuration seems to exist, set up `ts-node` if available.
|
||||||
|
if (require.extensions['.ts'] === undefined && existsSync(`${configPath}.ts`) &&
|
||||||
|
isTsNodeAvailable()) {
|
||||||
|
require('ts-node').register({skipProject: true, transpileOnly: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return require(configPath)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Could not read configuration file.');
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts the provided array of error messages is empty. If any errors are in the array,
|
* Asserts the provided array of error messages is empty. If any errors are in the array,
|
||||||
* logs the errors and exit the process as a failure.
|
* logs the errors and exit the process as a failure.
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Whether ts-node has been installed and is available to ng-dev. */
|
||||||
|
export function isTsNodeAvailable(): boolean {
|
||||||
|
try {
|
||||||
|
require.resolve('ts-node');
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue