-
-
Notifications
You must be signed in to change notification settings - Fork 636
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add dumper and upgrade edge.js with new stacks functionality
- Loading branch information
1 parent
b75f122
commit f6e05ba
Showing
14 changed files
with
516 additions
and
19 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
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,21 @@ | ||
/* | ||
* @adonisjs/core | ||
* | ||
* (c) AdonisJS | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { ConsoleDumpConfig } from '@poppinss/dumper/console/types' | ||
import { HTMLDumpConfig } from '@poppinss/dumper/html/types' | ||
|
||
/** | ||
* Define config for the dumper service exported by | ||
* the "@adonisjs/core/services/dumper" module | ||
*/ | ||
export function defineConfig( | ||
dumperConfig: Partial<{ html: HTMLDumpConfig; console: ConsoleDumpConfig }> | ||
) { | ||
return dumperConfig | ||
} |
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,139 @@ | ||
/* | ||
* @adonisjs/core | ||
* | ||
* (c) AdonisJS | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { dump as consoleDump } from '@poppinss/dumper/console' | ||
import type { HTMLDumpConfig } from '@poppinss/dumper/html/types' | ||
import type { ConsoleDumpConfig } from '@poppinss/dumper/console/types' | ||
import { createScript, createStyleSheet, dump } from '@poppinss/dumper/html' | ||
|
||
import type { Application } from '../app.js' | ||
import { E_DUMP_DIE_EXCEPTION } from './errors.js' | ||
|
||
const DUMP_TITLE_STYLES = ` | ||
.adonisjs-dump-header { | ||
font-family: JetBrains Mono, monaspace argon, Menlo, Monaco, Consolas, monospace; | ||
background: #ff1639; | ||
border-radius: 4px; | ||
color: #fff; | ||
border-bottom-left-radius: 0; | ||
border-bottom-right-radius: 0; | ||
padding: 0.4rem 1.2rem; | ||
font-size: 1em; | ||
display: flex; | ||
justify-content: space-between; | ||
} | ||
.adonisjs-dump-header .adonisjs-dump-header-title { | ||
font-weight: bold; | ||
text-transform: uppercase; | ||
} | ||
.adonisjs-dump-header .adonisjs-dump-header-source { | ||
font-weight: bold; | ||
color: inherit; | ||
text-decoration: underline; | ||
} | ||
.dumper-dump pre { | ||
border-radius: 4px; | ||
border-top-left-radius: 0; | ||
border-top-right-radius: 0; | ||
}` | ||
|
||
/** | ||
* Dumper exposes the API to dump or die/dump values via your | ||
* AdonisJS application. An singleton instance of the Dumper | ||
* is shared as a service and may use it follows. | ||
* | ||
* ```ts | ||
* dumper.configureHtmlOutput({ | ||
* // parser + html formatter config | ||
* }) | ||
* | ||
* dumper.configureAnsiOutput({ | ||
* // parser + console formatter config | ||
* }) | ||
* | ||
* const html = dumper.dumpToHtml(value) | ||
* const ansi = dumper.dumpToAnsi(value) | ||
* | ||
* // Returns style and script tags that must be | ||
* // injeted to the head of the HTML document | ||
* const head = dumper.getHeadElements() | ||
* ``` | ||
*/ | ||
export class Dumper { | ||
#app: Application<any> | ||
#htmlConfig: HTMLDumpConfig = {} | ||
#consoleConfig: ConsoleDumpConfig = { | ||
collapse: ['DateTime', 'Date'], | ||
} | ||
|
||
constructor(app: Application<any>) { | ||
this.#app = app | ||
} | ||
|
||
/** | ||
* Configure the HTML formatter output | ||
*/ | ||
configureHtmlOutput(config: HTMLDumpConfig): this { | ||
this.#htmlConfig = config | ||
return this | ||
} | ||
|
||
/** | ||
* Configure the ANSI formatter output | ||
*/ | ||
configureAnsiOutput(config: ConsoleDumpConfig): this { | ||
this.#consoleConfig = config | ||
return this | ||
} | ||
|
||
/** | ||
* Returns the style and the script elements for the | ||
* HTML document | ||
*/ | ||
getHeadElements(cspNonce?: string): string { | ||
return ( | ||
'<style id="dumper-styles">' + | ||
createStyleSheet() + | ||
DUMP_TITLE_STYLES + | ||
'</style>' + | ||
`<script id="dumper-script"${cspNonce ? ` nonce="${cspNonce}"` : ''}>` + | ||
createScript() + | ||
'</script>' | ||
) | ||
} | ||
|
||
/** | ||
* Dump value to HTML ouput | ||
*/ | ||
dumpToHtml(value: unknown, cspNonce?: string) { | ||
return dump(value, { cspNonce, ...this.#htmlConfig }) | ||
} | ||
|
||
/** | ||
* Dump value to ANSI output | ||
*/ | ||
dumpToAnsi(value: unknown) { | ||
return consoleDump(value, this.#consoleConfig) | ||
} | ||
|
||
/** | ||
* Dump values and die. The formatter will be picked | ||
* based upon where your app is running. | ||
* | ||
* - In CLI commands, the ANSI output will be printed | ||
* to the console. | ||
* - During an HTTP request, the HTML output will be | ||
* sent to the server. | ||
*/ | ||
dd(value: unknown, traceSourceIndex: number = 1) { | ||
const error = new E_DUMP_DIE_EXCEPTION(value, this, this.#app) | ||
error.setTraceSourceIndex(traceSourceIndex) | ||
throw error | ||
} | ||
} |
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,141 @@ | ||
/* | ||
* @adonisjs/core | ||
* | ||
* (c) AdonisJS | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { inspect } from 'node:util' | ||
import { parse } from 'error-stack-parser-es' | ||
import type { Kernel } from '@adonisjs/core/ace' | ||
import { Exception } from '@poppinss/utils/exception' | ||
import type { HttpContext } from '@adonisjs/core/http' | ||
import type { ApplicationService } from '@adonisjs/core/types' | ||
|
||
import type { Dumper } from './dumper.js' | ||
|
||
const IDE = process.env.ADONIS_IDE ?? process.env.EDITOR ?? '' | ||
|
||
/** | ||
* DumpDie exception is raised by the "dd" function. It will | ||
* result in dumping the value in response to an HTTP | ||
* request or printing the value to the console | ||
*/ | ||
class DumpDieException extends Exception { | ||
static status: number = 500 | ||
static code: string = 'E_DUMP_DIE_EXCEPTION' | ||
|
||
#app: ApplicationService | ||
#dumper: Dumper | ||
#traceSourceIndex: number = 1 | ||
|
||
/** | ||
* A collections of known editors to create URLs to open | ||
* them | ||
*/ | ||
#editors: Record<string, string> = { | ||
textmate: 'txmt://open?url=file://%f&line=%l', | ||
macvim: 'mvim://open?url=file://%f&line=%l', | ||
emacs: 'emacs://open?url=file://%f&line=%l', | ||
sublime: 'subl://open?url=file://%f&line=%l', | ||
phpstorm: 'phpstorm://open?file=%f&line=%l', | ||
atom: 'atom://core/open/file?filename=%f&line=%l', | ||
vscode: 'vscode://file/%f:%l', | ||
} | ||
|
||
value: unknown | ||
|
||
constructor(value: unknown, dumper: Dumper, app: ApplicationService) { | ||
super('Dump and Die exception') | ||
this.#dumper = dumper | ||
this.#app = app | ||
this.value = value | ||
} | ||
|
||
/** | ||
* Returns the link to open the file using dd inside one | ||
* of the known code editors | ||
*/ | ||
#getEditorLink(): { href: string; text: string } | undefined { | ||
const editorURL = this.#editors[IDE] || IDE | ||
if (!editorURL) { | ||
return | ||
} | ||
|
||
const source = parse(this)[this.#traceSourceIndex] | ||
if (!source.fileName || !source.lineNumber) { | ||
return | ||
} | ||
|
||
return { | ||
href: editorURL.replace('%f', source.fileName).replace('%l', String(source.lineNumber)), | ||
text: `${this.#app.relativePath(source.fileName)}:${source.lineNumber}`, | ||
} | ||
} | ||
|
||
/** | ||
* Set the index for the trace source. This is helpful when | ||
* you build nested helpers on top of Die/Dump | ||
*/ | ||
setTraceSourceIndex(index: number) { | ||
this.#traceSourceIndex = index | ||
return this | ||
} | ||
|
||
/** | ||
* Preventing itself from getting reported by the | ||
* AdonisJS exception reporter | ||
*/ | ||
report() {} | ||
|
||
/** | ||
* Handler called by the AdonisJS HTTP exception handler | ||
*/ | ||
async handle(error: DumpDieException, ctx: HttpContext) { | ||
const link = this.#getEditorLink() | ||
/** | ||
* Comes from the shield package | ||
*/ | ||
const cspNonce = 'nonce' in ctx.response ? ctx.response.nonce : undefined | ||
|
||
ctx.response | ||
.status(500) | ||
.send( | ||
'<!DOCTYPE html>' + | ||
'<html>' + | ||
'<head>' + | ||
'<meta charset="utf-8">' + | ||
'<meta name="viewport" content="width=device-width">' + | ||
`${this.#dumper.getHeadElements(cspNonce)}` + | ||
'</head>' + | ||
'<body>' + | ||
'<div class="adonisjs-dump-header">' + | ||
'<span class="adonisjs-dump-header-title">DUMP DIE</span>' + | ||
(link | ||
? `<a href="${link.href}" class="adonisjs-dump-header-source">${link.text}</a>` | ||
: '') + | ||
'</div>' + | ||
`${this.#dumper.dumpToHtml(error.value, cspNonce)}` + | ||
'</body>' + | ||
'</html>' | ||
) | ||
} | ||
|
||
/** | ||
* Handler called by the AdonisJS Ace kernel | ||
*/ | ||
async render(error: DumpDieException, kernel: Kernel) { | ||
kernel.ui.logger.log(this.#dumper.dumpToAnsi(error.value)) | ||
} | ||
|
||
/** | ||
* Custom output for the Node.js util inspect | ||
*/ | ||
[inspect.custom]() { | ||
return this.#dumper.dumpToAnsi(this.value) | ||
} | ||
} | ||
|
||
export const E_DUMP_DIE_EXCEPTION = DumpDieException |
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,12 @@ | ||
/* | ||
* @adonisjs/core | ||
* | ||
* (c) AdonisJS | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
export * as errors from './errors.js' | ||
export { Dumper } from './dumper.js' | ||
export { defineConfig } from './define_config.js' |
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
Oops, something went wrong.