diff --git a/dev-infra/tmpl-package.json b/dev-infra/tmpl-package.json index e1ffd09573..5903d5f223 100644 --- a/dev-infra/tmpl-package.json +++ b/dev-infra/tmpl-package.json @@ -24,7 +24,13 @@ "peerDependencies": { "@bazel/buildifier": "", "clang-format": "", + "ts-node": "", "tslib": "", "typescript": "" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } } } diff --git a/dev-infra/utils/config.ts b/dev-infra/utils/config.ts index 260c5a7930..3c73301640 100644 --- a/dev-infra/utils/config.ts +++ b/dev-infra/utils/config.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import {existsSync} from 'fs'; import {join} from 'path'; import {exec} from 'shelljs'; +import {isTsNodeAvailable} from './ts-node'; /** * 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; /** - * Get the configuration from the file system, returning the already loaded copy if it - * is defined. + * Get the configuration from the file system, returning the already loaded + * copy if it is defined. */ export function getConfig(): NgDevConfig { // If the global config is not defined, load it from the file system. if (CONFIG === null) { // The full path to the configuration file. const configPath = join(getRepoBaseDir(), CONFIG_FILE_NAME); - // Set the global config object to a clone of the configuration loaded through default exports - // from the config file. - CONFIG = {...require(configPath)}; + // Set the global config object. + CONFIG = readConfigFile(configPath); } // 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. @@ -72,10 +73,28 @@ function validateCommonConfig(config: Partial) { errors.push(`"github.owner" is not defined`); } } - + assertNoErrors(errors); 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, * logs the errors and exit the process as a failure. diff --git a/dev-infra/utils/ts-node.ts b/dev-infra/utils/ts-node.ts new file mode 100644 index 0000000000..b21518ccfb --- /dev/null +++ b/dev-infra/utils/ts-node.ts @@ -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; + } +}