@danielx/civet 0.11.10 → 0.11.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/civet CHANGED
@@ -111,6 +111,12 @@ async function parseArgs(args, isTTY = process.stdin.isTTY) {
111
111
  options.compile = true;
112
112
  break;
113
113
  }
114
+ case "-w":
115
+ case "--watch": {
116
+ options.watch = true;
117
+ options.compile = true;
118
+ break;
119
+ }
114
120
  case "-o":
115
121
  case "--output": {
116
122
  options.output = args[++i];
@@ -223,13 +229,21 @@ async function parseArgs(args, isTTY = process.stdin.isTTY) {
223
229
  if (options.typecheck || options.emitDeclaration) {
224
230
  options.typescript = true;
225
231
  }
232
+ if (options.watch && options.typescript) {
233
+ console.error(`--watch is not compatible with --typecheck or --emit-declaration`);
234
+ errors++;
235
+ }
236
+ if (options.watch && !filenames.some((f) => f !== "-")) {
237
+ console.error(`--watch requires one or more input filenames`);
238
+ errors++;
239
+ }
226
240
  if (options.maxErrors == null && process.env.CIVET_TYPECHECK_MAX_ERRORS) {
227
241
  const parsed = parseInt(process.env.CIVET_TYPECHECK_MAX_ERRORS, 10);
228
242
  if (!isNaN(parsed)) {
229
243
  options.maxErrors = parsed;
230
244
  }
231
245
  }
232
- if (!(filenames.length || options.typescript || options.eval)) {
246
+ if (!(filenames.length || options.typescript || options.eval || options.watch)) {
233
247
  if (isTTY) {
234
248
  options.repl = true;
235
249
  } else {
@@ -269,55 +283,77 @@ async function parseArgs(args, isTTY = process.stdin.isTTY) {
269
283
  options.run = isRun();
270
284
  return { filenames, scriptArgs, options };
271
285
  }
272
- async function* readFiles(filenames, evalString) {
286
+ function readFiles(filenames, evalString) {
287
+ if ((() => {
288
+ let results1 = 0;
289
+ for (const filename of filenames) {
290
+ if (!(filename === "-")) continue;
291
+ ++results1;
292
+ }
293
+ return results1;
294
+ })() > 1) {
295
+ return [
296
+ Promise.resolve({
297
+ filename: "<stdin>",
298
+ error: new Error("Cannot read from stdin more than once."),
299
+ stdin: true
300
+ })
301
+ ];
302
+ }
303
+ let reads = [];
273
304
  if (evalString != null) {
274
- yield {
305
+ reads.push(Promise.resolve({
275
306
  filename: "<eval>",
276
307
  content: evalString + "\n",
277
308
  stdin: true
278
- };
309
+ }));
279
310
  }
280
311
  for (let i2 = 0, len1 = filenames.length; i2 < len1; i2++) {
281
312
  let filename = filenames[i2];
282
- const stdin = filename === "-";
283
- try {
284
- let content;
285
- if (stdin) {
286
- process.stdin.setEncoding(encoding);
287
- filename = "<stdin>";
313
+ reads.push((async () => {
314
+ {
315
+ const stdin = filename === "-";
288
316
  try {
289
- filename = await import_promises.default.realpath("/dev/stdin");
290
- } catch (e) {
291
- }
292
- if (process.stdin.isTTY) {
293
- const lines = [];
294
- const rl = (await import("node:readline")).createInterface(process.stdin, process.stdout);
295
- rl.on("line", (buffer) => lines.push(buffer + "\n"));
296
- content = await new Promise((resolve, reject) => {
297
- rl.on("SIGINT", () => {
298
- return reject("^C");
299
- });
300
- return rl.on("close", () => {
301
- return resolve(lines.join(""));
302
- });
303
- });
304
- } else {
305
- content = (await (async () => {
306
- const results1 = [];
307
- for await (const chunk of process.stdin) {
308
- results1.push(chunk);
317
+ let content;
318
+ if (stdin) {
319
+ process.stdin.setEncoding(encoding);
320
+ filename = "<stdin>";
321
+ try {
322
+ filename = await import_promises.default.realpath("/dev/stdin");
323
+ } catch (e) {
324
+ }
325
+ if (process.stdin.isTTY) {
326
+ const lines = [];
327
+ const rl = (await import("node:readline")).createInterface(process.stdin, process.stdout);
328
+ rl.on("line", (buffer) => lines.push(buffer + "\n"));
329
+ content = await new Promise((resolve, reject) => {
330
+ rl.on("SIGINT", () => {
331
+ return reject("^C");
332
+ });
333
+ return rl.on("close", () => {
334
+ return resolve(lines.join(""));
335
+ });
336
+ });
337
+ } else {
338
+ content = (await (async () => {
339
+ const results2 = [];
340
+ for await (const chunk of process.stdin) {
341
+ results2.push(chunk);
342
+ }
343
+ return results2;
344
+ })()).join("");
309
345
  }
310
- return results1;
311
- })()).join("");
346
+ } else {
347
+ content = await import_promises.default.readFile(filename, { encoding });
348
+ }
349
+ return { filename, content, stdin };
350
+ } catch (error) {
351
+ return { filename, error, stdin };
312
352
  }
313
- } else {
314
- content = await import_promises.default.readFile(filename);
315
353
  }
316
- yield { filename, content, stdin };
317
- } catch (error) {
318
- yield { filename, error, stdin };
319
- }
354
+ })());
320
355
  }
356
+ return reads;
321
357
  }
322
358
  function makeOutputFilename(filename, options) {
323
359
  let ref1;
@@ -427,8 +463,19 @@ async function repl(args, options) {
427
463
  if (error.errors != null) {
428
464
  error = error.errors[0];
429
465
  }
430
- return console.log(`${input.split("\n").slice(0, error.line).join("\n")}
431
- ${" ".repeat(error.column - 1)}^ ${error.header}`);
466
+ const parseError = error;
467
+ let ref3;
468
+ if (typeof parseError.line === "number") {
469
+ ref3 = parseError.line;
470
+ } else ref3 = 1;
471
+ const line = ref3;
472
+ let ref4;
473
+ if (typeof parseError.column === "number") {
474
+ ref4 = parseError.column;
475
+ } else ref4 = 1;
476
+ const column = ref4;
477
+ return console.log(`${input.split("\n").slice(0, line).join("\n")}
478
+ ${" ".repeat(column - 1)}^ ${parseError.header}`);
432
479
  } else {
433
480
  return console.error(error);
434
481
  }
@@ -557,6 +604,7 @@ Options:
557
604
  --version Show the version number
558
605
  -o / --output XX Specify output directory and/or extension, or filename
559
606
  -c / --compile Compile input files to TypeScript (or JavaScript)
607
+ -w / --watch Watch input files and recompile on change (implies -c)
560
608
  -e / --eval XX Evaluate specified code (or compile it with -c)
561
609
  --config XX Specify a config file (default scans for a config.civet, civet.json, civetconfig.civet or civetconfig.json file, optionally in a .config directory, or starting with a .)
562
610
  --civet XX Specify civet compiler flag, as in "civet XX" prologue
@@ -605,9 +653,9 @@ You can override this behavior via: --civet rewriteCivetImports=.ext
605
653
  require("typescript");
606
654
  } catch {
607
655
  const modulePkg = require("node:module");
608
- let ref3;
609
- if (ref3 = __dirname.match(/([/\\]@danielx)?[/\\][cC]ivet[/\\]dist[/\\]?$/)) {
610
- const match = ref3;
656
+ let ref5;
657
+ if (ref5 = __dirname.match(/([/\\]@danielx)?[/\\][cC]ivet[/\\]dist[/\\]?$/)) {
658
+ const match = ref5;
611
659
  if (match[1]) {
612
660
  modulePkg.globalPaths?.push(import_node_path.default.join(__dirname, "..", "..", ".."));
613
661
  } else {
@@ -653,132 +701,244 @@ You can override this behavior via: --civet rewriteCivetImports=.ext
653
701
  }
654
702
  });
655
703
  }
656
- let errors = 0;
657
- for await (let { filename, error, content, stdin } of readFiles(filenames, options.eval)) {
658
- if (error) {
659
- console.error(`${filename} failed to load:`);
660
- console.error(error);
661
- errors++;
662
- continue;
663
- }
664
- const outputFilename = makeOutputFilename(filename, options);
665
- let output;
666
- try {
667
- if (unplugin != null) {
668
- output = (await unplugin.load.call({
669
- addWatchFile() {
670
- ;
704
+ let errorCount = 0;
705
+ const results3 = [];
706
+ for (const result of readFiles(filenames, options.eval).map((readFile) => {
707
+ return (async () => {
708
+ {
709
+ let { filename, error: loadError, content, stdin } = await readFile;
710
+ const outputFilename = makeOutputFilename(filename, options);
711
+ const errors = [];
712
+ let stdout;
713
+ let output;
714
+ if (loadError) {
715
+ errors.push(`${filename} failed to load:`, loadError);
716
+ } else {
717
+ try {
718
+ if (unplugin != null) {
719
+ output = (await unplugin.load.call({
720
+ addWatchFile() {
721
+ ;
722
+ }
723
+ }, `${filename}.tsx`)).code;
724
+ } else {
725
+ output = await (0, import_main.compile)(content, { ...options, filename, outputFilename });
726
+ }
727
+ } catch (error) {
728
+ errors.push(error);
671
729
  }
672
- }, `${filename}.tsx`)).code;
673
- } else {
674
- output = await (0, import_main.compile)(content, { ...options, filename, outputFilename });
675
- }
676
- } catch (error2) {
677
- console.error(error2);
678
- errors++;
679
- continue;
680
- }
681
- if (options.ast) {
682
- process.stdout.write(JSON.stringify(output, null, 2));
683
- } else if (options.compile) {
684
- if (stdin && !options.output || options.output === "-") {
685
- process.stdout.write(output);
686
- } else {
687
- const outputDir = import_node_path.default.dirname(outputFilename);
688
- if (!(outputDir === ".")) {
689
- await import_promises.default.mkdir(outputDir, { recursive: true });
690
730
  }
691
- try {
692
- await import_promises.default.writeFile(outputFilename, output);
693
- } catch (error2) {
694
- console.error(`${outputFilename} failed to write:`);
695
- console.error(error2);
696
- errors++;
731
+ if (!errors.length) {
732
+ output = output;
733
+ if (options.ast) {
734
+ stdout = JSON.stringify(output, null, 2);
735
+ } else if (options.compile) {
736
+ if (stdin && !options.output || options.output === "-") {
737
+ stdout = output;
738
+ } else {
739
+ const outputDir = import_node_path.default.dirname(outputFilename);
740
+ if (!(outputDir === ".")) {
741
+ await import_promises.default.mkdir(outputDir, { recursive: true });
742
+ }
743
+ try {
744
+ await import_promises.default.writeFile(outputFilename, output);
745
+ } catch (error) {
746
+ errors.push(`${outputFilename} failed to write:`, error);
747
+ }
748
+ }
749
+ } else if (options.run) {
750
+ let ref6;
751
+ {
752
+ if (typeof output === "string" && /\b(await|import|export)\b/.test(output)) {
753
+ const ast = await (0, import_main.compile)(content, { ...options, ast: true, filename });
754
+ ref6 = import_main.lib.hasAwait(ast) || import_main.lib.hasImportDeclaration(ast) || import_main.lib.hasExportDeclaration(ast);
755
+ } else {
756
+ ref6 = void 0;
757
+ }
758
+ }
759
+ ;
760
+ const esm = ref6;
761
+ if (esm) {
762
+ if (stdin) {
763
+ filename = `.stdin-${process.pid}.civet`;
764
+ try {
765
+ await import_promises.default.writeFile(filename, content, { encoding });
766
+ } catch (e) {
767
+ console.error(`Could not write ${filename} for Civet ESM mode:`);
768
+ console.error(e);
769
+ process.exit(1);
770
+ }
771
+ }
772
+ const { fork } = await import("node:child_process");
773
+ const { register } = await import("node:module");
774
+ let execArgv;
775
+ if (register) {
776
+ const { join } = await import("path");
777
+ const { pathToFileURL } = await import("node:url");
778
+ execArgv = [
779
+ "--import",
780
+ pathToFileURL(join(__dirname, "../register.js")).href
781
+ ];
782
+ } else {
783
+ execArgv = [
784
+ "--loader",
785
+ "@danielx/civet/esm",
786
+ // ESM
787
+ "--require",
788
+ "@danielx/civet/register"
789
+ // CJS
790
+ ];
791
+ }
792
+ const debugRe = /--debug|--inspect/;
793
+ const isDebug = typeof v8debug === "object" || debugRe.test(process.execArgv.join(" ")) || debugRe.test(process.env.NODE_OPTIONS ?? "");
794
+ if (isDebug) {
795
+ execArgv.push("--inspect=" + (process.debugPort + 1));
796
+ }
797
+ const child = fork(filename, [
798
+ ...scriptArgs
799
+ ], {
800
+ execArgv,
801
+ stdio: "inherit"
802
+ });
803
+ child.on("exit", async (code) => {
804
+ if (stdin) {
805
+ await import_promises.default.unlink(filename);
806
+ }
807
+ return process.exit(code ?? 1);
808
+ });
809
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
810
+ process.on(signal, () => child.kill(signal));
811
+ }
812
+ } else {
813
+ await import("../register.js");
814
+ try {
815
+ module.filename = await import_promises.default.realpath(filename);
816
+ } catch {
817
+ module.filename = filename;
818
+ }
819
+ process.argv = ["civet", module.filename, ...scriptArgs];
820
+ module.paths = (await import("node:module"))._nodeModulePaths(import_node_path.default.dirname(module.filename));
821
+ try {
822
+ module._compile(output, module.filename);
823
+ } catch (error) {
824
+ console.error(`${filename} crashed while running in CJS mode:`);
825
+ console.error(error);
826
+ process.exit(1);
827
+ }
828
+ }
829
+ }
697
830
  }
831
+ return { errors, stdout };
698
832
  }
699
- } else if (options.run) {
700
- let ref4;
701
- {
702
- if (typeof output === "string" && /\b(await|import|export)\b/.test(output)) {
703
- const ast = await (0, import_main.compile)(content, { ...options, ast: true, filename });
704
- ref4 = import_main.lib.hasAwait(ast) || import_main.lib.hasImportDeclaration(ast) || import_main.lib.hasExportDeclaration(ast);
833
+ })();
834
+ })) {
835
+ const { errors, stdout } = await result;
836
+ if (stdout != null) {
837
+ process.stdout.write(stdout);
838
+ }
839
+ for (const error of errors) {
840
+ console.error(error);
841
+ }
842
+ if (errors.length) {
843
+ results3.push(errorCount++);
844
+ } else {
845
+ results3.push(void 0);
846
+ }
847
+ }
848
+ results3;
849
+ if (options.watch) {
850
+ const fsSync = (await import("node:fs")).default;
851
+ console.error(`Civet watching for changes... (Ctrl+C to stop)`);
852
+ const debounceTimers = /* @__PURE__ */ new Map();
853
+ const watchers = /* @__PURE__ */ new Map();
854
+ const rewatchTimers = /* @__PURE__ */ new Map();
855
+ const recompile = async (filename) => {
856
+ const outputFilename = makeOutputFilename(filename, options);
857
+ try {
858
+ const content = await import_promises.default.readFile(filename, encoding);
859
+ const output = await (0, import_main.compile)(content, { ...options, filename, outputFilename });
860
+ if (options.output === "-") {
861
+ process.stdout.write(output);
705
862
  } else {
706
- ref4 = void 0;
863
+ const outputDir = import_node_path.default.dirname(outputFilename);
864
+ if (!(outputDir === ".")) {
865
+ await import_promises.default.mkdir(outputDir, { recursive: true });
866
+ }
867
+ await import_promises.default.writeFile(outputFilename, output);
868
+ console.error(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Compiled ${filename} -> ${outputFilename}`);
707
869
  }
870
+ } catch (error) {
871
+ console.error(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Failed to compile ${filename}:`);
872
+ console.error(error);
708
873
  }
709
- ;
710
- const esm = ref4;
711
- if (esm) {
712
- if (stdin) {
713
- filename = `.stdin-${process.pid}.civet`;
714
- try {
715
- await import_promises.default.writeFile(filename, content, { encoding });
716
- } catch (e) {
717
- console.error(`Could not write ${filename} for Civet ESM mode:`);
718
- console.error(e);
719
- process.exit(1);
874
+ };
875
+ const scheduleRebuild = (filename) => {
876
+ const existing = debounceTimers.get(filename);
877
+ if (existing != null) {
878
+ clearTimeout(existing);
879
+ }
880
+ const cb = () => {
881
+ debounceTimers.delete(filename);
882
+ return void recompile(filename);
883
+ };
884
+ debounceTimers.set(filename, setTimeout(cb, 100));
885
+ };
886
+ const startWatching = (filename) => {
887
+ try {
888
+ const watcher = fsSync.watch(filename, (eventType) => {
889
+ if (!(eventType === "change" || eventType === "rename")) {
890
+ return;
720
891
  }
721
- }
722
- const { fork } = await import("node:child_process");
723
- const { register } = await import("node:module");
724
- let execArgv;
725
- if (register) {
726
- const { join } = await import("path");
727
- const { pathToFileURL } = await import("node:url");
728
- execArgv = [
729
- "--import",
730
- pathToFileURL(join(__dirname, "../register.js")).href
731
- ];
732
- } else {
733
- execArgv = [
734
- "--loader",
735
- "@danielx/civet/esm",
736
- // ESM
737
- "--require",
738
- "@danielx/civet/register"
739
- // CJS
740
- ];
741
- }
742
- const debugRe = /--debug|--inspect/;
743
- const isDebug = typeof v8debug === "object" || debugRe.test(process.execArgv.join(" ")) || debugRe.test(process.env.NODE_OPTIONS ?? "");
744
- if (isDebug) {
745
- execArgv.push("--inspect=" + (process.debugPort + 1));
746
- }
747
- const child = fork(filename, [
748
- ...scriptArgs
749
- ], {
750
- execArgv,
751
- stdio: "inherit"
752
- });
753
- child.on("exit", async (code) => {
754
- if (stdin) {
755
- await import_promises.default.unlink(filename);
892
+ scheduleRebuild(filename);
893
+ if (eventType === "rename") {
894
+ watchers.get(filename)?.close();
895
+ watchers.delete(filename);
896
+ const existing = rewatchTimers.get(filename);
897
+ if (existing != null) {
898
+ clearTimeout(existing);
899
+ }
900
+ const timer = setTimeout(
901
+ () => {
902
+ rewatchTimers.delete(filename);
903
+ return startWatching(filename);
904
+ },
905
+ 100
906
+ );
907
+ return rewatchTimers.set(filename, timer);
756
908
  }
757
- return process.exit(code ?? 1);
909
+ ;
910
+ return;
758
911
  });
759
- for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
760
- process.on(signal, () => child.kill(signal));
912
+ watchers.set(filename, watcher);
913
+ } catch (error) {
914
+ console.error(`Could not watch ${filename}:`);
915
+ console.error(error);
916
+ }
917
+ };
918
+ for (const filename of filenames) {
919
+ if (!fsSync.existsSync(filename)) {
920
+ continue;
921
+ }
922
+ startWatching(filename);
923
+ }
924
+ return {
925
+ close: () => {
926
+ for (const watcher of watchers.values()) {
927
+ watcher.close();
761
928
  }
762
- } else {
763
- await import("../register.js");
764
- try {
765
- module.filename = await import_promises.default.realpath(filename);
766
- } catch {
767
- module.filename = filename;
929
+ watchers.clear();
930
+ for (const timer of debounceTimers.values()) {
931
+ clearTimeout(timer);
768
932
  }
769
- process.argv = ["civet", module.filename, ...scriptArgs];
770
- module.paths = (await import("node:module"))._nodeModulePaths(import_node_path.default.dirname(module.filename));
771
- try {
772
- module._compile(output, module.filename);
773
- } catch (error2) {
774
- console.error(`${filename} crashed while running in CJS mode:`);
775
- console.error(error2);
776
- process.exit(1);
933
+ debounceTimers.clear();
934
+ for (const timer of rewatchTimers.values()) {
935
+ clearTimeout(timer);
777
936
  }
937
+ return rewatchTimers.clear();
778
938
  }
779
- }
939
+ };
780
940
  }
781
- process.exitCode = Math.min(255, errors);
941
+ process.exitCode = Math.min(255, errorCount);
782
942
  if (unplugin != null) {
783
943
  try {
784
944
  const pending = [];
@@ -797,10 +957,10 @@ You can override this behavior via: --civet rewriteCivetImports=.ext
797
957
  }, !filenames.length);
798
958
  return await Promise.all(pending);
799
959
  } catch (error) {
800
- let ref5;
801
- if (ref5 = error.message.match(/Aborting build because of (\d+) TypeScript diagnostic/)) {
802
- const match = ref5;
803
- return process.exitCode = Math.min(255, errors + +match[1]);
960
+ let ref7;
961
+ if (ref7 = error.message.match(/Aborting build because of (\d+) TypeScript diagnostic/)) {
962
+ const match = ref7;
963
+ return process.exitCode = Math.min(255, errorCount + +match[1]);
804
964
  } else {
805
965
  process.exitCode = 1;
806
966
  throw error;