Skip to content

Commit 9afd744

Browse files
committed
chore: add script to build typescript project references
1 parent ec37f2f commit 9afd744

File tree

3 files changed

+140
-5
lines changed

3 files changed

+140
-5
lines changed

bin/update-project-refs.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env node
2+
// Copyright IBM Corp. 2017,2018. All Rights Reserved.
3+
// Node module: loopback-next
4+
// This file is licensed under the MIT License.
5+
// License text available at https://opensource.org/licenses/MIT
6+
7+
/**
8+
* This is an internal script to update TypeScript project references based on
9+
* lerna's local package dependencies.
10+
*
11+
* See https://www.typescriptlang.org/docs/handbook/project-references.html
12+
*/
13+
'use strict';
14+
15+
const path = require('path');
16+
const fs = require('fs');
17+
const buildUtils = require('../packages/build/bin/utils');
18+
19+
const Project = require('@lerna/project');
20+
const PackageGraph = require('@lerna/package-graph');
21+
22+
const TSCONFIG = 'tsconfig.build.json';
23+
24+
async function updateReferences() {
25+
const project = new Project(process.cwd());
26+
const packages = await project.getPackages();
27+
28+
const rootRefs = [];
29+
const graph = new PackageGraph(packages);
30+
31+
for (const p of graph.values()) {
32+
console.log('Package %s', p.pkg.name);
33+
const pkgLocation = p.pkg.location;
34+
const tsconfigFile = path.join(pkgLocation, TSCONFIG);
35+
// Skip non-typescript packages
36+
if (!fs.existsSync(tsconfigFile)) continue;
37+
rootRefs.push({
38+
path: path.join(
39+
path.relative(project.rootPath, pkgLocation),
40+
'tsconfig.build.json',
41+
),
42+
});
43+
const tsconfig = require(tsconfigFile);
44+
const refs = [];
45+
for (const d of p.localDependencies.keys()) {
46+
const depPkg = graph.get(d);
47+
// Skip non-typescript packages
48+
if (!fs.existsSync(path.join(depPkg.pkg.location, 'tsconfig.build.json')))
49+
continue;
50+
const relativePath = path.relative(pkgLocation, depPkg.pkg.location);
51+
refs.push({path: path.join(relativePath, 'tsconfig.build.json')});
52+
}
53+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
54+
tsconfig.compilerOptions.composite = true;
55+
tsconfig.compilerOptions.target =
56+
tsconfig.compilerOptions.target || buildUtils.getCompilationTarget();
57+
tsconfig.compilerOptions.outDir =
58+
tsconfig.compilerOptions.outDir ||
59+
buildUtils.getDistribution(tsconfig.compilerOptions.target);
60+
tsconfig.references = refs;
61+
62+
// Convert to JSON
63+
const tsconfigJson = JSON.stringify(tsconfig, null, 2);
64+
65+
if (process.argv[2] === '-f') {
66+
// Using `-f` to overwrite tsconfig.build.json
67+
fs.writeFileSync(tsconfigFile, tsconfigJson + '\n', {encoding: 'utf-8'});
68+
console.log('%s has been updated.', tsconfigFile);
69+
} else {
70+
// Otherwise write to console
71+
console.log(tsconfigJson);
72+
}
73+
}
74+
75+
const rootTsconfigFile = path.join(project.rootPath, 'tsconfig.json');
76+
const rootTsconfig = require(rootTsconfigFile);
77+
rootTsconfig.compilerOptions = rootTsconfig.compilerOptions || {};
78+
rootTsconfig.compilerOptions.composite = true;
79+
rootTsconfig.references = rootRefs;
80+
// Convert to JSON
81+
const rootTsconfigJson = JSON.stringify(rootTsconfig, null, 2);
82+
if (process.argv[2] === '-f') {
83+
// Using `-f` to overwrite tsconfig.build.json
84+
fs.writeFileSync(rootTsconfigFile, rootTsconfigJson + '\n', {
85+
encoding: 'utf-8',
86+
});
87+
console.log('%s has been updated.', rootTsconfigFile);
88+
} else {
89+
console.log(rootTsconfigJson);
90+
}
91+
}
92+
93+
if (require.main === module) updateReferences();

packages/build/bin/compile-package.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ function run(argv, options) {
2424
const glob = require('glob');
2525
const fse = require('fs-extra');
2626

27+
if (options === true) {
28+
options = {dryRun: true};
29+
} else {
30+
options = options || {};
31+
}
32+
2733
const packageDir = utils.getPackageDir();
2834

2935
const compilerOpts = argv.slice(2);
@@ -36,6 +42,11 @@ function run(argv, options) {
3642
'--ignore-resources',
3743
);
3844

45+
// Honor --dry from tsc
46+
if (utils.isOptionSet(compilerOpts, '--dry')) {
47+
options.dryRun = true;
48+
}
49+
3950
var target;
4051

4152
// --ignore-resources is not a TS Compiler option so we remove it from the
@@ -126,7 +137,7 @@ function run(argv, options) {
126137
// Since outDir is set, ts files are compiled into that directory.
127138
// If ignore-resources flag is not passed, copy resources (non-ts files)
128139
// to the same outDir as well.
129-
if (rootDir && tsConfigFile && !isIgnoreResourcesSet) {
140+
if (rootDir && tsConfigFile && !isIgnoreResourcesSet && !options.dryRun) {
130141
const tsConfig = require(tsConfigFile);
131142
const dirs = tsConfig.include
132143
? tsConfig.include.join('|')
@@ -146,11 +157,21 @@ function run(argv, options) {
146157

147158
args.push(...compilerOpts);
148159

149-
if (options === true) {
150-
options = {dryRun: true};
151-
} else {
152-
options = options || {};
160+
// Move --build or -b as the 1st argument to avoid:
161+
// error TS6369: Option '--build' must be the first command line argument.
162+
const buildOptions = utils.removeOptions(args, '-b', '--build');
163+
if (buildOptions.length) {
164+
let projectOptions = utils.removeOptions(args, '-p', '--project');
165+
projectOptions = projectOptions.filter(p => !p.startsWith('-'));
166+
// Remove conflict options with '--build'
167+
utils.removeOptions(args, '--outDir', '--target');
168+
if (buildOptions.length === 1) {
169+
args.unshift(...buildOptions, ...projectOptions);
170+
} else {
171+
args.unshift(...buildOptions);
172+
}
153173
}
174+
154175
return utils.runCLI('typescript/lib/tsc', args, {cwd, ...options});
155176
}
156177

packages/build/bin/utils.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,26 @@ function isOptionSet(opts, ...optionNames) {
194194
);
195195
}
196196

197+
/**
198+
* Remove options and their values from args
199+
*/
200+
function removeOptions(args, ...options) {
201+
const removed = [];
202+
for (const e of options) {
203+
const index = args.indexOf(e);
204+
if (index !== -1) {
205+
const next = args[index + 1];
206+
if (typeof next === 'string' && !next.startsWith('-')) {
207+
// The next element is the value of the option, remove it too
208+
removed.push(...args.splice(index, 2));
209+
} else {
210+
removed.push(...args.splice(index, 1));
211+
}
212+
}
213+
}
214+
return removed;
215+
}
216+
197217
exports.getCompilationTarget = getCompilationTarget;
198218
exports.getDistribution = getDistribution;
199219
exports.getRootDir = getRootDir;
@@ -203,3 +223,4 @@ exports.resolveCLI = resolveCLI;
203223
exports.runCLI = runCLI;
204224
exports.runShell = runShell;
205225
exports.isOptionSet = isOptionSet;
226+
exports.removeOptions = removeOptions;

0 commit comments

Comments
 (0)