Commit 480b6d77 authored by Robert Knight's avatar Robert Knight

Generate `.d.ts` files as part of the frontend-shared package

Generate TypeScript definition files as part of the frontend-shared
package so that TS can typecheck code that uses the package in other
projects. Within the client repository we don't need to generate these files
because TypeScript will read the JSDoc comments. When the package is
consumed from other projects however, it seems that it does not read the
JSDoc comments. Note that when these `.d.ts` files exist, they are used in preference
to JSDoc comments by other code in the client repository. Therefore they
need to be kept up to date when the files are recompiled in watch mode.

In the process of adding this I discovered an issue that the method of
running CLI commands in gulp tasks in `scripts/gulp/frontend-shared.js` did not
fail if the exit status was non-zero. I created a `run` utility that
handles this correctly along with providing the desired defaults.
parent 898e61b8
...@@ -17,6 +17,7 @@ const createBundle = require('./scripts/gulp/create-bundle'); ...@@ -17,6 +17,7 @@ const createBundle = require('./scripts/gulp/create-bundle');
const createStyleBundle = require('./scripts/gulp/create-style-bundle'); const createStyleBundle = require('./scripts/gulp/create-style-bundle');
const { const {
buildFrontendSharedJs, buildFrontendSharedJs,
buildFrontendSharedTypes,
linkFrontendShared, linkFrontendShared,
} = require('./scripts/gulp/frontend-shared'); } = require('./scripts/gulp/frontend-shared');
const manifest = require('./scripts/gulp/manifest'); const manifest = require('./scripts/gulp/manifest');
...@@ -137,7 +138,10 @@ gulp.task( ...@@ -137,7 +138,10 @@ gulp.task(
}) })
); );
gulp.task('build-frontend-shared-js', buildFrontendSharedJs); gulp.task(
'build-frontend-shared-js',
gulp.parallel(buildFrontendSharedJs, buildFrontendSharedTypes)
);
gulp.task('link-frontend-shared', linkFrontendShared); gulp.task('link-frontend-shared', linkFrontendShared);
...@@ -147,7 +151,10 @@ gulp.task( ...@@ -147,7 +151,10 @@ gulp.task(
); );
gulp.task('watch-frontend-shared', () => { gulp.task('watch-frontend-shared', () => {
gulp.watch('./frontend-shared/src/**', gulp.series(buildFrontendSharedJs)); gulp.watch(
'./frontend-shared/src/**',
gulp.series('build-frontend-shared-js')
);
}); });
gulp.task( gulp.task(
......
'use strict'; 'use strict';
const cp = require('child_process');
const fs = require('fs'); const fs = require('fs');
const gulp = require('gulp'); const gulp = require('gulp');
const babel = require('gulp-babel'); const babel = require('gulp-babel');
const sourcemaps = require('gulp-sourcemaps'); const sourcemaps = require('gulp-sourcemaps');
const { run } = require('./run');
const buildFrontendSharedJs = () => { const buildFrontendSharedJs = () => {
// There does not appear to be a simple way of forcing gulp-babel to use a config // There does not appear to be a simple way of forcing gulp-babel to use a config
// file. Load it up as JSON and pass it in manually. // file. Load it up as JSON and pass it in manually.
...@@ -25,22 +27,29 @@ const buildFrontendSharedJs = () => { ...@@ -25,22 +27,29 @@ const buildFrontendSharedJs = () => {
); );
}; };
const linkFrontendShared = done => { const buildFrontendSharedTypes = async () => {
// Setup a symlink from the client to the frontend-shared package. // nb. If the options get significantly more complex, they should be moved to
cp.spawn('yarn', ['link'], { // a `tsconfig.json` file.
env: process.env, await run('node_modules/.bin/tsc', [
cwd: './frontend-shared', '--allowJs',
}).on('exit', () => { '--declaration',
cp.spawn('yarn', ['link', '@hypothesis/frontend-shared'], { '--emitDeclarationOnly',
env: process.env, '--outDir',
stdio: 'inherit', 'frontend-shared/lib',
}).on('exit', () => { 'frontend-shared/src/index.js',
done(); ]);
}); };
});
const linkFrontendShared = async () => {
// Make @hypothesis/frontend-shared available for linking in other projects.
await run('yarn', ['link'], { cwd: './frontend-shared' });
// Link it in the parent `client` repo.
await run('yarn', ['link', '@hypothesis/frontend-shared']);
}; };
module.exports = { module.exports = {
buildFrontendSharedJs, buildFrontendSharedJs,
buildFrontendSharedTypes,
linkFrontendShared, linkFrontendShared,
}; };
'use strict';
const { spawn } = require('child_process');
/**
* Run a command and return a promise for when it completes.
*
* Output and environment is forwarded as if running a CLI command in the terminal
* or make.
*
* This function is useful for running CLI tools as part of a gulp command.
*
* @param {string} cmd - Command to run
* @param {string[]} args - Command arguments
* @param {object} options - Options to forward to `spawn`
* @return {Promise<void>}
*/
function run(cmd, args, options = {}) {
return new Promise((resolve, reject) => {
spawn(cmd, args, { env: process.env, stdio: 'inherit', ...options }).on(
'exit',
code => {
if (code === 0) {
resolve();
} else {
reject(new Error(`${cmd} exited with status ${code}`));
}
}
);
});
}
module.exports = { run };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment