Commit a69ddd4
Changed files (8)
src/core.ts
@@ -25,6 +25,12 @@ import { type Readable, type Writable } from 'node:stream'
import { inspect } from 'node:util'
import { EOL as _EOL } from 'node:os'
import { EventEmitter } from 'node:events'
+import {
+ formatErrorMessage,
+ formatExitMessage,
+ getCallerLocation,
+ getExitCodeInfo,
+} from './error.js'
import {
exec,
buildCmd,
@@ -39,10 +45,7 @@ import {
} from './vendor-core.js'
import {
type Duration,
- errnoMessage,
- exitCodeInfo,
formatCmd,
- getCallerLocation,
isString,
isStringLiteral,
noop,
@@ -720,34 +723,9 @@ export class ProcessOutput extends Error {
return this._duration
}
- static getExitMessage(
- code: number | null,
- signal: NodeJS.Signals | null,
- stderr: string,
- from: string
- ): string {
- let message = `exit code: ${code}`
- if (code != 0 || signal != null) {
- message = `${stderr || '\n'} at ${from}`
- message += `\n exit code: ${code}${
- exitCodeInfo(code) ? ' (' + exitCodeInfo(code) + ')' : ''
- }`
- if (signal != null) {
- message += `\n signal: ${signal}`
- }
- }
-
- return message
- }
+ static getExitMessage = formatExitMessage
- static getErrorMessage(err: NodeJS.ErrnoException, from: string): string {
- return (
- `${err.message}\n` +
- ` errno: ${err.errno} (${errnoMessage(err.errno)})\n` +
- ` code: ${err.code}\n` +
- ` at ${from}`
- )
- }
+ static getErrorMessage = formatErrorMessage;
[inspect.custom](): string {
let stringify = (s: string, c: ChalkInstance) =>
@@ -757,8 +735,8 @@ export class ProcessOutput extends Error {
stderr: ${stringify(this.stderr, chalk.red)},
signal: ${inspect(this.signal)},
exitCode: ${(this.exitCode === 0 ? chalk.green : chalk.red)(this.exitCode)}${
- exitCodeInfo(this.exitCode)
- ? chalk.grey(' (' + exitCodeInfo(this.exitCode) + ')')
+ getExitCodeInfo(this.exitCode)
+ ? chalk.grey(' (' + getExitCodeInfo(this.exitCode) + ')')
: ''
},
duration: ${this.duration}
src/error.ts
@@ -0,0 +1,226 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+const EXIT_CODES = {
+ 2: 'Misuse of shell builtins',
+ 126: 'Invoked command cannot execute',
+ 127: 'Command not found',
+ 128: 'Invalid exit argument',
+ 129: 'Hangup',
+ 130: 'Interrupt',
+ 131: 'Quit and dump core',
+ 132: 'Illegal instruction',
+ 133: 'Trace/breakpoint trap',
+ 134: 'Process aborted',
+ 135: 'Bus error: "access to undefined portion of memory object"',
+ 136: 'Floating point exception: "erroneous arithmetic operation"',
+ 137: 'Kill (terminate immediately)',
+ 138: 'User-defined 1',
+ 139: 'Segmentation violation',
+ 140: 'User-defined 2',
+ 141: 'Write to pipe with no one reading',
+ 142: 'Signal raised by alarm',
+ 143: 'Termination (request to terminate)',
+ 145: 'Child process terminated, stopped (or continued*)',
+ 146: 'Continue if stopped',
+ 147: 'Stop executing temporarily',
+ 148: 'Terminal stop signal',
+ 149: 'Background process attempting to read from tty ("in")',
+ 150: 'Background process attempting to write to tty ("out")',
+ 151: 'Urgent data available on socket',
+ 152: 'CPU time limit exceeded',
+ 153: 'File size limit exceeded',
+ 154: 'Signal raised by timer counting virtual time: "virtual timer expired"',
+ 155: 'Profiling timer expired',
+ 157: 'Pollable event',
+ 159: 'Bad syscall',
+}
+
+const ERRNO_CODES = {
+ 0: 'Success',
+ 1: 'Not super-user',
+ 2: 'No such file or directory',
+ 3: 'No such process',
+ 4: 'Interrupted system call',
+ 5: 'I/O error',
+ 6: 'No such device or address',
+ 7: 'Arg list too long',
+ 8: 'Exec format error',
+ 9: 'Bad file number',
+ 10: 'No children',
+ 11: 'No more processes',
+ 12: 'Not enough core',
+ 13: 'Permission denied',
+ 14: 'Bad address',
+ 15: 'Block device required',
+ 16: 'Mount device busy',
+ 17: 'File exists',
+ 18: 'Cross-device link',
+ 19: 'No such device',
+ 20: 'Not a directory',
+ 21: 'Is a directory',
+ 22: 'Invalid argument',
+ 23: 'Too many open files in system',
+ 24: 'Too many open files',
+ 25: 'Not a typewriter',
+ 26: 'Text file busy',
+ 27: 'File too large',
+ 28: 'No space left on device',
+ 29: 'Illegal seek',
+ 30: 'Read only file system',
+ 31: 'Too many links',
+ 32: 'Broken pipe',
+ 33: 'Math arg out of domain of func',
+ 34: 'Math result not representable',
+ 35: 'File locking deadlock error',
+ 36: 'File or path name too long',
+ 37: 'No record locks available',
+ 38: 'Function not implemented',
+ 39: 'Directory not empty',
+ 40: 'Too many symbolic links',
+ 42: 'No message of desired type',
+ 43: 'Identifier removed',
+ 44: 'Channel number out of range',
+ 45: 'Level 2 not synchronized',
+ 46: 'Level 3 halted',
+ 47: 'Level 3 reset',
+ 48: 'Link number out of range',
+ 49: 'Protocol driver not attached',
+ 50: 'No CSI structure available',
+ 51: 'Level 2 halted',
+ 52: 'Invalid exchange',
+ 53: 'Invalid request descriptor',
+ 54: 'Exchange full',
+ 55: 'No anode',
+ 56: 'Invalid request code',
+ 57: 'Invalid slot',
+ 59: 'Bad font file fmt',
+ 60: 'Device not a stream',
+ 61: 'No data (for no delay io)',
+ 62: 'Timer expired',
+ 63: 'Out of streams resources',
+ 64: 'Machine is not on the network',
+ 65: 'Package not installed',
+ 66: 'The object is remote',
+ 67: 'The link has been severed',
+ 68: 'Advertise error',
+ 69: 'Srmount error',
+ 70: 'Communication error on send',
+ 71: 'Protocol error',
+ 72: 'Multihop attempted',
+ 73: 'Cross mount point (not really error)',
+ 74: 'Trying to read unreadable message',
+ 75: 'Value too large for defined data type',
+ 76: 'Given log. name not unique',
+ 77: 'f.d. invalid for this operation',
+ 78: 'Remote address changed',
+ 79: 'Can access a needed shared lib',
+ 80: 'Accessing a corrupted shared lib',
+ 81: '.lib section in a.out corrupted',
+ 82: 'Attempting to link in too many libs',
+ 83: 'Attempting to exec a shared library',
+ 84: 'Illegal byte sequence',
+ 86: 'Streams pipe error',
+ 87: 'Too many users',
+ 88: 'Socket operation on non-socket',
+ 89: 'Destination address required',
+ 90: 'Message too long',
+ 91: 'Protocol wrong type for socket',
+ 92: 'Protocol not available',
+ 93: 'Unknown protocol',
+ 94: 'Socket type not supported',
+ 95: 'Not supported',
+ 96: 'Protocol family not supported',
+ 97: 'Address family not supported by protocol family',
+ 98: 'Address already in use',
+ 99: 'Address not available',
+ 100: 'Network interface is not configured',
+ 101: 'Network is unreachable',
+ 102: 'Connection reset by network',
+ 103: 'Connection aborted',
+ 104: 'Connection reset by peer',
+ 105: 'No buffer space available',
+ 106: 'Socket is already connected',
+ 107: 'Socket is not connected',
+ 108: "Can't send after socket shutdown",
+ 109: 'Too many references',
+ 110: 'Connection timed out',
+ 111: 'Connection refused',
+ 112: 'Host is down',
+ 113: 'Host is unreachable',
+ 114: 'Socket already connected',
+ 115: 'Connection already in progress',
+ 116: 'Stale file handle',
+ 122: 'Quota exceeded',
+ 123: 'No medium (in tape drive)',
+ 125: 'Operation canceled',
+ 130: 'Previous owner died',
+ 131: 'State not recoverable',
+}
+
+export function getErrnoMessage(errno?: number): string {
+ return (
+ ERRNO_CODES[-(errno as number) as keyof typeof ERRNO_CODES] ||
+ 'Unknown error'
+ )
+}
+
+export function getExitCodeInfo(exitCode: number | null): string | undefined {
+ return EXIT_CODES[exitCode as keyof typeof EXIT_CODES]
+}
+
+export const formatExitMessage = (
+ code: number | null,
+ signal: NodeJS.Signals | null,
+ stderr: string,
+ from: string
+) => {
+ let message = `exit code: ${code}`
+ if (code != 0 || signal != null) {
+ message = `${stderr || '\n'} at ${from}`
+ message += `\n exit code: ${code}${
+ getExitCodeInfo(code) ? ' (' + getExitCodeInfo(code) + ')' : ''
+ }`
+ if (signal != null) {
+ message += `\n signal: ${signal}`
+ }
+ }
+
+ return message
+}
+
+export const formatErrorMessage = (
+ err: NodeJS.ErrnoException,
+ from: string
+) => {
+ return (
+ `${err.message}\n` +
+ ` errno: ${err.errno} (${getErrnoMessage(err.errno)})\n` +
+ ` code: ${err.code}\n` +
+ ` at ${from}`
+ )
+}
+
+export function getCallerLocation(err = new Error('zx error')) {
+ return getCallerLocationFromString(err.stack)
+}
+
+export function getCallerLocationFromString(stackString = 'unknown') {
+ return (
+ stackString
+ .split(/^\s*(at\s)?/m)
+ .filter((s) => s?.includes(':'))[2]
+ ?.trim() || stackString
+ )
+}
src/util.ts
@@ -121,174 +121,6 @@ export function quotePowerShell(arg: string): string {
return `'` + arg.replace(/'/g, "''") + `'`
}
-const EXIT_CODES = {
- 2: 'Misuse of shell builtins',
- 126: 'Invoked command cannot execute',
- 127: 'Command not found',
- 128: 'Invalid exit argument',
- 129: 'Hangup',
- 130: 'Interrupt',
- 131: 'Quit and dump core',
- 132: 'Illegal instruction',
- 133: 'Trace/breakpoint trap',
- 134: 'Process aborted',
- 135: 'Bus error: "access to undefined portion of memory object"',
- 136: 'Floating point exception: "erroneous arithmetic operation"',
- 137: 'Kill (terminate immediately)',
- 138: 'User-defined 1',
- 139: 'Segmentation violation',
- 140: 'User-defined 2',
- 141: 'Write to pipe with no one reading',
- 142: 'Signal raised by alarm',
- 143: 'Termination (request to terminate)',
- 145: 'Child process terminated, stopped (or continued*)',
- 146: 'Continue if stopped',
- 147: 'Stop executing temporarily',
- 148: 'Terminal stop signal',
- 149: 'Background process attempting to read from tty ("in")',
- 150: 'Background process attempting to write to tty ("out")',
- 151: 'Urgent data available on socket',
- 152: 'CPU time limit exceeded',
- 153: 'File size limit exceeded',
- 154: 'Signal raised by timer counting virtual time: "virtual timer expired"',
- 155: 'Profiling timer expired',
- 157: 'Pollable event',
- 159: 'Bad syscall',
-}
-
-export function exitCodeInfo(exitCode: number | null): string | undefined {
- return EXIT_CODES[exitCode as keyof typeof EXIT_CODES]
-}
-
-const ERRNO_CODES = {
- 0: 'Success',
- 1: 'Not super-user',
- 2: 'No such file or directory',
- 3: 'No such process',
- 4: 'Interrupted system call',
- 5: 'I/O error',
- 6: 'No such device or address',
- 7: 'Arg list too long',
- 8: 'Exec format error',
- 9: 'Bad file number',
- 10: 'No children',
- 11: 'No more processes',
- 12: 'Not enough core',
- 13: 'Permission denied',
- 14: 'Bad address',
- 15: 'Block device required',
- 16: 'Mount device busy',
- 17: 'File exists',
- 18: 'Cross-device link',
- 19: 'No such device',
- 20: 'Not a directory',
- 21: 'Is a directory',
- 22: 'Invalid argument',
- 23: 'Too many open files in system',
- 24: 'Too many open files',
- 25: 'Not a typewriter',
- 26: 'Text file busy',
- 27: 'File too large',
- 28: 'No space left on device',
- 29: 'Illegal seek',
- 30: 'Read only file system',
- 31: 'Too many links',
- 32: 'Broken pipe',
- 33: 'Math arg out of domain of func',
- 34: 'Math result not representable',
- 35: 'File locking deadlock error',
- 36: 'File or path name too long',
- 37: 'No record locks available',
- 38: 'Function not implemented',
- 39: 'Directory not empty',
- 40: 'Too many symbolic links',
- 42: 'No message of desired type',
- 43: 'Identifier removed',
- 44: 'Channel number out of range',
- 45: 'Level 2 not synchronized',
- 46: 'Level 3 halted',
- 47: 'Level 3 reset',
- 48: 'Link number out of range',
- 49: 'Protocol driver not attached',
- 50: 'No CSI structure available',
- 51: 'Level 2 halted',
- 52: 'Invalid exchange',
- 53: 'Invalid request descriptor',
- 54: 'Exchange full',
- 55: 'No anode',
- 56: 'Invalid request code',
- 57: 'Invalid slot',
- 59: 'Bad font file fmt',
- 60: 'Device not a stream',
- 61: 'No data (for no delay io)',
- 62: 'Timer expired',
- 63: 'Out of streams resources',
- 64: 'Machine is not on the network',
- 65: 'Package not installed',
- 66: 'The object is remote',
- 67: 'The link has been severed',
- 68: 'Advertise error',
- 69: 'Srmount error',
- 70: 'Communication error on send',
- 71: 'Protocol error',
- 72: 'Multihop attempted',
- 73: 'Cross mount point (not really error)',
- 74: 'Trying to read unreadable message',
- 75: 'Value too large for defined data type',
- 76: 'Given log. name not unique',
- 77: 'f.d. invalid for this operation',
- 78: 'Remote address changed',
- 79: 'Can access a needed shared lib',
- 80: 'Accessing a corrupted shared lib',
- 81: '.lib section in a.out corrupted',
- 82: 'Attempting to link in too many libs',
- 83: 'Attempting to exec a shared library',
- 84: 'Illegal byte sequence',
- 86: 'Streams pipe error',
- 87: 'Too many users',
- 88: 'Socket operation on non-socket',
- 89: 'Destination address required',
- 90: 'Message too long',
- 91: 'Protocol wrong type for socket',
- 92: 'Protocol not available',
- 93: 'Unknown protocol',
- 94: 'Socket type not supported',
- 95: 'Not supported',
- 96: 'Protocol family not supported',
- 97: 'Address family not supported by protocol family',
- 98: 'Address already in use',
- 99: 'Address not available',
- 100: 'Network interface is not configured',
- 101: 'Network is unreachable',
- 102: 'Connection reset by network',
- 103: 'Connection aborted',
- 104: 'Connection reset by peer',
- 105: 'No buffer space available',
- 106: 'Socket is already connected',
- 107: 'Socket is not connected',
- 108: "Can't send after socket shutdown",
- 109: 'Too many references',
- 110: 'Connection timed out',
- 111: 'Connection refused',
- 112: 'Host is down',
- 113: 'Host is unreachable',
- 114: 'Socket already connected',
- 115: 'Connection already in progress',
- 116: 'Stale file handle',
- 122: 'Quota exceeded',
- 123: 'No medium (in tape drive)',
- 125: 'Operation canceled',
- 130: 'Previous owner died',
- 131: 'State not recoverable',
-}
-
-export function errnoMessage(errno?: number): string {
- return (
- ERRNO_CODES[-(errno as number) as keyof typeof ERRNO_CODES] ||
- 'Unknown error'
- )
-}
-
export type Duration = number | `${number}m` | `${number}s` | `${number}ms`
export function parseDuration(d: Duration) {
@@ -427,19 +259,6 @@ const RESERVED_WORDS = new Set([
'in',
])
-export function getCallerLocation(err = new Error()) {
- return getCallerLocationFromString(err.stack)
-}
-
-export function getCallerLocationFromString(stackString = 'unknown') {
- return (
- stackString
- .split(/^\s*(at\s)?/m)
- .filter((s) => s?.includes(':'))[2]
- ?.trim() || stackString
- )
-}
-
export const once = <T extends (...args: any[]) => any>(fn: T) => {
let called = false
let result: ReturnType<T>
test/all.test.js
@@ -15,6 +15,7 @@
import './cli.test.js'
import './core.test.js'
import './deps.test.js'
+import './error.test.ts'
import './global.test.js'
import './goods.test.js'
import './index.test.js'
test/core.test.js
@@ -997,6 +997,27 @@ describe('core', () => {
assert.throws(() => o.blob(), /Blob is not supported/)
globalThis.Blob = Blob
})
+
+ describe('static', () => {
+ test('getExitMessage()', () => {
+ assert.match(
+ ProcessOutput.getExitMessage(2, null, '', ''),
+ /Misuse of shell builtins/
+ )
+ })
+
+ test('getErrorMessage()', () => {
+ assert.match(
+ ProcessOutput.getErrorMessage({ errno: -2 }, ''),
+ /No such file or directory/
+ )
+ assert.match(
+ ProcessOutput.getErrorMessage({ errno: -1e9 }, ''),
+ /Unknown error/
+ )
+ assert.match(ProcessOutput.getErrorMessage({}, ''), /Unknown error/)
+ })
+ })
})
describe('cd()', () => {
test/error.test.ts
@@ -0,0 +1,112 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import assert from 'node:assert'
+import { test, describe } from 'node:test'
+import {
+ getErrnoMessage,
+ getExitCodeInfo,
+ getCallerLocation,
+ getCallerLocationFromString,
+ formatExitMessage,
+ formatErrorMessage,
+} from '../src/error.ts'
+
+describe('error', () => {
+ test('getExitCodeInfo()', () => {
+ assert.equal(getExitCodeInfo(2), 'Misuse of shell builtins')
+ })
+
+ test('getErrnoMessage()', () => {
+ assert.equal(getErrnoMessage(-2), 'No such file or directory')
+ assert.equal(getErrnoMessage(1e9), 'Unknown error')
+ assert.equal(getErrnoMessage(undefined), 'Unknown error')
+ })
+
+ describe('getCallerLocation()', () => {
+ assert.match(getCallerLocation(new Error('Foo')), /Suite\.runInAsyncScope/)
+ })
+
+ describe('getCallerLocationFromString()', () => {
+ test('empty', () => {
+ assert.equal(getCallerLocationFromString(), 'unknown')
+ })
+
+ test('no-match', () => {
+ assert.equal(
+ getCallerLocationFromString('stack\nstring'),
+ 'stack\nstring'
+ )
+ })
+
+ test(`getCallerLocationFromString-v8`, () => {
+ const stack = `
+ Error
+ at getCallerLocation (/Users/user/test.js:22:17)
+ at e (/Users/user/test.js:34:13)
+ at d (/Users/user/test.js:11:5)
+ at c (/Users/user/test.js:8:5)
+ at b (/Users/user/test.js:5:5)
+ at a (/Users/user/test.js:2:5)
+ at Object.<anonymous> (/Users/user/test.js:37:1)
+ at Module._compile (node:internal/modules/cjs/loader:1254:14)
+ at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
+ at Module.load (node:internal/modules/cjs/loader:1117:32)
+ at Module._load (node:internal/modules/cjs/loader:958:12)
+ `
+ assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
+ })
+
+ test(`getCallerLocationFromString-JSC`, () => {
+ const stack = `
+ getCallerLocation@/Users/user/test.js:22:17
+ e@/Users/user/test.js:34:13
+ d@/Users/user/test.js:11:5
+ c@/Users/user/test.js:8:5
+ b@/Users/user/test.js:5:5
+ a@/Users/user/test.js:2:5
+ module code@/Users/user/test.js:37:1
+ evaluate@[native code]
+ moduleEvaluation@[native code]
+ moduleEvaluation@[native code]
+ @[native code]
+ asyncFunctionResume@[native code]
+ promiseReactionJobWithoutPromise@[native code]
+ promiseReactionJob@[native code]
+ d@/Users/user/test.js:11:5
+ `
+ assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
+ })
+ })
+
+ test('getExitMessage()', () => {
+ assert.match(formatExitMessage(2, null, '', ''), /Misuse of shell builtins/)
+ assert.match(formatExitMessage(1, 'SIGKILL', '', ''), /SIGKILL/)
+ })
+
+ test('getErrorMessage()', () => {
+ assert.match(
+ formatErrorMessage({ errno: -2 } as NodeJS.ErrnoException, ''),
+ /No such file or directory/
+ )
+ assert.match(
+ formatErrorMessage({ errno: -1e9 } as NodeJS.ErrnoException, ''),
+ /Unknown error/
+ )
+ assert.match(
+ formatErrorMessage({} as NodeJS.ErrnoException, ''),
+ /Unknown error/
+ )
+ })
+})
test/util.test.js
@@ -16,8 +16,6 @@ import assert from 'node:assert'
import fs from 'node:fs'
import { test, describe } from 'node:test'
import {
- exitCodeInfo,
- errnoMessage,
formatCmd,
isString,
isStringLiteral,
@@ -27,7 +25,6 @@ import {
quotePowerShell,
randomId,
// normalizeMultilinePieces,
- getCallerLocationFromString,
tempdir,
tempfile,
preferLocalBin,
@@ -36,16 +33,6 @@ import {
} from '../build/util.js'
describe('util', () => {
- test('exitCodeInfo()', () => {
- assert.equal(exitCodeInfo(2), 'Misuse of shell builtins')
- })
-
- test('errnoMessage()', () => {
- assert.equal(errnoMessage(-2), 'No such file or directory')
- assert.equal(errnoMessage(1e9), 'Unknown error')
- assert.equal(errnoMessage(undefined), 'Unknown error')
- })
-
test('randomId()', () => {
assert.ok(/^[a-z0-9]+$/.test(randomId()))
assert.ok(
@@ -120,90 +107,43 @@ describe('util', () => {
// ' a ,b c d, e'
// )
// })
-})
-
-test('getCallerLocation: empty', () => {
- assert.equal(getCallerLocationFromString(), 'unknown')
-})
-
-test('getCallerLocation: no-match', () => {
- assert.equal(getCallerLocationFromString('stack\nstring'), 'stack\nstring')
-})
-
-test(`getCallerLocationFromString-v8`, () => {
- const stack = `
- Error
- at getCallerLocation (/Users/user/test.js:22:17)
- at e (/Users/user/test.js:34:13)
- at d (/Users/user/test.js:11:5)
- at c (/Users/user/test.js:8:5)
- at b (/Users/user/test.js:5:5)
- at a (/Users/user/test.js:2:5)
- at Object.<anonymous> (/Users/user/test.js:37:1)
- at Module._compile (node:internal/modules/cjs/loader:1254:14)
- at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
- at Module.load (node:internal/modules/cjs/loader:1117:32)
- at Module._load (node:internal/modules/cjs/loader:958:12)
- `
- assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
-})
-
-test(`getCallerLocationFromString-JSC`, () => {
- const stack = `
- getCallerLocation@/Users/user/test.js:22:17
- e@/Users/user/test.js:34:13
- d@/Users/user/test.js:11:5
- c@/Users/user/test.js:8:5
- b@/Users/user/test.js:5:5
- a@/Users/user/test.js:2:5
- module code@/Users/user/test.js:37:1
- evaluate@[native code]
- moduleEvaluation@[native code]
- moduleEvaluation@[native code]
- @[native code]
- asyncFunctionResume@[native code]
- promiseReactionJobWithoutPromise@[native code]
- promiseReactionJob@[native code]
- d@/Users/user/test.js:11:5
- `
- assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
-})
-test('tempdir() creates temporary folders', () => {
- assert.match(tempdir(), /\/zx-/)
- assert.match(tempdir('foo'), /\/foo$/)
-})
+ test('tempdir() creates temporary folders', () => {
+ assert.match(tempdir(), /\/zx-/)
+ assert.match(tempdir('foo'), /\/foo$/)
+ })
-test('tempfile() creates temporary files', () => {
- assert.match(tempfile(), /\/zx-.+/)
- assert.match(tempfile('foo.txt'), /\/zx-.+\/foo\.txt$/)
+ test('tempfile() creates temporary files', () => {
+ assert.match(tempfile(), /\/zx-.+/)
+ assert.match(tempfile('foo.txt'), /\/zx-.+\/foo\.txt$/)
- const tf = tempfile('bar.txt', 'bar')
- assert.match(tf, /\/zx-.+\/bar\.txt$/)
- assert.equal(fs.readFileSync(tf, 'utf-8'), 'bar')
-})
+ const tf = tempfile('bar.txt', 'bar')
+ assert.match(tf, /\/zx-.+\/bar\.txt$/)
+ assert.equal(fs.readFileSync(tf, 'utf-8'), 'bar')
+ })
-test('preferLocalBin()', () => {
- const env = {
- PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin',
- }
- const _env = preferLocalBin(env, process.cwd())
- assert.equal(
- _env.PATH,
- `${process.cwd()}/node_modules/.bin:${process.cwd()}:${env.PATH}`
- )
-})
+ test('preferLocalBin()', () => {
+ const env = {
+ PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin',
+ }
+ const _env = preferLocalBin(env, process.cwd())
+ assert.equal(
+ _env.PATH,
+ `${process.cwd()}/node_modules/.bin:${process.cwd()}:${env.PATH}`
+ )
+ })
-test('camelToSnake()', () => {
- assert.equal(camelToSnake('verbose'), 'VERBOSE')
- assert.equal(camelToSnake('nothrow'), 'NOTHROW')
- assert.equal(camelToSnake('preferLocal'), 'PREFER_LOCAL')
- assert.equal(camelToSnake('someMoreBigStr'), 'SOME_MORE_BIG_STR')
-})
+ test('camelToSnake()', () => {
+ assert.equal(camelToSnake('verbose'), 'VERBOSE')
+ assert.equal(camelToSnake('nothrow'), 'NOTHROW')
+ assert.equal(camelToSnake('preferLocal'), 'PREFER_LOCAL')
+ assert.equal(camelToSnake('someMoreBigStr'), 'SOME_MORE_BIG_STR')
+ })
-test('snakeToCamel()', () => {
- assert.equal(snakeToCamel('VERBOSE'), 'verbose')
- assert.equal(snakeToCamel('NOTHROW'), 'nothrow')
- assert.equal(snakeToCamel('PREFER_LOCAL'), 'preferLocal')
- assert.equal(snakeToCamel('SOME_MORE_BIG_STR'), 'someMoreBigStr')
+ test('snakeToCamel()', () => {
+ assert.equal(snakeToCamel('VERBOSE'), 'verbose')
+ assert.equal(snakeToCamel('NOTHROW'), 'nothrow')
+ assert.equal(snakeToCamel('PREFER_LOCAL'), 'preferLocal')
+ assert.equal(snakeToCamel('SOME_MORE_BIG_STR'), 'someMoreBigStr')
+ })
})
package.json
@@ -63,10 +63,10 @@
"fmt": "prettier --write .",
"fmt:check": "prettier --check .",
"build": "npm run build:js && npm run build:dts && npm run build:tests",
- "build:js": "node scripts/build-js.mjs --format=cjs --hybrid --entry=src/*.ts && npm run build:vendor",
+ "build:js": "node scripts/build-js.mjs --format=cjs --hybrid --entry=src/*.ts:!src/error.ts && npm run build:vendor",
"build:vendor": "node scripts/build-js.mjs --format=cjs --entry=src/vendor-*.ts --bundle=all",
"build:tests": "node scripts/build-tests.mjs",
- "build:dts": "tsc --project tsconfig.prod.json && node scripts/build-dts.mjs",
+ "build:dts": "tsc --project tsconfig.prod.json && rm build/error.d.ts && node scripts/build-dts.mjs",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs",
@@ -74,7 +74,7 @@
"test": "npm run test:size && npm run fmt:check && npm run test:unit && npm run test:types && npm run test:license",
"test:it": "node ./test/it/build.test.js",
"test:jsr": "node ./test/it/build-jsr.test.js",
- "test:unit": "node ./test/all.test.js",
+ "test:unit": "node --experimental-strip-types ./test/all.test.js",
"test:coverage": "c8 -x build/deno.js -x build/vendor-extra.cjs -x build/vendor-core.cjs -x build/esblib.cjs -x 'test/**' -x scripts --check-coverage npm run test:unit",
"test:circular": "madge --circular src/*",
"test:types": "tsd",