• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DanielXMoore / Civet / 14696205467

27 Apr 2025 09:16PM UTC coverage: 91.652% (+0.01%) from 91.64%
14696205467

Pull #1734

github

web-flow
Merge aef507707 into 0039cdd9c
Pull Request #1734: ESM loader supports civetconfig by default, and overriding configuration

3643 of 3962 branches covered (91.95%)

Branch coverage included in aggregate %.

47 of 49 new or added lines in 2 files covered. (95.92%)

3 existing lines in 2 files now uncovered.

18808 of 20534 relevant lines covered (91.59%)

16289.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

35.95
/source/cli.civet
1
{ compile, generate, parse, lib, isCompileError, SourceMap } from ./main.civet
1✔
2
type { ASTError, BlockStatement, ParseError, ParseErrors } from ./main.civet
1✔
3
{ findConfig, loadConfig } from ./config.civet
1✔
4

1✔
5
// unplugin ends up getting installed in the same dist directory
1✔
6
{rawPlugin} from ./unplugin/unplugin.civet
1✔
7
let unplugin:
1✔
8
  buildStart: () => Promise<void>
1✔
9
  buildEnd: (this: {emitFile: (data: {source: string, fileName: string, type: string}) => void}, useConfigFileNames?: boolean) => Promise<void>
1✔
10
  load: (this: {addWatchFile: (filename: string) => void}, filename: string) => Promise<{code: string, map: unknown}>
1✔
11

1✔
12
export function version: Promise<string>
×
13
  // Once import assertions (with form) are universal, we can switch to this:
×
14
  //import package from "../package.json" with type: "json"
×
15
  //package.version
×
16
  if import.meta.url  // ESM mode (e.g. testing)
×
17
    { createRequire } from node:module
×
18
    createRequire(import.meta.url)('../package.json').version
×
19
  else
×
20
    require('../package.json').version
×
21

1✔
22
encoding .= "utf8" as BufferEncoding
1✔
23

1✔
24
fs from node:fs/promises
1✔
25
type { Stats } from node:fs
1✔
26
path from node:path
1✔
27

1✔
28
// TODO: Once the types are exported within the Civet source code,
1✔
29
// we should import them directly here, instead of looking at an old release.
1✔
30
type { CompileOptions } from @danielx/civet
1✔
31

1✔
32
export interface Options extends CompileOptions
1✔
33
  version?: boolean
1✔
34
  help?: boolean
1✔
35
  run?: boolean
1✔
36
  compile?: boolean
1✔
37
  output?: string
1✔
38
  outputDir?: string
1✔
39
  outputExt?: string
1✔
40
  outputPath?: path.ParsedPath
1✔
41
  eval?: string
1✔
42
  config?: string | boolean | undefined
1✔
43
  ast?: boolean | "raw"
1✔
44
  repl?: boolean
1✔
45
  typecheck?: boolean
1✔
46
  emitDeclaration?: boolean
1✔
47
  typescript?: boolean
1✔
48

1✔
49
export interface ParsedArgs
1✔
50
  filenames: string[]
1✔
51
  scriptArgs: string[]
1✔
52
  options: Options
1✔
53

1✔
54
export function parseArgs(args: string[], isTTY = process.stdin.isTTY): Promise<ParsedArgs>
54✔
55
  options: Options := {}
54✔
56
  isRun := => not (or)
54✔
57
    options.ast
60✔
58
    options.compile
59✔
59
    options.typecheck
42✔
60
    options.emitDeclaration
39✔
61
  filenames: string[] .= []
54✔
62
  scriptArgs: string[] .= []
54✔
63

54✔
64
  options.version = true if args.includes '-version'
54✔
65
  options.help = true if args.includes '-help'
54✔
66
  return {filenames, scriptArgs, options} if options.version or options.help
54✔
67

52✔
68
  i .= 0
52✔
69
  errors .= 0
52✔
70
  function endOfArgs(j: number): void
52✔
71
    i = args.length  // trigger end of loop
×
72
    return if j >= args.length  // no more args
×
73
    if options.run
×
74
      filenames.push args[j]
×
75
      scriptArgs = args[j+1..]
×
76
    else
×
77
      filenames.push ...args[j..]
×
78
  while i < args.length
52✔
79
    arg := args[i]
66✔
80
    // Split -ab into -a -b
66✔
81
    if /^-\w{2,}$/.test arg
66✔
82
      args[i..i] =
1✔
83
        for each char of arg[1..]
1✔
84
          `-${char}`
2✔
85
      continue
1✔
86
    // Main argument handling
65✔
87
    switch arg
65✔
88
      when '-v', '--version'
2✔
89
        options.version = true
2✔
90
      when '-h', '--help'
3✔
91
        options.help = true
3✔
92
      when '-c', '--compile'
8✔
93
        options.compile = true
8✔
94
      when '-o', '--output'
16✔
95
        options.output = args[++i]
16✔
96
      when '-e', '--eval'
66✔
97
        options.eval = args[++i]
2✔
98
      when '--config'
66✔
99
        options.config = args[++i]
1✔
100
      when '--no-config'
66✔
101
        options.config = null
1✔
102
      when '--civet'
66✔
103
        Object.assign options.parseOptions ??= {},
5✔
104
          parse `civet ${args[++i]}`,
5✔
105
            startRule: 'CivetPrologueContent'
5✔
106
            filename: '--civet argument'
5✔
107
            events: // remove cache in case we've compiled Civet before
5✔
108
              enter: undefined
5✔
109
              exit: undefined
5✔
110
          |> .config
5✔
111
      when '--comptime'
66✔
112
        (options.parseOptions ??= {}).comptime = true
3✔
113
      when '--no-comptime'
66✔
114
        (options.parseOptions ??= {}).comptime = false
3✔
115
      when '--ast'
66✔
116
        options.ast = true
1✔
117
      when '--no-cache'
66✔
118
        options.noCache = true
1✔
119
      when '--inline-map'
66✔
120
        options.inlineMap = true
1✔
121
      when '--js'
66✔
122
        options.js = true
1✔
123
      when '--hits'
66✔
124
        options.hits = args[++i]
1✔
125
      when '--trace'
66✔
126
        options.trace = args[++i]
1✔
127
      when '--typecheck'
66✔
128
        options.typecheck = true
3✔
129
      when '--emit-declaration', '--emitDeclaration'
4✔
130
        options.emitDeclaration = true
4✔
131
      when '--'
66!
132
        endOfArgs ++i  // remaining arguments are filename and/or arguments
66✔
133
      else
66✔
134
        if arg.startsWith('-') and arg is not '-'
8!
135
          console.error `Invalid command-line argument: ${arg}`
×
136
          errors++
×
137
        else if (options.run = isRun())
8✔
138
          endOfArgs i  // remaining arguments are arguments to the script
8!
139
        else
8✔
140
          filenames.push arg
8✔
141
    i++
65✔
142

52✔
143
  options.typescript = true if options.typecheck or options.emitDeclaration
54✔
144

52✔
145
  unless filenames.length or options.typescript or options.eval
54✔
146
    if isTTY
41✔
147
      options.repl = true
40✔
148
    else
1✔
149
      // When piped, default to old behavior of transpiling stdin to stdout
1✔
150
      options.compile = true
1✔
151
      options.run = false
1✔
152
      filenames = ['-']
1✔
153

52✔
154
  // Parse `output` option into forced directory, extension, and/or full path
52✔
155
  if options.output and options.output is not '-'
54✔
156
    optionsPath := path.parse options.output
14✔
157
    let stat: Stats | null
14✔
158
    try
14✔
159
      stat = await fs.stat options.output
2✔
160
    catch
14✔
161
      stat = null
12✔
162
    if stat?.isDirectory() or options.output.endsWith(path.sep) or
14✔
163
                              options.output.endsWith('/')
10✔
164
      // -o dir writes outputs into that directory with default name
4✔
165
      options.outputDir = options.output
4✔
166
    else if /^(\.[^]+)+$/.test optionsPath.base
10✔
167
      // -o .js or .ts or .civet.js or .civet.ts etc. to control extension
6✔
168
      options.outputExt = optionsPath.base
6✔
169
      // Can also be prefixed by a directory name
6✔
170
      options.outputDir = optionsPath.dir if optionsPath.dir
6✔
171
    else
4✔
172
      // -o filename fully specifies the output filename
4✔
173
      // (don't use this with multiple input files)
4✔
174
      options.outputPath = optionsPath
4✔
175
      options.outputExt = optionsPath.ext
4✔
176
  // For CLI compilations, default to rewriting imports to output extension,
54✔
177
  // with .jsx instead of .tsx to satisfy TypeScript.
54✔
178
  (options.parseOptions ??= {}).rewriteCivetImports ??=
54✔
179
    options.outputExt ?? '.civet.jsx'
54✔
180

54✔
181
  process.exit Math.min 255, errors if errors
54!
182
  options.run = isRun()
52✔
183
  {filenames, scriptArgs, options}
52✔
184

1✔
185
type ReadFile = (
1✔
186
  filename: string
1✔
187
  stdin: boolean
1✔
188
  content?: string
1✔
189
  error?: unknown
1✔
190
) & ((content: string) | (error: unknown))
1✔
191

1✔
192
function readFiles(filenames: string[], evalString?: string): AsyncGenerator<ReadFile>
×
193
  if evalString?
×
194
    yield
×
195
      filename: '<eval>'
×
196
      content: evalString + '\n'
×
197
      stdin: true
×
198

×
199
  for each let filename of filenames
×
200
    stdin := filename is '-'
×
201
    try
×
202
      let content: string
×
203
      if stdin
×
204
        process.stdin.setEncoding encoding
×
205

×
206
        // Try to guess filename for stdin, such as /dev/fd/filename
×
207
        filename = "<stdin>"
×
208
        try
×
209
          filename = await fs.realpath '/dev/stdin'
×
210

×
211
        if process.stdin.isTTY
×
212
          // In interactive stdin, `readline` lets user end the file via ^D.
×
213
          lines: string[] := []
×
214
          rl := import('node:readline') |> await |> .createInterface process.stdin, process.stdout
×
215
          rl.on 'line', (buffer: string) => lines.push buffer + '\n'
×
216
          content = await new Promise (resolve, reject) =>
×
217
            rl.on 'SIGINT', =>
×
218
              reject '^C'
×
219
            rl.on 'close', =>
×
220
              resolve lines.join ''
×
221
        else
×
222
          // For piped stdin, read stdin directly to avoid potential echo.
×
223
          content = (chunk for await chunk of process.stdin).join ''
×
224
      else
×
225
        content = await fs.readFile filename, {encoding}
×
226
      yield {filename, content, stdin}
×
227
    catch error
×
228
      yield {filename, error, stdin}
×
229

1✔
230
declare global
1✔
231
  var quit: () => void, exit: () => void
1✔
232
  var v8debug: unknown
1✔
233

1✔
234
export function repl(args: string[], options: Options)
×
235
  * as vm from 'node:vm'
×
236
  // Node 21.7.0+ supports dynamic import() in vm calls via this constant:
×
237
  importModuleDynamically .= vm.constants?.USE_MAIN_CONTEXT_DEFAULT_LOADER
×
238
  unless importModuleDynamically
×
239
    // For older Node, we need to provide our own dynamic import function,
×
240
    // which requires `--experimental-vm-modules`.  Check if we did it already:
×
241
    if vm.SourceTextModule?
×
242
      { pathToFileURL } from node:url
×
243
      importModuleDynamically = (specifier: string) =>
×
244
        if /^\.\.?[/\\]/.test specifier
×
245
          import pathToFileURL(path.join process.cwd(), specifier).href
×
246
        else
×
247
          import specifier
×
248
    else
×
249
      // If not, run this script with `--experimental-vm-modules`.
×
250
      execArgv := [ '--experimental-vm-modules' ]
×
251
      /* This doesn't work; --loader seems to force ESM mode which breaks CLI.
×
252
      { register } from node:module
×
253
      unless register
×
254
        // On Node <20.6.0, we need to use `--loader` for the ESM loader.
×
255
        execArgv.push '--loader', '@danielx/civet/esm'
×
256
      */
×
257
      { fork } from node:child_process
×
258
      fork __filename, args, {
×
259
        execArgv
×
260
        stdio: 'inherit'
×
261
      }
×
262
      return
×
263

×
264
  await import '../register.js'
×
265
  console.log `Civet ${await version()} REPL.  Enter a blank line to ${
×
266
    switch
×
267
      when options.ast then 'parse'
×
268
      when options.compile then 'transpile'
×
269
      else 'execute'
×
270
  } code.`
×
271
  global.quit = global.exit = => process.exit 0
×
272
  import * as nodeRepl from node:repl
×
273
  r := nodeRepl.start
×
274
    prompt:
×
275
      switch
×
276
        when options.ast then '🌲> '
×
277
        when options.compile then '🐈> '
×
278
        else '🐱> '
×
279
    writer:
×
280
      if options.ast
×
281
        (obj: unknown) =>
×
282
          try
×
283
            JSON.stringify obj, null, 2
×
284
          catch e
×
285
            console.log `Failed to stringify: ${e}`
×
286
            ''
×
287
      else if options.compile
×
288
        (obj: unknown) =>
×
289
          if obj <? 'string'
×
290
            obj?.replace /\n*$/, ''
×
291
          else
×
292
            ''
×
293
    eval: (input: string, context, filename: string, callback) ->
×
294
      if input is '\n'  // blank input
×
295
        callback null, undefined
×
296
      else if input in ['quit\n', 'exit\n', 'quit()\n', 'exit()\n']
×
297
        process.exit 0
×
298
      else if input.endsWith '\n\n'  // finished input with blank line
×
299
        function showError(error: ???)
×
300
          console.error "Error while parsing Civet code:"
×
301
          if isCompileError error
×
302
            // Unwrap ParseErrors to first error
×
303
            if (error as ParseErrors).errors?
×
304
              error = (error as ParseErrors).errors[0]
×
305
            console.log ```
×
306
              ${input.split('\n')[0...(error as ParseError).line].join '\n'}
×
307
              ${' '.repeat (error as ParseError).column - 1}^ ${(error as ParseError).header}
×
308
            ```
×
309
          else
×
310
            console.error error
×
311

×
312
        let output: string
×
313
        if options.compile or options.ast
×
314
          try
×
315
            output = await compile input, {...options, filename}
×
316
          catch error
×
317
            showError error
×
318
            return callback null, undefined
×
319
          return callback null, output
×
320

×
321
        parseOptions := {...options.parseOptions,
×
322
          repl: true
×
323
        }
×
324

×
325
        let ast: BlockStatement
×
326
        try
×
327
          ast = await compile input, {...options, parseOptions, filename, ast: true}
×
328
        catch error
×
329
          showError error
×
330
          return callback null, undefined
×
331

×
332
        errors: ASTError[] .= []
×
333
        try
×
334
          output = generate ast, { ...options, errors, sourceMap: undefined }
×
335
        catch error
×
336
          //console.error "Failed to transpile Civet:"
×
337
          console.error error
×
338
          return callback null, undefined
×
339
        if errors#
×
340
          // Rerun with sourceMap
×
341
          errors = []
×
342
          generate ast, { ...options, errors, sourceMap: new SourceMap input }
×
343
          showError errors[0]
×
344
          return callback null, undefined
×
345

×
346
        let result: string
×
347
        try
×
348
          result = vm.runInContext output, context, {
×
349
            filename
×
350
            importModuleDynamically
×
351
          }
×
352
        catch error
×
353
          return callback error as Error, undefined
×
354

×
355
        if ast.topLevelAwait
×
356
          // If there was a top-level await, the result is a promise
×
357
          // that we need to await before returning it.
×
358
          try
×
359
            result = await result
×
360
          catch error
×
361
            callback error as Error, undefined
×
362
          else
×
363
            callback null, result
×
364
        else
×
365
          callback null, result
×
366
      else  // still reading
×
367
        callback (new nodeRepl.Recoverable new Error "Enter a blank line to execute code."), null
×
368

1✔
369
export function cli(args = process.argv[2..])
×
370
  // process.argv gets overridden when running scripts, but gets saved here
×
371

×
372
  {filenames, scriptArgs, options} .= await parseArgs args
×
373

×
374
  if options.version
×
375
    console.log await version()
×
376
    process.exit(0)
×
377

×
378
  if options.help
×
379
    process.stderr.write """
×
380
       ▄▄· ▪   ▌ ▐·▄▄▄ .▄▄▄▄▄
×
381
      ▐█ ▌▪██ ▪█·█▌▀▄.▀·•██       _._     _,-'""`-._
×
382
      ██ ▄▄▐█·▐█▐█•▐▀▀▪▄ ▐█.▪    (,-.`._,'(       |\\`-/|
×
383
      ▐███▌▐█▌ ███ ▐█▄▄▌ ▐█▌·        `-.-' \\ )-`( , o o)
×
384
      ·▀▀▀ ▀▀▀. ▀   ▀▀▀  ▀▀▀               `-    \\`_`"'-
×
385

×
386

×
387
Usage:
×
388

×
389
    civet                                        # REPL for executing code
×
390
    civet -c                                     # REPL for transpiling code
×
391
    civet --ast                                  # REPL for parsing code
×
392
    civet [options] input.civet                  # run input.civet
×
393
    civet [options] -c input.civet               # -> input.civet.tsx
×
394
    civet [options] -c input.civet -o .ts        # -> input.ts
×
395
    civet [options] -c input.civet -o dir        # -> dir/input.civet.tsx
×
396
    civet [options] -c input.civet -o dir/.ts    # -> dir/input.ts
×
397
    civet [options] -c input.civet -o output.ts  # -> output.ts
×
398
    civet [options] < input.civet > output.ts    # pipe form
×
399

×
400
Options:
×
401
  --help           Show this help message
×
402
  --version        Show the version number
×
403
  -o / --output XX Specify output directory and/or extension, or filename
×
404
  -c / --compile   Compile input files to TypeScript (or JavaScript)
×
405
  -e / --eval XX   Evaluate specified code (or compile it with -c)
×
406
  --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 .)
×
407
  --civet XX       Specify civet compiler flag, as in "civet XX" prologue
×
408
  --comptime       Enable execution of code during compilation via comptime
×
409
  --no-config      Don't scan for a config file
×
410
  --js             Strip out all type annotations; default to .jsx extension
×
411
  --ast            Print the AST instead of the compiled code
×
412
  --inline-map     Generate a sourcemap
×
413
  --no-cache       Disable compiler caching (slow, for debugging)
×
414
  --typecheck      Run TypeScript and output diagnostics
×
415
  --emit-declaration  Run TypeScript and emit .d.ts files (if no errors)
×
416
  --trace XX       Log detailed parsing notes to a file, for parser debugging
×
417

×
418
You can use - to read from stdin or (prefixed by -o) write to stdout.
×
419

×
420
By default, .civet imports get rewritten to use the output extension.
×
421
You can override this behavior via: --civet rewriteCivetImports=.ext
×
422

×
423

×
424
    """
×
425
    process.exit(0)
×
426

×
NEW
427
  unless options.config is null // --no-config
×
428
    options.config ?= await findConfig process.cwd()
×
429

×
430
  if options.config
×
431
    parsed := await loadConfig options.config as string
×
432
    options = {
×
433
      ...parsed
×
434
      ...options
×
435
    }
×
436
    // Deep merge
×
437
    if parsed.parseOptions and options.parseOptions
×
438
      options.parseOptions = {
×
439
        ...parsed.parseOptions
×
440
        ...options.parseOptions
×
441
      }
×
442

×
443
  if options.typescript
×
444
    unpluginOptions := {
×
445
      ...options
×
446
      ts: if options.js then 'civet' else 'preserve'
×
447
      outputExtension: '.tsx'
×
448
      declarationExtension:
×
449
        options.outputExt?.replace /\.[jt]sx?$/i, '.d.ts'
×
450
    }
×
451
    // TypeScript wants .civet.tsx files imported as .civet.jsx
×
452
    (unpluginOptions.parseOptions ??= {}).rewriteCivetImports = '.civet.jsx'
×
453
    unplugin = rawPlugin unpluginOptions, framework: 'civet-cli'
×
454
    await unplugin.buildStart()
×
455

×
456
  // In run mode, compile to JS with source maps
×
457
  if options.run
×
458
    options.js = true
×
459
    options.inlineMap = true
×
460

×
461
  return repl args, options if options.repl
×
462

×
463
  // Ignore EPIPE errors, e.g. when piping to `head`
×
464
  process.stdout.on "error", (e) =>
×
465
    if e.code is in ['EPIPE', 'EOF']
×
466
      process.exit 0
×
467
    else
×
468
      console.error e
×
469
      process.exit 1
×
470

×
471
  errors .= 0
×
472
  for await let {filename, error, content, stdin} of readFiles filenames, options.eval
×
473
    if error
×
474
      console.error `${filename} failed to load:`
×
475
      console.error error
×
476
      errors++
×
477
      continue
×
478

×
479
    // Transpile
×
480
    let output: string
×
481
    try
×
482
      if unplugin?
×
483
        output = unplugin.load.call {
×
484
          addWatchFile();
×
485
        }, `${filename}.tsx`
×
486
        |> await
×
487
        |> .code
×
488
      else
×
489
        output = await compile content!, {...options, filename}
×
490
    catch error
×
491
      //console.error `${filename} failed to transpile:`
×
492
      console.error error
×
493
      errors++
×
494
      continue
×
495

×
496
    if options.ast
×
497
      process.stdout.write JSON.stringify(output, null, 2)
×
498
    else if options.compile
×
499
      if (stdin and not options.output) or options.output is '-'
×
500
        process.stdout.write output
×
501
      else
×
502
        targetPath: path.FormatInputPathObject .= path.parse filename
×
503
        delete targetPath.base  // use name and ext
×
504
        // Default extension
×
505
        if options.js
×
506
          targetPath.ext += ".jsx"
×
507
        else
×
508
          targetPath.ext += ".tsx"
×
509
        // `output` option overrides
×
510
        targetPath.dir = options.outputDir if options.outputDir?
×
511
        targetPath.ext = options.outputExt if options.outputExt?
×
512
        targetPath = options.outputPath if options.outputPath?
×
513
        // Make output directory in case it doesn't already exist
×
514
        await fs.mkdir targetPath.dir, recursive: true if targetPath.dir
×
515
        targetFilename := path.format targetPath
×
516
        try
×
517
          await fs.writeFile targetFilename, output
×
518
        catch error
×
519
          console.error `${targetFilename} failed to write:`
×
520
          console.error error
×
521
          errors++
×
522
    else if options.run
×
523
      esm := do
×
524
        if output is like /\b(await|import|export)\b/  // potentially ESM
×
525
          ast := await compile content!, {...options, ast: true, filename}
×
526
          (or)
×
527
            lib.hasAwait ast
×
528
            lib.hasImportDeclaration ast
×
529
            lib.hasExportDeclaration ast
×
530
      if esm
×
531
        // Run ESM code via `node --import @danielx/civet/register` subprocess
×
532
        if stdin
×
533
          // If code was read on stdin via command-line argument "-", try to
×
534
          // save it in a temporary file in same directory so paths are correct.
×
535
          filename = `.stdin-${process.pid}.civet`
×
536
          try
×
537
            await fs.writeFile filename, content!, {encoding}
×
538
          catch e
×
539
            console.error `Could not write ${filename} for Civet ESM mode:`
×
540
            console.error e
×
541
            process.exit 1
×
542
        { fork } from node:child_process
×
543

×
544
        { register } from node:module
×
545
        let execArgv
×
546
        if register
×
547
          // On Node 20.6.0+, module.register does the work for us;
×
548
          // we just need to `--import` ESM/CJS registration.
×
549
          { join } from path
×
550
          { pathToFileURL } from node:url
×
551
          execArgv = [
×
552
            '--import'
×
553
            pathToFileURL(join __dirname, '../register.js').href
×
554
          ]
×
555
        else
×
556
          // On Node <20.6.0, we need to use `--loader` for the ESM loader.
×
557
          execArgv = [
×
558
            '--loader', '@danielx/civet/esm' // ESM
×
559
            '--require', '@danielx/civet/register' // CJS
×
560
          ]
×
561

×
562
        debugRe := /--debug|--inspect/
×
563
        isDebug := v8debug <? "object" or debugRe.test(process.execArgv.join(' ')) or debugRe.test(process.env.NODE_OPTIONS ?? '')
×
564
        if isDebug
×
565
          execArgv.push "--inspect=" + (process.debugPort + 1)
×
566
        child := fork filename, [
×
567
          ...scriptArgs
×
568
        ], {
×
569
          execArgv,
×
570
          stdio: 'inherit'
×
571
        }
×
572
        child.on 'exit', (code) =>
×
573
          if stdin
×
574
            // Delete temporary file
×
575
            await fs.unlink filename
×
576

×
577
          process.exit code ?? 1
×
578

×
579
      else
×
580
        await import '../register.js'
×
581
        try
×
582
          module.filename = await fs.realpath filename
×
583
        catch
×
584
          module.filename = filename
×
585
        process.argv = ["civet", module.filename, ...scriptArgs]
×
586
        module.paths =
×
587
          import 'node:module' |> await |> ._nodeModulePaths path.dirname module.filename
×
588
        try
×
589
          module._compile output, module.filename
×
590
        catch error
×
591
          console.error `${filename} crashed while running in CJS mode:`
×
592
          console.error error
×
593
          process.exit 1
×
594

×
595
  process.exitCode = Math.min 255, errors
×
596
  if unplugin?
×
597
    try
×
598
      await unplugin.buildEnd.call {
×
599
        emitFile({source, fileName})
×
600
          fs.writeFile fileName, source
×
601
      }, not filenames.length
×
602
    catch error
×
603
      if match := (error as Error).message.match /Aborting build because of (\d+) TypeScript diagnostic/
×
604
        process.exitCode = Math.min 255, errors + +match[1]
×
605
      else
×
606
        process.exitCode = 1
×
UNCOV
607
        throw error
×
608

1✔
609
// build/build.sh adds a call to cli() at the end here
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc