Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port parts of Structured Errors to TS + Add two more errors #20597

Merged
merged 15 commits into from
Mar 13, 2020
Merged
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@types/fs-extra": "^8.0.1",
"@types/got": "^9.6.9",
"@types/jest": "^24.0.23",
"@types/joi": "^14.3.4",
"@types/node": "^12.12.11",
"@types/webpack": "^4.41.0",
"@typescript-eslint/eslint-plugin": "^2.12.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-cli/src/reporter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const tracer = require(`opentracing`).globalTracer()

const { getErrorFormatter } = require(`./errors`)
const { getStore } = require(`./redux`)
const constructError = require(`../structured-errors/construct-error`)
import constructError from "../structured-errors/construct-error"

const errorFormatter = getErrorFormatter()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
const constructError = require(`../construct-error`)
import constructError from "../construct-error"

let log
let processExit
beforeEach(() => {
log = jest.spyOn(console, `log`).mockImplementation(() => {})
processExit = jest.spyOn(process, `exit`).mockImplementation(() => {})
processExit = ((jest.spyOn(
process,
`exit`
) as unknown) as jest.Mock).mockImplementation(() => {})

log.mockReset()
processExit.mockReset()
})

afterAll(() => {
console.log.mockClear()
process.exit.mockClear()
;(console.log as jest.Mock).mockClear()
;((process.exit as unknown) as jest.Mock).mockClear()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol what a goofy syntax

})

test(`it exits on invalid error schema`, () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { errorMap, defaultError } = require(`../error-map`)
import { errorMap, defaultError } from "../error-map"

test(`it defaults to generic error`, () => {
expect(defaultError).toEqual(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const schema = require(`../error-schema`)
import schema from "../error-schema"

test(`throws invalid on an invalid error`, () => {
expect(schema.validate({ lol: `true` })).rejects.toBeDefined()
Expand Down
39 changes: 0 additions & 39 deletions packages/gatsby-cli/src/structured-errors/construct-error.js

This file was deleted.

75 changes: 75 additions & 0 deletions packages/gatsby-cli/src/structured-errors/construct-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Joi from "@hapi/joi"
import stackTrace from "stack-trace"
import errorSchema from "./error-schema"
import { errorMap, defaultError, IErrorMapEntry } from "./error-map"
import { sanitizeStructuredStackTrace } from "../reporter/errors"

interface IConstructError {
details: {
id?: keyof typeof errorMap
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now allows for auto completion of all error IDs 👍

context?: Record<string, string>
error?: string
[key: string]: unknown
}
}

interface ILocationPosition {
line: number
column: number
}

interface IStructuredError {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This schema is more or less copied from the joi schema

code?: string
text: string
stack: {
fileName: string
functionName?: string
lineNumber?: number
columnNumber?: number
}[]
filePath?: string
location?: {
start: ILocationPosition
end?: ILocationPosition
}
error?: unknown
group?: string
level: IErrorMapEntry["level"]
type?: IErrorMapEntry["type"]
docsUrl?: string
}

// Merge partial error details with information from the errorMap
// Validate the constructed object against an error schema
const constructError = ({
details: { id, ...otherDetails },
}: IConstructError): IStructuredError => {
const result: IErrorMapEntry = (id && errorMap[id]) || defaultError

// merge
const structuredError: IStructuredError = {
context: {},
...otherDetails,
...result,
text: result.text(otherDetails.context),
stack: otherDetails.error
? sanitizeStructuredStackTrace(stackTrace.parse(otherDetails.error))
: null,
docsUrl: result.docsUrl || `https://gatsby.dev/issue-how-to`,
}

if (id) {
structuredError.code = id
}

// validate
const { error } = Joi.validate(structuredError, errorSchema)
if (error !== null) {
console.log(`Failed to validate error`, error)
process.exit(1)
}

return structuredError
}

export default constructError
Loading