|
#!/bin/bash |
|
# |
|
# Task wrapper. Runs various chores in a cross platform manner. |
|
# |
|
# Usage: run [-h] <command> |
|
# |
|
# Available commands are: |
|
# build: Build the project |
|
# <other>: Run any other command available in the NPM path |
|
# |
|
# Options: |
|
# -h, --help Show this help and exit |
|
|
|
################################################################################ |
|
# Automatic configuration |
|
################################################################################ |
|
|
|
TSC_CMD=tsc |
|
BABEL_CMD=babel |
|
PATH=./node_modules/.bin:$PATH |
|
IS_WINDOWS=false |
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
|
SCRIPT_DIR_LEN=${#SCRIPT_DIR} |
|
|
|
# check if we're operating under windows (under mingw / git bash) |
|
# on windows, the symlinked script files have an obnoxious .cmd file extension. |
|
if [[ $(uname) == MINGW* ]]; then |
|
IS_WINDOWS=true |
|
TSC_CMD=tsc.cmd |
|
BABEL_CMD=babel.cmd |
|
fi |
|
|
|
################################################################################ |
|
# Build scripts |
|
################################################################################ |
|
|
|
# Typescript wrapper |
|
# |
|
# Typescript 2 ships with a flag to emit compiled files to stdout |
|
# (`-listEmittedFiles`). This makes it possible to convert the emitted |
|
# files from ES7+ to ES5 using, for example, the babel transpiler. |
|
# |
|
# The problem, however, is that these emitted files may be mangled with |
|
# other output of the compiler, since it emits everything to the same fd. |
|
# This script contains a `tsc` wrapper (`_tsc`) that addresses this issue |
|
# by filtering out the lines that describe an emitted file and those that |
|
# do not and re-emitting them to stdout and stderr respectively. Further, |
|
# it emits "sets" of changed files, not just single files which is help- |
|
# ful, for example, in the case of babel which seems to perform much better |
|
# given multiple files in one go, rather than performing a cold start for |
|
# each. It does so by interspering a null-byte after each set of files: |
|
# |
|
# file 1\nfile2\nfile3\n\0file4\nfile |
|
# |
|
# This script has been tested to run on git-bash under Windows as well as |
|
# Bash 3 on OSX (default). |
|
function _tsc { |
|
local IFS=$'\n' |
|
$TSC_CMD "$@" --listEmittedFiles | awk ' |
|
function flush() { |
|
if (files != "") { |
|
printf "%s%c", files, 0 |
|
files = "" |
|
} |
|
fflush() |
|
} |
|
|
|
BEGIN { files = "" } |
|
|
|
/.*Compilation complete.*/ { |
|
print $0 > "/dev/stderr" |
|
flush() |
|
next |
|
} |
|
|
|
/^TSFILE:.*\.js$/ { |
|
if (files != "") { |
|
files = files "\n" |
|
} |
|
files = files substr($0, 9) |
|
} |
|
|
|
{ print $0 > "/dev/stderr" } |
|
|
|
END { flush() } |
|
' |
|
} |
|
|
|
# Read filepaths on stdin and remove their common leading path to the root of |
|
# the project, taking into account Windows pathing. |
|
function mk_relpath { |
|
while IFS=$'\n' read -r file; do |
|
if $IS_WINDOWS; then |
|
file=/$(echo "$file" | sed 's/\\/\//g' | sed 's/://') |
|
fi |
|
eval "echo .${file:$SCRIPT_DIR_LEN}" |
|
done |
|
} |
|
|
|
# Build the project from start to finish. All typescript source files are |
|
# compiled and the output is run through the babel compiler: |
|
# |
|
# Typescript -> ES6 -> Babel -> ES5 |
|
# |
|
# Any adhoc options are passed to the typescript compiler only. Configure babel |
|
# behavior using the .babelrc file. Likewise, prefer tsconfig.json to configure |
|
# typescript and only use the adhoc options for e.g. watching (-w|--watch). |
|
function build { |
|
local IFS=$'\n' |
|
local -r outdir=$SCRIPT_DIR |
|
local relfiles |
|
|
|
_tsc "$@" |\ |
|
while read -d '' -r files; do |
|
relfiles=($(mk_relpath <<< "$files")) |
|
echo >&2 "babel: compiling ${#relfiles[@]} files" |
|
"$BABEL_CMD" >&2 --out-dir "$outdir" "${relfiles[@]}" |
|
done |
|
} |
|
|
|
################################################################################ |
|
# Command line interface |
|
################################################################################ |
|
|
|
# derive the help text from the first comment in a shell script |
|
function derive_help { |
|
awk ' |
|
f && !NF { exit } |
|
/^#/ && NR>2 { f=1; sub("^# ?", "", $0); print $0 } |
|
' < "$1" |
|
} |
|
|
|
# print the help text, derived from this file |
|
function help { |
|
derive_help "${BASH_SOURCE[0]}" |
|
} |
|
|
|
case "${1:-build}" in |
|
-h|--help) help ;; |
|
build) shift; build "$@" ;; |
|
-*) echo >&2 "unknown option: $1"; exit 1 ;; |
|
*) cmd=$1; shift; "$cmd" "$@"; ;; |
|
esac |