-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
72173eb
commit e7e769e
Showing
14 changed files
with
393 additions
and
210 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nx.js/inspect": patch | ||
--- | ||
|
||
Add `@nx.js/inspect` package |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
title: Installation | ||
--- | ||
|
||
<InstallTabs items={['npm', 'pnpm', 'yarn', 'bun']}> | ||
<Tab value='npm'> | ||
|
||
```bash | ||
npm install @nx.js/inspect | ||
``` | ||
|
||
</Tab> | ||
<Tab value="pnpm"> | ||
|
||
```bash | ||
pnpm add @nx.js/inspect | ||
``` | ||
|
||
</Tab> | ||
<Tab value='yarn'> | ||
|
||
```bash | ||
yarn add @nx.js/inspect | ||
``` | ||
|
||
</Tab> | ||
<Tab value='bun'> | ||
|
||
```bash | ||
bun add @nx.js/inspect | ||
``` | ||
|
||
</Tab> | ||
|
||
</InstallTabs> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"root": true, | ||
"pages": ["--- Usage ---", "index", "--- API Reference ---", "...api"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { createInspect } from './src/index'; | ||
|
||
export const inspect = createInspect(); | ||
|
||
console.log(inspect(Promise.resolve(42))); | ||
console.log(inspect(/test/g)); | ||
console.log(inspect({ a: 1, b: 2, 'c d': 3 })); | ||
console.log(inspect(async () => 42)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "@nx.js/inspect", | ||
"version": "0.0.0", | ||
"description": "JavaScript value inspect utility for nx.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/TooTallNate/nx.js.git", | ||
"directory": "packages/inspect" | ||
}, | ||
"type": "module", | ||
"homepage": "https://nxjs.n8.io/inspect", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "tsc", | ||
"test": "vitest", | ||
"docs": "typedoc && ../../type-aliases-meta.sh" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"dependencies": { | ||
"kleur": "github:TooTallNate/kleur#rgb" | ||
}, | ||
"devDependencies": { | ||
"vite": "^5.4.2", | ||
"vitest": "^2.0.5" | ||
}, | ||
"keywords": [ | ||
"nx.js", | ||
"switch", | ||
"inspect" | ||
], | ||
"author": "Nathan Rajlich <[email protected]>", | ||
"license": "MIT" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
import { bold, cyan, green, magenta, red, rgb, yellow } from 'kleur/colors'; | ||
|
||
const grey = rgb(100, 100, 100); | ||
|
||
export const PROMISE_STATE_UNKNOWN = -1 as const; | ||
export const PROMISE_STATE_PENDING = 0 as const; | ||
export const PROMISE_STATE_FULFILLED = 1 as const; | ||
export const PROMISE_STATE_REJECTED = 2 as const; | ||
|
||
export type PromiseState = | ||
| typeof PROMISE_STATE_UNKNOWN | ||
| typeof PROMISE_STATE_PENDING | ||
| typeof PROMISE_STATE_FULFILLED | ||
| typeof PROMISE_STATE_REJECTED; | ||
|
||
export interface CreateInspectOptions { | ||
getPromiseState?: (p: Promise<unknown>) => [PromiseState, unknown]; | ||
} | ||
|
||
export interface InspectOptions { | ||
depth?: number; | ||
refs?: Map<{}, number>; | ||
} | ||
|
||
export function createInspect(opts?: CreateInspectOptions) { | ||
const { getPromiseState } = opts ?? {}; | ||
|
||
/** | ||
* Inspects a given value and returns a string representation of it. | ||
* The function uses ANSI color codes to highlight different parts of the output. | ||
* It can handle and correctly output different types of values including primitives, functions, arrays, and objects. | ||
* | ||
* @param v The value to inspect. | ||
* @param opts Options which may modify the generated string representation of the value. | ||
* @returns A string representation of `v` with ANSI color codes. | ||
*/ | ||
function inspect(v: unknown, opts: InspectOptions = {}): string { | ||
const { depth = 1 } = opts; | ||
|
||
// Primitives | ||
if (typeof v === 'boolean') { | ||
return bold(yellow(v)); | ||
} | ||
if (typeof v === 'number') { | ||
return bold(yellow(isNegZ(v) ? '-0' : v)); | ||
} | ||
if (typeof v === 'bigint') { | ||
return bold(yellow(`${v}n`)); | ||
} | ||
if (typeof v === 'symbol') { | ||
return green(String(v)); | ||
} | ||
if (typeof v === 'string') { | ||
return green(JSON.stringify(v)); | ||
} | ||
if (typeof v === 'undefined') { | ||
return grey(String(v)); | ||
} | ||
if (v === null) { | ||
return bold(String(v)); | ||
} | ||
|
||
// After this point, all should be typeof "object" or | ||
// "function", so they can have additional properties | ||
// which may be circular references. | ||
const refs = opts.refs ?? new Map(); | ||
const refIndex = refs.get(v); | ||
if (typeof refIndex === 'number') { | ||
return cyan(`[Circular *${refIndex}]`); | ||
} | ||
|
||
refs.set(v, refs.size + 1); | ||
|
||
// If the value defines the `inspect.custom` symbol, then invoke | ||
// the function. If the return value is a string, return that. | ||
// Otherwise, treat the return value as the value to inspect | ||
if (v && typeof (v as any)[inspect.custom] === 'function') { | ||
const c = (v as any)[inspect.custom]({ ...opts, depth }); | ||
if (typeof c === 'string') { | ||
return c; | ||
} | ||
v = c; | ||
} | ||
|
||
if (typeof v === 'function') { | ||
const { name } = v; | ||
if (String(v).startsWith('class')) { | ||
return cyan(`[class${name ? `: ${name}` : ''}]`); | ||
} | ||
return cyan(`[Function${name ? `: ${name}` : ' (anonymous)'}]`); | ||
} | ||
if (Array.isArray(v)) { | ||
const contents = | ||
v.length === 0 | ||
? '' | ||
: ` ${v | ||
.map((e) => inspect(e, { ...opts, refs, depth })) | ||
.join(', ')} `; | ||
return `[${contents}]`; | ||
} | ||
if (isRegExp(v)) { | ||
return bold(red(String(v))); | ||
} | ||
if (isDate(v)) { | ||
return magenta(v.toISOString()); | ||
} | ||
if (isPromise(v)) { | ||
let val = ''; | ||
const [state, result] = getPromiseState?.(v) ?? [ | ||
PROMISE_STATE_UNKNOWN, | ||
undefined, | ||
]; | ||
if (state === PROMISE_STATE_PENDING) { | ||
val = cyan('<pending>'); | ||
} else if (state === PROMISE_STATE_UNKNOWN) { | ||
val = grey('<unknown>'); | ||
} else { | ||
if (state === PROMISE_STATE_REJECTED) { | ||
val = `${red('<rejected>')} `; | ||
} | ||
val += inspect(result, { ...opts, refs, depth }); | ||
} | ||
return `Promise { ${val} }`; | ||
} | ||
if (isError(v)) { | ||
const { stack } = v; | ||
const obj = | ||
Object.keys(v).length > 0 | ||
? ` ${printObject(v, { ...opts, refs, depth })}` | ||
: ''; | ||
return stack ? `${v}\n${stack.trimEnd()}${obj}` : `[${v}]${obj}`; | ||
} | ||
if (isArrayBuffer(v)) { | ||
const contents = new Uint8Array(v); | ||
const b: string[] = []; | ||
for (let i = 0; i < Math.min(50, v.byteLength); i++) { | ||
b.push(contents[i].toString(16).padStart(2, '0')); | ||
} | ||
let c = b.join(' '); | ||
if (contents.length > 50) c += '...'; | ||
const len = inspect(v.byteLength); | ||
return `ArrayBuffer { ${cyan( | ||
'[Uint8Contents]', | ||
)}: <${c}>, byteLength: ${len} }`; | ||
} | ||
if (isTypedArray(v)) { | ||
const b: string[] = []; | ||
for (let i = 0; i < Math.min(50, v.length); i++) { | ||
b.push(inspect(v[i])); | ||
} | ||
let c = b.length === 0 ? '' : ` ${b.join(', ')} `; | ||
if (v.length > 50) c += '...'; | ||
return `${getClass(v)}(${v.length}) [${c}]`; | ||
} | ||
if (typeof v === 'object') { | ||
return printObject(v, { ...opts, refs, depth }); | ||
} | ||
return `? ${v}`; | ||
} | ||
|
||
inspect.custom = Symbol('inspect.custom'); | ||
inspect.keys = Symbol('inspect.keys'); | ||
inspect.values = Symbol('inspect.values'); | ||
inspect.entries = Symbol('inspect.entries'); | ||
|
||
function printObject(v: any, opts: InspectOptions) { | ||
const { depth = 1 } = opts; | ||
const keys = new Set([...(v[inspect.keys]?.() || []), ...Object.keys(v)]); | ||
const ctor = v.constructor; | ||
const className = | ||
ctor && ctor !== Object && typeof ctor.name === 'string' | ||
? `${ctor.name} ` | ||
: ''; | ||
let contents = ''; | ||
let endSpace = ''; | ||
let len = 0; | ||
const parts: string[] = []; | ||
if (typeof v[inspect.values] === 'function') { | ||
for (const val of v[inspect.values]()) { | ||
const l = inspect(val, { ...opts, depth: depth + 1 }); | ||
len += l.length; | ||
parts.push(l); | ||
} | ||
} | ||
if (typeof v[inspect.entries] === 'function') { | ||
for (const [k, val] of v[inspect.entries]()) { | ||
const l = `${inspect(k, { | ||
...opts, | ||
depth: depth + 1, | ||
})} => ${inspect(val, { ...opts, depth: depth + 1 })}`; | ||
len += l.length; | ||
parts.push(l); | ||
} | ||
} | ||
for (const k of keys) { | ||
const l = `${k}: ${inspect(v[k], { ...opts, depth: depth + 1 })}`; | ||
len += l.length; | ||
parts.push(l); | ||
} | ||
if (parts.length > 0) { | ||
if (len > 60) { | ||
const space = ' '.repeat(depth); | ||
contents = parts.map((p) => `\n${space}${p},`).join('') + '\n'; | ||
endSpace = ' '.repeat(depth - 1); | ||
} else { | ||
contents = ` ${parts.join(', ')} `; | ||
} | ||
} | ||
return `${className}{${contents}${endSpace}}`; | ||
} | ||
|
||
return inspect; | ||
} | ||
|
||
function isNegZ(n: number) { | ||
return 1 / n === -Infinity; | ||
} | ||
|
||
function getClass(v: unknown) { | ||
return Object.prototype.toString.call(v).slice(8, -1); | ||
} | ||
|
||
function isDate(v: unknown): v is Date { | ||
return getClass(v) === 'Date'; | ||
} | ||
|
||
function isError(v: unknown): v is Error { | ||
return getClass(v) === 'Error'; | ||
} | ||
|
||
function isRegExp(v: unknown): v is RegExp { | ||
return getClass(v) === 'RegExp'; | ||
} | ||
|
||
function isArrayBuffer(v: unknown): v is ArrayBuffer { | ||
return getClass(v) === 'ArrayBuffer'; | ||
} | ||
|
||
function isTypedArray(v: unknown): v is ArrayLike<number> { | ||
return getClass(v).endsWith('Array'); | ||
} | ||
|
||
function isPromise(v: unknown): v is Promise<unknown> { | ||
return getClass(v) === 'Promise'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"compilerOptions": { | ||
"outDir": "dist", | ||
"target": "es2022", | ||
"declaration": true, | ||
"sourceMap": true, | ||
"moduleResolution": "node", | ||
"forceConsistentCasingInFileNames": true, | ||
"strict": true, | ||
"skipLibCheck": true | ||
}, | ||
"include": [ | ||
"src/**/*.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"$schema": "https://typedoc.org/schema.json", | ||
"extends": ["../../typedoc.json"], | ||
"name": "@nx.js/inspect", | ||
"entryPoints": ["./src/index.ts"], | ||
"out": "docs" | ||
} |
Oops, something went wrong.