add websocket server to this dir. fix stuff for client

This commit is contained in:
2024-10-30 15:12:52 -05:00
parent f8152c6db8
commit 4886bc5b1f
3058 changed files with 1201180 additions and 2 deletions

View File

@ -0,0 +1,15 @@
/// <reference types="node" />
import { EventEmitter } from 'events';
export declare class TscWatchClient extends EventEmitter {
private tscWatchPath;
private tsc;
constructor(tscWatchPath?: string);
start(...args: string[]): void;
kill(): void;
runOnCompilationStartedCommand(): void;
runOnCompilationCompleteCommand(): void;
runOnFirstSuccessCommand(): void;
runOnFailureCommand(): void;
runOnSuccessCommand(): void;
runOnEmitCommand(): void;
}

View File

@ -0,0 +1,90 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TscWatchClient = void 0;
const path = __importStar(require("path"));
const child_process_1 = require("child_process");
const events_1 = require("events");
const tscWatchLibPath = path.join(__dirname, '..', 'lib', 'tsc-watch');
class TscWatchClient extends events_1.EventEmitter {
constructor(tscWatchPath = tscWatchLibPath) {
super();
this.tscWatchPath = tscWatchPath;
}
start(...args) {
const options = { stdio: 'inherit' };
this.tsc = (0, child_process_1.fork)(this.tscWatchPath, args, options);
this.tsc.on('message', (msg) => {
this.emit(...deserializeTscMessage(msg));
});
this.tsc.on('exit', (code, signal) => {
this.emit('exit', code, signal);
});
}
kill() {
if (this.tsc && this.tsc.kill) {
this.tsc.kill();
}
this.removeAllListeners();
}
runOnCompilationStartedCommand() {
if (this.tsc) {
this.tsc.send('run-on-compilation-started-command');
}
}
runOnCompilationCompleteCommand() {
if (this.tsc) {
this.tsc.send('run-on-compilation-complete-command');
}
}
runOnFirstSuccessCommand() {
if (this.tsc) {
this.tsc.send('run-on-first-success-command');
}
}
runOnFailureCommand() {
if (this.tsc) {
this.tsc.send('run-on-failure-command');
}
}
runOnSuccessCommand() {
if (this.tsc) {
this.tsc.send('run-on-success-command');
}
}
runOnEmitCommand() {
if (this.tsc) {
this.tsc.send('run-on-emit-command');
}
}
}
exports.TscWatchClient = TscWatchClient;
function deserializeTscMessage(strMsg) {
const indexOfSeparator = strMsg.indexOf(':');
if (indexOfSeparator === -1) {
return [strMsg];
}
return [strMsg.substring(0, indexOfSeparator), strMsg.substring(indexOfSeparator + 1)];
}

View File

@ -0,0 +1 @@
export * from './client';

View File

@ -0,0 +1,17 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./client"), exports);

View File

@ -0,0 +1 @@
"use strict";

View File

@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractArgs = exports.hasWatchCommand = exports.isCommandExist = void 0;
function removeRunnerArgs(args) {
return args.splice(2); // removing "node tsc-watch.js"
}
function getCommandIdx(args, command) {
const lowerCasedCommand = command.toLowerCase();
return args.map(arg => arg.toLowerCase()).indexOf(lowerCasedCommand);
}
function isCommandExist(args, command) {
return getCommandIdx(args, command) > 0;
}
exports.isCommandExist = isCommandExist;
function hasWatchCommand(args) {
return isCommandExist(args, '-w') || isCommandExist(args, '--watch');
}
exports.hasWatchCommand = hasWatchCommand;
function forceWatch(args) {
if (!hasWatchCommand(args)) {
args.push('--watch');
}
return args;
}
function extractCommandWithValue(args, command) {
let commandValue = null;
let commandIdx = getCommandIdx(args, command);
if (commandIdx > -1) {
commandValue = args[commandIdx + 1];
args.splice(commandIdx, 2);
}
return commandValue;
}
function extractCommand(args, command) {
let commandIdx = getCommandIdx(args, command);
if (commandIdx > -1) {
args.splice(commandIdx, 1);
return true;
}
return false;
}
function extractArgs(inputArgs) {
const args = forceWatch(removeRunnerArgs(inputArgs));
const onFirstSuccessCommand = extractCommandWithValue(args, '--onFirstSuccess');
const onSuccessCommand = extractCommandWithValue(args, '--onSuccess');
const onFailureCommand = extractCommandWithValue(args, '--onFailure');
const onEmitCommand = extractCommandWithValue(args, '--onEmit');
const onEmitDebounceMs = Number(extractCommandWithValue(args, '--onEmitDebounceMs')) || 300;
const onCompilationStarted = extractCommandWithValue(args, '--onCompilationStarted');
const onCompilationComplete = extractCommandWithValue(args, '--onCompilationComplete');
const maxNodeMem = extractCommandWithValue(args, '--maxNodeMem');
const noColors = extractCommand(args, '--noColors');
const noClear = extractCommand(args, '--noClear');
const silent = extractCommand(args, '--silent');
const signalEmittedFiles = extractCommand(args, '--signalEmittedFiles');
const requestedToListEmittedFiles = extractCommand(args, '--listEmittedFiles');
let compiler = extractCommandWithValue(args, '--compiler');
if (!compiler) {
compiler = 'typescript/bin/tsc';
}
else {
compiler = require.resolve(compiler, { paths: [process.cwd()] });
}
if (signalEmittedFiles || requestedToListEmittedFiles) {
if (args[0] === '--build' || args[0] === '-b') {
// TS6369: Option '--build' must be the first command line argument.
args.splice(1, 0, '--listEmittedFiles');
}
else {
args.unshift('--listEmittedFiles');
}
}
return {
onFirstSuccessCommand,
onSuccessCommand,
onFailureCommand,
onEmitCommand,
onEmitDebounceMs,
onCompilationStarted,
onCompilationComplete,
maxNodeMem,
noColors,
noClear,
requestedToListEmittedFiles,
signalEmittedFiles,
silent,
compiler,
args,
};
}
exports.extractArgs = extractArgs;

View File

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.debounce = void 0;
function debounce(fn, delay = 300) {
let timer;
return (...args) => {
timer && clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
exports.debounce = debounce;

View File

@ -0,0 +1,38 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.kill = void 0;
const ps_tree_1 = __importDefault(require("ps-tree"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const child_process_1 = require("child_process");
let KILL_SIGNAL = '15'; // SIGTERM
let hasPS = true;
const isWindows = process.platform === 'win32';
// discover if the OS has `ps`, and therefore can use psTree
(0, child_process_1.exec)('ps', function (error) {
if (error) {
hasPS = false;
}
});
function kill(child) {
return new Promise((resolve) => {
if (isWindows) {
(0, child_process_1.exec)(`taskkill /pid ${child.pid} /T /F`, () => resolve());
}
else {
if (hasPS) {
(0, ps_tree_1.default)(child.pid, (err, kids) => {
const kidsPIDs = kids.map((p) => p.PID);
const args = [`-${KILL_SIGNAL}`, child.pid.toString(), ...kidsPIDs];
(0, cross_spawn_1.default)('kill', args).on('close', resolve);
});
}
else {
(0, child_process_1.exec)(`kill -${KILL_SIGNAL} ${child.pid}`, () => resolve());
}
}
});
}
exports.kill = kill;

View File

@ -0,0 +1,23 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const string_argv_1 = __importDefault(require("string-argv"));
const killer_1 = require("./killer");
function runCommand(fullCommand) {
const parts = (0, string_argv_1.default)(fullCommand);
const exec = parts[0];
const args = parts.splice(1);
return (0, cross_spawn_1.default)(exec, args, {
stdio: 'inherit',
});
}
function run(command) {
const process = runCommand(command);
const exitPromise = new Promise((resolve) => process.on('exit', resolve));
return () => Promise.all([(0, killer_1.kill)(process), exitPromise]);
}
exports.run = run;

View File

@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectState = exports.manipulate = exports.deleteClear = exports.print = void 0;
const ANSI_REGEX = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))', 'g');
const stripAnsi = (str) => str.replace(ANSI_REGEX, '');
const tscUsageSyntaxRegex = / -w, --watch.*Watch input files\./;
const typescriptPrettyErrorRegex = /:\d+:\d+ \- error TS\d+: /;
const typescriptErrorRegex = /\(\d+,\d+\): error TS\d+: /;
const typescriptEmittedFileRegex = /(TSFILE:)\s*(.*)/;
const compilationCompleteWithErrorRegex = / Found [^0][0-9]* error[s]?\. Watching for file changes\./;
const compilationCompleteWithoutErrorRegex = / Found 0 errors\. Watching for file changes\./;
const compilationCompleteRegex = /( Compilation complete\. Watching for file changes\.| Found \d+ error[s]?\. Watching for file changes\.)/;
const compilationStartedRegex = /( Starting compilation in watch mode\.\.\.| File change detected\. Starting incremental compilation\.\.\.)/;
const newAdditionToSyntax = [
' -w, --watch Watch input files. [always on]',
' --onSuccess COMMAND Executes `COMMAND` on **every successful** compilation.',
' --onFirstSuccess COMMAND Executes `COMMAND` on the **first successful** compilation.',
' --onFailure COMMAND Executes `COMMAND` on **every failed** compilation.',
' --onEmit COMMAND Executes debounced `COMMAND` on **every emitted file**, ignoring unchanged files and disregards compilation success or failure.',
' --onEmitDebounceMs DELAY Delay by which to debounce `--onEmit` (default: 300).',
' --onCompilationStarted COMMAND Executes `COMMAND` on **every compilation start** event.',
' --onCompilationComplete COMMAND Executes `COMMAND` on **every successful or failed** compilation.',
' --noColors Removes the red/green colors from the compiler output',
' --noClear Prevents the compiler from clearing the screen',
' --compiler PATH The PATH will be used instead of typescript compiler. Defaults typescript/bin/tsc.',
].join('\n');
function color(line, noClear = false) {
// coloring errors:
line = line.replace(typescriptErrorRegex, (m) => `\u001B[36m${m}\u001B[39m`); // Cyan
line = line.replace(typescriptPrettyErrorRegex, (m) => `\u001B[36m${m}\u001B[39m`); // Cyan
// completed with error:
line = line.replace(compilationCompleteWithErrorRegex, (m) => `\u001B[31m${m}\u001B[39m`); // Red
// completed without error:
line = line.replace(compilationCompleteWithoutErrorRegex, (m) => `\u001B[32m${m}\u001B[39m`); // Green
// usage
line = line.replace(tscUsageSyntaxRegex, (m) => `\u001B[33m${m}\u001B[39m`); // Yellow
if (noClear && compilationStartedRegex.test(line)) {
return '\n\n----------------------\n' + line;
}
return line;
}
function print(line, { noColors = false, noClear = false, requestedToListEmittedFiles = false, signalEmittedFiles = false, } = {}) {
if (signalEmittedFiles && !requestedToListEmittedFiles && line.startsWith('TSFILE:')) {
return;
}
console.log(noColors ? line : color(line, noClear));
}
exports.print = print;
function deleteClear(line) {
const buffer = Buffer.from(line);
if (buffer.length >= 2 && buffer[0] === 0x1b && buffer[1] === 0x63) {
return line.substr(2);
}
return line;
}
exports.deleteClear = deleteClear;
function manipulate(line) {
return line.replace(tscUsageSyntaxRegex, newAdditionToSyntax);
}
exports.manipulate = manipulate;
function detectState(line) {
const clearLine = stripAnsi(line);
const compilationStarted = compilationStartedRegex.test(clearLine);
const compilationError = compilationCompleteWithErrorRegex.test(clearLine) ||
typescriptErrorRegex.test(clearLine) ||
typescriptPrettyErrorRegex.test(clearLine);
const compilationComplete = compilationCompleteRegex.test(clearLine);
const fileEmittedExec = typescriptEmittedFileRegex.exec(clearLine);
const fileEmitted = fileEmittedExec !== null ? fileEmittedExec[2] : null; // if the regex is not null it will return an array with 3 elements
return {
compilationStarted,
compilationError,
compilationComplete,
fileEmitted,
};
}
exports.detectState = detectState;

View File

@ -0,0 +1,280 @@
#!/usr/bin/env node
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_cleanup_1 = __importStar(require("node-cleanup"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const runner_1 = require("./runner");
const args_manager_1 = require("./args-manager");
const debounce_1 = require("./debounce");
const stdout_manipulator_1 = require("./stdout-manipulator");
const readline_1 = require("readline");
let firstTime = true;
let firstSuccessKiller = null;
let successKiller = null;
let failureKiller = null;
let emitKiller = null;
let compilationStartedKiller = null;
let compilationCompleteKiller = null;
const { onFirstSuccessCommand, onSuccessCommand, onFailureCommand, onEmitCommand, onEmitDebounceMs, onCompilationStarted, onCompilationComplete, maxNodeMem, noColors, noClear, requestedToListEmittedFiles, signalEmittedFiles, silent, compiler, args, } = (0, args_manager_1.extractArgs)(process.argv);
let runningKillProcessesPromise = null;
function killProcesses(currentCompilationId, killAll) {
if (runningKillProcessesPromise) {
return runningKillProcessesPromise.then(() => currentCompilationId);
}
const promisesToWaitFor = [];
if (killAll && firstSuccessKiller) {
promisesToWaitFor.push(firstSuccessKiller());
firstSuccessKiller = null;
}
if (successKiller) {
promisesToWaitFor.push(successKiller());
successKiller = null;
}
if (failureKiller) {
promisesToWaitFor.push(failureKiller());
failureKiller = null;
}
if (compilationStartedKiller) {
promisesToWaitFor.push(compilationStartedKiller());
compilationStartedKiller = null;
}
if (compilationCompleteKiller) {
promisesToWaitFor.push(compilationCompleteKiller());
compilationCompleteKiller = null;
}
runningKillProcessesPromise = Promise.all(promisesToWaitFor).then(() => {
runningKillProcessesPromise = null;
return currentCompilationId;
});
return runningKillProcessesPromise;
}
let runningKillEmitProcessesPromise = null;
// The same as `killProcesses`, but we separate it to avoid canceling each other
function killEmitProcesses(currentEmitId) {
if (runningKillEmitProcessesPromise) {
return runningKillEmitProcessesPromise.then(() => currentEmitId);
}
let emitKilled = Promise.resolve();
if (emitKiller) {
emitKilled = emitKiller();
emitKiller = null;
}
runningKillEmitProcessesPromise = emitKilled.then(() => {
runningKillEmitProcessesPromise = null;
return currentEmitId;
});
return runningKillEmitProcessesPromise;
}
function runOnCompilationStarted() {
if (onCompilationStarted) {
compilationStartedKiller = (0, runner_1.run)(onCompilationStarted);
}
}
function runOnCompilationComplete() {
if (onCompilationComplete) {
compilationCompleteKiller = (0, runner_1.run)(onCompilationComplete);
}
}
function runOnFailureCommand() {
if (onFailureCommand) {
failureKiller = (0, runner_1.run)(onFailureCommand);
}
}
function runOnFirstSuccessCommand() {
if (onFirstSuccessCommand) {
firstSuccessKiller = (0, runner_1.run)(onFirstSuccessCommand);
}
}
function runOnSuccessCommand() {
if (onSuccessCommand) {
successKiller = (0, runner_1.run)(onSuccessCommand);
}
}
const debouncedEmit = onEmitCommand
? (0, debounce_1.debounce)(() => { emitKiller = (0, runner_1.run)(onEmitCommand); }, onEmitDebounceMs)
: undefined;
function runOnEmitCommand() {
debouncedEmit === null || debouncedEmit === void 0 ? void 0 : debouncedEmit();
}
function getTscPath() {
let tscBin;
try {
return require.resolve(compiler);
}
catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
console.error(e.message);
process.exit(9);
}
throw e;
}
}
function spawnTsc({ maxNodeMem, requestedToListEmittedFiles, signalEmittedFiles }, args) {
const tscBin = getTscPath();
const nodeArgs = [
...((maxNodeMem) ? [`--max_old_space_size=${maxNodeMem}`] : []),
tscBin,
...args
];
return (0, cross_spawn_1.default)('node', nodeArgs);
}
function echoExit(code, signal) {
if (signal !== null) {
process.kill(process.pid, signal);
}
}
let compilationErrorSinceStart = false;
const tscProcess = spawnTsc({ maxNodeMem, requestedToListEmittedFiles, signalEmittedFiles }, args);
if (!tscProcess.stdout) {
throw new Error('Unable to read Typescript stdout');
}
if (!tscProcess.stderr) {
throw new Error('Unable to read Typescript stderr');
}
tscProcess.on('exit', echoExit);
tscProcess.stderr.pipe(process.stderr);
const rl = (0, readline_1.createInterface)({ input: tscProcess.stdout });
let compilationId = 0;
let emitId = 0;
function triggerOnEmit() {
if (onEmitCommand) {
killEmitProcesses(++emitId).then((previousEmitId) => previousEmitId === emitId && runOnEmitCommand());
}
}
rl.on('line', function (input) {
if (noClear) {
input = (0, stdout_manipulator_1.deleteClear)(input);
}
const line = (0, stdout_manipulator_1.manipulate)(input);
if (!silent) {
(0, stdout_manipulator_1.print)(line, { noColors, noClear, signalEmittedFiles, requestedToListEmittedFiles });
}
const state = (0, stdout_manipulator_1.detectState)(line);
const compilationStarted = state.compilationStarted;
const compilationError = state.compilationError;
const compilationComplete = state.compilationComplete;
compilationErrorSinceStart =
(!compilationStarted && compilationErrorSinceStart) || compilationError;
if (state.fileEmitted !== null) {
Signal.emitFile(state.fileEmitted);
triggerOnEmit();
}
if (compilationStarted) {
compilationId++;
killProcesses(compilationId, false).then((previousCompilationId) => {
if (previousCompilationId !== compilationId) {
return;
}
runOnCompilationStarted();
Signal.emitStarted();
});
}
if (compilationComplete) {
compilationId++;
killProcesses(compilationId, false).then((previousCompilationId) => {
if (previousCompilationId !== compilationId) {
return;
}
runOnCompilationComplete();
if (compilationErrorSinceStart) {
Signal.emitFail();
runOnFailureCommand();
}
else {
if (firstTime) {
firstTime = false;
Signal.emitFirstSuccess();
runOnFirstSuccessCommand();
triggerOnEmit();
}
Signal.emitSuccess();
runOnSuccessCommand();
}
});
}
});
if (typeof process.on === 'function') {
process.on('message', (msg) => {
switch (msg) {
case 'run-on-compilation-started-command':
if (compilationStartedKiller) {
compilationStartedKiller().then(runOnCompilationStarted);
}
break;
case 'run-on-compilation-complete-command':
if (compilationCompleteKiller) {
compilationCompleteKiller().then(runOnCompilationComplete);
}
break;
case 'run-on-first-success-command':
if (firstSuccessKiller) {
firstSuccessKiller().then(runOnFirstSuccessCommand);
}
break;
case 'run-on-failure-command':
if (failureKiller) {
failureKiller().then(runOnFailureCommand);
}
break;
case 'run-on-success-command':
if (successKiller) {
successKiller().then(runOnSuccessCommand);
}
break;
case 'run-on-emit-command':
if (emitKiller) {
emitKiller().then(runOnEmitCommand);
}
break;
default:
console.log('Unknown message', msg);
}
});
}
const sendSignal = (msg) => {
if (process.send) {
process.send(msg);
}
};
const Signal = {
emitStarted: () => sendSignal('started'),
emitFirstSuccess: () => sendSignal('first_success'),
emitSuccess: () => sendSignal('success'),
emitFail: () => sendSignal('compile_errors'),
emitFile: (path) => sendSignal(`file_emitted:${path}`),
};
(0, node_cleanup_1.default)((_exitCode, signal) => {
if (signal) {
tscProcess.kill(signal);
}
killProcesses(0, true).then(() => process.exit());
// don't call cleanup handler again
(0, node_cleanup_1.uninstall)();
return false;
});