Compare commits

...

9 Commits

Author SHA1 Message Date
Sam Burba 9e5c27c509
docs: Fix readme converter link (#1108) 2023-03-16 11:04:52 -04:00
Jan Piotrowski 601c2f03f4
fix(prisma): Replace outdated note (#1153)Co-authored-by: Andrew Carlson <5479270+andrewicarlson@users.noreply.github.com>
* fix(prisma): Remove outdated note

* Update 010-overview.mdx

---------

Co-authored-by: Andrew Carlson <5479270+andrewicarlson@users.noreply.github.com>
2023-03-16 11:04:26 -04:00
Andrew Carlson 4e085dc7b2
Feature/update docs (#1136)
* Replaced Prisma reference

* Updated copyright info
2023-02-02 10:48:58 -06:00
Alex Kunin 1e6b9212d3
chore: remove irrelevant paragraph in docs (#1128)
Resolver shorthands were removed in v0.18.0, docs need to be updated.
2022-10-31 09:25:32 -04:00
Tim Griesser 4d8e37177b
feat: better esm support, remove top-level node imports (#1112)
* test for esm/esbuild use of nexus

* refactor: add nodeImports, remove top-level references

* Don't minify the esbuild test script

* A bit more explicit of a check on the process being node
2022-07-02 16:08:16 -04:00
Tim Griesser eec4b91091
feat: add sourceType option to fieldDefinition (#1106)
* feat: add sourceType option to fieldDefinition

* add additional configurability for field-level sourceType
2022-06-28 13:21:58 -04:00
Tim Griesser 8e65081539
fix: remove hasSDLDirectives internal state (#1091)
* fix: remove hasSDLDirectives from schema construction
2022-05-16 00:12:23 -04:00
Tim Griesser 7ee48c4f2c
fix: add missing as const on the RequestDirectiveLocation (#1090) 2022-05-15 22:48:26 -04:00
Tim Griesser e9dc7e0c4a chore: Fix codecov 2022-05-15 16:59:29 -04:00
28 changed files with 419 additions and 149 deletions

View File

@ -38,7 +38,7 @@ jobs:
run: yarn -s test:ci
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x'
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '14.x'
with:
directory: ./coverage

View File

@ -38,7 +38,7 @@ jobs:
- name: Test
run: yarn -s test:ci
- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '10.x'
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '14.x'
uses: codecov/codecov-action@v1
with:
directory: ./coverage

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ examples/*/dist
website/static/playground-dist
yarn-error.log
coverage/*
tests/esm/out/

View File

@ -1,4 +1,4 @@
(c) 2018-2019 Tim Griesser
(c) 2018-2022 Tim Griesser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View File

@ -74,4 +74,4 @@ You can find the docs for Nexus [here](http://nexusjs.org/).
## Migrate from SDL
If you've been following an [SDL-first](https://www.prisma.io/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/) approach to build your GraphQL server and want to see what your code looks like when written with GraphQL Nexus, you can use the [**SDL converter**](https://nexus.js.org/converter).
If you've been following an [SDL-first](https://www.prisma.io/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/) approach to build your GraphQL server and want to see what your code looks like when written with GraphQL Nexus, you can use the [**SDL converter**](https://nexusjs.org/converter).

View File

@ -28,18 +28,3 @@ Each public API is documented below, feel free to open a PR with more examples/c
- [extendType / extendInputType](/api/extend-type)
- [mutationField](/api/mutation-field)
- [queryField](/api/query-field)
## Resolving: Inline Function
One common idiom in GraphQL is exposing fields that mask or rename the property name on the backing object. GraphQL Nexus makes this simple by allowing a function as the second parameter to any built-in scalar resolver function.
```ts
const User = objectType({
name: 'User',
definition(t) {
t.id('id', o => o.user_id)
t.string('name', o => o.user_name)
t.string('description', o => o.user_description)
},
})
```

View File

@ -6,7 +6,7 @@ title: Overview
This plugin integrates [Prisma](https://www.prisma.io/) into [Nexus](https://nexusjs.org/). It gives you an API to project fields from models defined in your Prisma schema into your GraphQL API. It also gives you an API to build GraphQL root fields that allow your API clients to query and mutate data.
> **Note**: The Prisma team is currently [rewriting](https://github.com/graphql-nexus/nexus-plugin-prisma/issues/1039) the plugin to make it maintainable longterm.
**Note**: You may also use [`nexus-prisma`](https://github.com/graphql-nexus/nexus-prisma), a newer API for integrating Nexus and Prisma.
## Installation

View File

@ -214,8 +214,7 @@ const Footer = ({ footerProps }: FooterViewProps) => {
}
</div>
<p className="social-text">Prisma © 2018-2020</p>
<p>Made with in Berlin</p>
<p className="social-text">Tim Griesser © 2018-2022</p>
</div>
</SocialWrapper>
</div>

View File

@ -79,6 +79,7 @@
"@types/prettier": "^1.18.3",
"@typescript-eslint/eslint-plugin": "2.7.0",
"dripip": "^0.10.0",
"esbuild": "^0.14.48",
"eslint": "^6.6.0",
"get-port": "^5.1.1",
"graphql": "^16.3.0",

View File

@ -504,9 +504,6 @@ export class SchemaBuilder {
/** All Schema Directives */
// private schemaDirectives: GraphQLDirective[] = []
/** Whether we have used any custom directives within the schema construction */
private hasSDLDirectives: boolean = false
/** All types that need to be traversed for children types */
private typesToWalk: TypeToWalk[] = []
@ -999,14 +996,14 @@ export class SchemaBuilder {
this.beforeBuildTypes()
this.checkForInterfaceCircularDependencies()
this.buildNexusTypes()
return {
finalConfig: this.config,
typeMap: this.finalTypeMap,
schemaExtension: this.schemaExtension!,
schemaExtension: this.schemaExtension,
missingTypes: this.missingTypes,
onAfterBuildFns: this.onAfterBuildFns,
customDirectives: this.directivesMap,
hasSDLDirectives: this.hasSDLDirectives,
schemaDirectives: this.maybeAddDirectiveUses('SCHEMA', this.config.schemaDirectives),
}
}
@ -1200,11 +1197,7 @@ export class SchemaBuilder {
for (const directive of directives) {
this.addDirective(directive)
}
const result = maybeAddDirectiveUses(kind, directives, this.directivesMap)
if (result) {
this.hasSDLDirectives = true
}
return result
return maybeAddDirectiveUses(kind, directives, this.directivesMap)
}
private buildEnumType(config: NexusEnumTypeConfig<any>) {
@ -1901,7 +1894,6 @@ export interface BuildTypes<TypeMapDefs extends Record<string, GraphQLNamedType>
schemaExtension: NexusSchemaExtension
onAfterBuildFns: SchemaBuilder['onAfterBuildFns']
customDirectives: Record<string, GraphQLDirective>
hasSDLDirectives: boolean
schemaDirectives?: Partial<{ astNode: ASTKindToNode['SchemaDefinition'] }>
}

View File

@ -111,8 +111,36 @@ export type CommonOutputFieldConfig<TypeName extends string, FieldName extends s
* directives: [addDirective('ExampleDirective', { arg: true })]
*/
directives?: Directives
/**
* Defines a typing for the field, overriding the default behavior to default to the scalar,
* and omit the field if a resolver exists. Most useful in situations where we have a resolver
* but we still want the field defined on the output type.
*
* @example
* sourceType: 'string | number'
*/
sourceType?: string | FieldSourceType | NamedFieldSourceType[]
} & NexusGenPluginFieldConfig<TypeName, FieldName>
export interface FieldSourceType {
/**
* String representing the TypeScript type output as the value
*/
type: string
/**
* If true, marks the field as optional `?:`
* @default false
*/
optional?: boolean
}
export interface NamedFieldSourceType extends FieldSourceType {
/**
* Property name in the output TypeScript field
*/
name: string
}
export type CommonInputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & {
/** The default value for the field, if any */
default?: GetGen3<'inputTypes', TypeName, FieldName>

View File

@ -27,7 +27,7 @@ export const RequestDirectiveLocation = [
'FRAGMENT_SPREAD',
'INLINE_FRAGMENT',
'VARIABLE_DEFINITION',
]
] as const
export const SchemaDirectiveLocation = [
/** Type System Definitions */

View File

@ -5,13 +5,17 @@ import type { NexusOutputFieldConfig } from './definitions/definitionBlocks'
import type { NexusInputObjectTypeConfig } from './definitions/inputObjectType'
import type { NexusInterfaceTypeConfig } from './definitions/interfaceType'
import type { NexusObjectTypeConfig } from './definitions/objectType'
import type { Directives } from './core'
import type { Directives, FieldSourceType, NamedFieldSourceType } from './core'
/** @internal */
export function hasNexusExtension(val: any): val is any {
return Boolean(val)
}
export function isNexusFieldExtension(val: any): val is NexusFieldExtension {
return Boolean(val?._type === 'NexusFieldExtension')
}
export type NexusGraphQLNamedType = GraphQLNamedType & {
extensions?: {
nexus?: {
@ -24,13 +28,17 @@ export type NexusTypeExtensions = NexusObjectTypeExtension | NexusInterfaceTypeE
/** Container object living on `fieldDefinition.extensions.nexus` */
export class NexusFieldExtension<TypeName extends string = any, FieldName extends string = any> {
readonly _type = 'NexusFieldExtension' as const
readonly config: Omit<NexusOutputFieldConfig<TypeName, FieldName>, 'resolve'>
/** Whether the user has provided a custom "resolve" function, or whether we're using GraphQL's defaultResolver */
readonly hasDefinedResolver: boolean
readonly sourceType: string | FieldSourceType | NamedFieldSourceType[] | undefined
constructor(config: NexusOutputFieldConfig<TypeName, FieldName>) {
const { resolve, ...rest } = config
this.config = rest
this.hasDefinedResolver = Boolean(resolve && resolve !== defaultFieldResolver)
this.sourceType = rest.sourceType
}
/** Called when there are modifications on the interface fields */
modify(modifications: Partial<NexusOutputFieldConfig<any, any>>) {
@ -40,6 +48,7 @@ export class NexusFieldExtension<TypeName extends string = any, FieldName extend
/** Container object living on `inputObjectType.extensions.nexus` */
export class NexusInputObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInputObjectTypeExtension' as const
readonly config: Omit<NexusInputObjectTypeConfig<TypeName>, 'definition'>
constructor(config: NexusInputObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config
@ -49,6 +58,7 @@ export class NexusInputObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `objectType.extensions.nexus` */
export class NexusObjectTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusObjectTypeExtension' as const
readonly config: Omit<NexusObjectTypeConfig<TypeName>, 'definition' | 'isTypeOf'>
constructor(config: NexusObjectTypeConfig<TypeName>) {
const { definition, ...rest } = config
@ -58,6 +68,7 @@ export class NexusObjectTypeExtension<TypeName extends string = any> {
/** Container object living on `interfaceType.extensions.nexus` */
export class NexusInterfaceTypeExtension<TypeName extends string = any> {
readonly _type = 'NexusInterfaceTypeExtension' as const
readonly config: Omit<NexusInterfaceTypeConfig<TypeName>, 'definition' | 'resolveType'>
constructor(config: NexusInterfaceTypeConfig<TypeName>) {
const { definition, ...rest } = config

View File

@ -19,14 +19,14 @@ import { assertNoMissingTypes, objValues, runAbstractTypeRuntimeChecks } from '.
* Requires at least one type be named "Query", which will be used as the root query type.
*/
export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config)
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig)
const sdl = typegenConfig.outputs.schema
const typegen = typegenConfig.outputs.typegen
if (sdl || typegen) {
// Generating in the next tick allows us to use the schema
// in the optional thunk for the typegen config
const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema, hasSDLDirectives)
const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema)
if (config.shouldExitAfterGenerateArtifacts) {
let typegenPath = '(not enabled)'
if (typegenConfig.outputs.typegen) {
@ -59,9 +59,9 @@ export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
/** Like makeSchema except that typegen is always run and waited upon. */
export async function generateSchema(config: SchemaConfig): Promise<NexusGraphQLSchema> {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config)
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig)
await new TypegenMetadata(typegenConfig).generateArtifacts(schema, hasSDLDirectives)
await new TypegenMetadata(typegenConfig).generateArtifacts(schema)
assertNoMissingTypes(schema, missingTypes)
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
return schema
@ -80,11 +80,11 @@ generateSchema.withArtifacts = async (
tsTypes: string
globalTypes: string | null
}> => {
const { schema, missingTypes, finalConfig, hasSDLDirectives } = makeSchemaInternal(config)
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config)
const typegenConfig = resolveTypegenConfig(finalConfig)
const { schemaTypes, tsTypes, globalTypes } = await new TypegenMetadata(
typegenConfig
).generateArtifactContents(schema, typegen, hasSDLDirectives)
).generateArtifactContents(schema, typegen)
assertNoMissingTypes(schema, missingTypes)
runAbstractTypeRuntimeChecks(schema, finalConfig.features)
return { schema, schemaTypes, tsTypes, globalTypes }
@ -125,7 +125,6 @@ export function makeSchemaInternal(config: SchemaConfig) {
onAfterBuildFns,
customDirectives,
schemaDirectives,
hasSDLDirectives,
} = builder.getFinalTypeMap()
const schema = new GraphQLSchema({
@ -144,7 +143,7 @@ export function makeSchemaInternal(config: SchemaConfig) {
onAfterBuildFns.forEach((fn) => fn(schema))
return { schema, missingTypes, finalConfig, hasSDLDirectives }
return { schema, missingTypes, finalConfig }
}
type OmittedVals = Partial<{ [K in keyof MakeSchemaOptions]: never }>

8
src/node.ts Normal file
View File

@ -0,0 +1,8 @@
export function nodeImports() {
const fs = require('fs') as typeof import('fs')
const path = require('path') as typeof import('path')
return {
fs,
path,
}
}

View File

@ -1,8 +1,8 @@
import { GraphQLNamedType, GraphQLSchema, isOutputType } from 'graphql'
import * as path from 'path'
import type { TypegenInfo } from './builder'
import type { TypingImport } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { getOwnPackage, log, objValues, relativePathTo, typeScriptFileExtension } from './utils'
/** Any common types / constants that would otherwise be circular-imported */
@ -129,16 +129,12 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
}
})
const path = nodeImports().path
const typeSources = await Promise.all(
options.modules.map(async (source) => {
// Keeping all of this in here so if we don't have any sources
// e.g. in the Playground, it doesn't break things.
// Yeah, this doesn't exist in Node 6, but since this is a new
// lib and Node 6 is close to EOL so if you really need it, open a PR :)
const fs = require('fs') as typeof import('fs')
const util = require('util') as typeof import('util')
const readFile = util.promisify(fs.readFile)
const { module: pathOrModule, glob = true, onlyTypes, alias, typeMatch } = source
if (path.isAbsolute(pathOrModule) && path.extname(pathOrModule) !== '.ts') {
return console.warn(
@ -154,7 +150,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
if (path.extname(resolvedPath) !== '.ts') {
resolvedPath = findTypingForFile(resolvedPath, pathOrModule)
}
fileContents = await readFile(resolvedPath, 'utf-8')
fileContents = String(await nodeImports().fs.promises.readFile(resolvedPath, 'utf-8'))
} catch (e) {
if (e instanceof Error && e.message.indexOf('Cannot find module') !== -1) {
console.error(`GraphQL Nexus: Unable to find file or module ${pathOrModule}, skipping`)
@ -277,7 +273,7 @@ export function typegenAutoConfig(options: SourceTypesConfigOptions, contextType
function findTypingForFile(absolutePath: string, pathOrModule: string) {
// First try to find the "d.ts" adjacent to the file
try {
const typeDefPath = absolutePath.replace(path.extname(absolutePath), '.d.ts')
const typeDefPath = absolutePath.replace(nodeImports().path.extname(absolutePath), '.d.ts')
require.resolve(typeDefPath)
return typeDefPath
} catch (e) {

View File

@ -1,5 +1,5 @@
import * as path from 'path'
import type * as Prettier from 'prettier'
import { nodeImports } from './node'
export type TypegenFormatFn = (content: string, type: 'types' | 'schema') => string | Promise<string>
@ -22,6 +22,8 @@ export function typegenFormatPrettier(prettierConfig: string | object): TypegenF
let prettierConfigResolved: Prettier.Options
const path = nodeImports().path
if (typeof prettierConfig === 'string') {
/* istanbul ignore if */
if (!path.isAbsolute(prettierConfig)) {

View File

@ -1,9 +1,9 @@
import { GraphQLSchema, lexicographicSortSchema, printSchema } from 'graphql'
import * as path from 'path'
import { GraphQLSchema, lexicographicSortSchema } from 'graphql'
import type { BuilderConfigInput, TypegenInfo } from './builder'
import type { ConfiguredTypegen } from './core'
import type { NexusGraphQLSchema } from './definitions/_types'
import { SDL_HEADER, TYPEGEN_HEADER } from './lang'
import { nodeImports } from './node'
import { printSchemaWithDirectives } from './printSchemaWithDirectives'
import { typegenAutoConfig } from './typegenAutoConfig'
import { typegenFormatPrettier } from './typegenFormatPrettier'
@ -26,15 +26,11 @@ export class TypegenMetadata {
constructor(protected config: TypegenMetadataConfig) {}
/** Generates the artifacts of the build based on what we know about the schema and how it was defined. */
async generateArtifacts(schema: NexusGraphQLSchema, hasSDLDirectives: boolean) {
async generateArtifacts(schema: NexusGraphQLSchema) {
const sortedSchema = this.sortSchema(schema)
const { typegen } = this.config.outputs
if (this.config.outputs.schema || typegen) {
const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents(
sortedSchema,
typegen,
hasSDLDirectives
)
const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents(sortedSchema, typegen)
if (this.config.outputs.schema) {
await this.writeFile('schema', schemaTypes, this.config.outputs.schema)
}
@ -51,13 +47,9 @@ export class TypegenMetadata {
}
}
async generateArtifactContents(
schema: NexusGraphQLSchema,
typegen: string | null | ConfiguredTypegen,
hasSDLDirectives: boolean
) {
async generateArtifactContents(schema: NexusGraphQLSchema, typegen: string | null | ConfiguredTypegen) {
const result = {
schemaTypes: this.generateSchemaFile(schema, hasSDLDirectives),
schemaTypes: this.generateSchemaFile(schema),
tsTypes: '',
globalTypes: null as null | string,
}
@ -83,30 +75,26 @@ export class TypegenMetadata {
}
async writeFile(type: 'schema' | 'types', output: string, filePath: string) {
if (typeof filePath !== 'string' || !path.isAbsolute(filePath)) {
if (typeof filePath !== 'string' || !nodeImports().path.isAbsolute(filePath)) {
return Promise.reject(
new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`)
)
}
const fs = require('fs') as typeof import('fs')
const util = require('util') as typeof import('util')
const [readFile, writeFile, removeFile, mkdir] = [
util.promisify(fs.readFile),
util.promisify(fs.writeFile),
util.promisify(fs.unlink),
util.promisify(fs.mkdir),
]
const fs = nodeImports().fs
const formattedOutput =
typeof this.config.formatTypegen === 'function' ? await this.config.formatTypegen(output, type) : output
const content = this.config.prettierConfig
? await typegenFormatPrettier(this.config.prettierConfig)(formattedOutput, type)
: formattedOutput
const [toSave, existing] = await Promise.all([content, readFile(filePath, 'utf8').catch(() => '')])
const [toSave, existing] = await Promise.all([
content,
fs.promises.readFile(filePath, 'utf8').catch(() => ''),
])
if (toSave !== existing) {
const dirPath = path.dirname(filePath)
const dirPath = nodeImports().path.dirname(filePath)
try {
await mkdir(dirPath, { recursive: true })
await fs.promises.mkdir(dirPath, { recursive: true })
} catch (e) {
if (e.code !== 'EEXIST') {
throw e
@ -116,23 +104,22 @@ export class TypegenMetadata {
// apparently. See issue motivating this logic here:
// https://github.com/graphql-nexus/schema/issues/247.
try {
await removeFile(filePath)
await fs.promises.unlink(filePath)
} catch (e) {
/* istanbul ignore next */
if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') {
throw e
}
}
return writeFile(filePath, toSave)
return fs.promises.writeFile(filePath, toSave)
}
}
/** Generates the schema, adding any directives as necessary */
generateSchemaFile(schema: GraphQLSchema, hasSDLDirectives: boolean): string {
const printer = hasSDLDirectives ? printSchemaWithDirectives : printSchema
generateSchemaFile(schema: GraphQLSchema): string {
let printedSchema = this.config.customPrintSchemaFn
? this.config.customPrintSchemaFn(schema)
: printer(schema)
: printSchemaWithDirectives(schema)
return [SDL_HEADER, printedSchema].join('\n\n')
}

View File

@ -28,7 +28,7 @@ import { isNexusPrintedGenTyping, isNexusPrintedGenTypingImport } from './defini
import type { NexusGraphQLSchema } from './definitions/_types'
import { TYPEGEN_HEADER } from './lang'
import type { StringLike } from './plugin'
import { hasNexusExtension } from './extensions'
import { hasNexusExtension, isNexusFieldExtension } from './extensions'
import {
eachObj,
getOwnPackage,
@ -641,8 +641,17 @@ export class TypegenPrinter {
} else {
eachObj(type.getFields(), (field) => {
const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {})
if (!this.hasResolver(field, type)) {
if (typeof obj !== 'string') {
const fieldSourceType = this.fieldSourceType(field, type)
if (typeof obj !== 'string') {
if (Array.isArray(fieldSourceType)) {
for (const field of fieldSourceType) {
obj[field.name] = [field.optional ? '?:' : ':', field.type]
}
} else if (typeof fieldSourceType === 'object') {
obj[field.name] = [fieldSourceType.optional ? '?:' : ':', fieldSourceType.type]
} else if (fieldSourceType) {
obj[field.name] = [':', fieldSourceType]
} else if (!this.hasResolver(field, type)) {
obj[field.name] = [
this.argSeparator(field.type as GraphQLInputType, false),
this.printOutputType(field.type),
@ -663,6 +672,17 @@ export class TypegenPrinter {
return (this.typegenInfo.sourceTypeMap as any)[typeName]
}
private fieldSourceType(
field: GraphQLField<any, any>,
// Used in test mocking
_type: GraphQLObjectType
) {
if (field.extensions && isNexusFieldExtension(field.extensions.nexus)) {
return field.extensions.nexus.sourceType
}
return undefined
}
private hasResolver(
field: GraphQLField<any, any>,
// Used in test mocking

View File

@ -1,65 +1,75 @@
import * as path from 'path'
import type { BuilderConfigInput } from './builder'
import type { ConfiguredTypegen } from './core'
import { nodeImports } from './node'
import type { TypegenMetadataConfig } from './typegenMetadata'
import { assertAbsolutePath, getOwnPackage, isProductionStage } from './utils'
/** Normalizes the builder config into the config we need for typegen */
export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadataConfig {
const {
outputs,
shouldGenerateArtifacts = Boolean(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production'),
...rest
} = config
const { outputs, shouldGenerateArtifacts = defaultShouldGenerateArtifacts(), ...rest } = config
const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql')
function getOutputPaths() {
const defaultSDLFilePath = nodeImports().path.join(process.cwd(), 'schema.graphql')
let typegenFilePath: ConfiguredTypegen | null = null
let sdlFilePath: string | null = null
let typegenFilePath: ConfiguredTypegen | null = null
let sdlFilePath: string | null = null
if (outputs === undefined) {
if (isProductionStage()) {
sdlFilePath = defaultSDLFilePath
}
} else if (outputs === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs === 'object') {
if (outputs.schema === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs.schema === 'string') {
sdlFilePath = assertAbsolutePath(outputs.schema, 'outputs.schema')
} else if (outputs.schema === undefined && isProductionStage()) {
}
// handle typegen configuration
if (typeof outputs.typegen === 'string') {
typegenFilePath = {
outputPath: assertAbsolutePath(outputs.typegen, 'outputs.typegen'),
if (outputs === undefined) {
if (isProductionStage()) {
sdlFilePath = defaultSDLFilePath
}
} else if (typeof outputs.typegen === 'object') {
typegenFilePath = {
...outputs.typegen,
outputPath: assertAbsolutePath(outputs.typegen.outputPath, 'outputs.typegen.outputPath'),
} as ConfiguredTypegen
if (outputs.typegen.globalsPath) {
typegenFilePath.globalsPath = assertAbsolutePath(
outputs.typegen.globalsPath,
'outputs.typegen.globalsPath'
)
} else if (outputs === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs === 'object') {
if (outputs.schema === true) {
sdlFilePath = defaultSDLFilePath
} else if (typeof outputs.schema === 'string') {
sdlFilePath = assertAbsolutePath(outputs.schema, 'outputs.schema')
} else if (outputs.schema === undefined && isProductionStage()) {
}
// handle typegen configuration
if (typeof outputs.typegen === 'string') {
typegenFilePath = {
outputPath: assertAbsolutePath(outputs.typegen, 'outputs.typegen'),
}
} else if (typeof outputs.typegen === 'object') {
typegenFilePath = {
...outputs.typegen,
outputPath: assertAbsolutePath(outputs.typegen.outputPath, 'outputs.typegen.outputPath'),
} as ConfiguredTypegen
if (outputs.typegen.globalsPath) {
typegenFilePath.globalsPath = assertAbsolutePath(
outputs.typegen.globalsPath,
'outputs.typegen.globalsPath'
)
}
}
} else if (outputs !== false) {
console.warn(
`You should specify a configuration value for outputs in Nexus' makeSchema. ` +
`Provide one to remove this warning.`
)
}
return {
typegenFilePath,
sdlFilePath,
}
} else if (outputs !== false) {
console.warn(
`You should specify a configuration value for outputs in Nexus' makeSchema. ` +
`Provide one to remove this warning.`
)
}
return {
...rest,
nexusSchemaImportId: getOwnPackage().name,
outputs: {
typegen: shouldGenerateArtifacts ? typegenFilePath : null,
schema: shouldGenerateArtifacts ? sdlFilePath : null,
typegen: shouldGenerateArtifacts ? getOutputPaths().typegenFilePath : null,
schema: shouldGenerateArtifacts ? getOutputPaths().sdlFilePath : null,
},
}
}
function defaultShouldGenerateArtifacts() {
return Boolean(
typeof process === 'object' &&
typeof process.cwd === 'function' &&
(!process.env.NODE_ENV || process.env.NODE_ENV !== 'production')
)
}

View File

@ -1,4 +1,3 @@
import * as fs from 'fs'
import {
GraphQLEnumType,
GraphQLInputObjectType,
@ -22,7 +21,6 @@ import {
isWrappingType,
specifiedScalarTypes,
} from 'graphql'
import * as Path from 'path'
import { decorateType } from './definitions/decorateType'
import { isNexusMetaType, NexusMetaType, resolveNexusMetaType } from './definitions/nexusMeta'
import {
@ -42,6 +40,7 @@ import {
TypingImport,
withNexusSymbol,
} from './definitions/_types'
import { nodeImports } from './node'
export const isInterfaceField = (type: GraphQLObjectType, fieldName: string) => {
return type.getInterfaces().some((i) => Boolean(i.getFields()[fieldName]))
@ -150,7 +149,7 @@ export function eachObj<T>(obj: Record<string, T>, iter: (val: T, key: string, i
export const isObject = (obj: any): boolean => obj !== null && typeof obj === 'object'
export const assertAbsolutePath = (pathName: string, property: string) => {
if (!Path.isAbsolute(pathName)) {
if (!nodeImports().path.isAbsolute(pathName)) {
throw new Error(`Expected path for "${property}" to be an absolute path, saw "${pathName}"`)
}
return pathName
@ -221,7 +220,7 @@ export function isPromiseLike(value: any): value is PromiseLike<any> {
export const typeScriptFileExtension = /(\.d)?\.ts$/
function makeRelativePathExplicitlyRelative(path: string) {
if (Path.isAbsolute(path)) return path
if (nodeImports().path.isAbsolute(path)) return path
if (path.startsWith('./')) return path
return `./${path}`
}
@ -243,6 +242,7 @@ export function formatPathForModuleImport(path: string) {
}
export function relativePathTo(absolutePath: string, fromPath: string): string {
const Path = nodeImports().path
const filename = Path.basename(absolutePath)
const relative = Path.relative(Path.dirname(fromPath), Path.dirname(absolutePath))
return formatPathForModuleImport(Path.join(relative, filename))
@ -477,20 +477,18 @@ export function casesHandled(x: never): never {
throw new Error(`A case was not handled for value: "${x}"`)
}
/** Quickly log objects */
export function dump(x: any) {
console.log(require('util').inspect(x, { depth: null }))
}
function isNodeModule(path: string) {
// Avoid treating absolute windows paths as Node packages e.g. D:/a/b/c
return !Path.isAbsolute(path) && /^([A-z0-9@])/.test(path)
return !nodeImports().path.isAbsolute(path) && /^([A-z0-9@])/.test(path)
}
export function resolveImportPath(rootType: TypingImport, typeName: string, outputPath: string) {
const rootTypePath = rootType.module
if (typeof rootTypePath !== 'string' || (!Path.isAbsolute(rootTypePath) && !isNodeModule(rootTypePath))) {
if (
typeof rootTypePath !== 'string' ||
(!nodeImports().path.isAbsolute(rootTypePath) && !isNodeModule(rootTypePath))
) {
throw new Error(
`Expected an absolute path or Node package for the root typing path of the type "${typeName}", saw "${rootTypePath}"`
)
@ -502,7 +500,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
} catch (e) {
throw new Error(`Module "${rootTypePath}" for the type "${typeName}" does not exist`)
}
} else if (!fs.existsSync(rootTypePath)) {
} else if (!nodeImports().fs.existsSync(rootTypePath)) {
throw new Error(`Root typing path "${rootTypePath}" for the type "${typeName}" does not exist`)
}
@ -510,7 +508,7 @@ export function resolveImportPath(rootType: TypingImport, typeName: string, outp
return rootTypePath
}
if (Path.isAbsolute(rootTypePath)) {
if (nodeImports().path.isAbsolute(rootTypePath)) {
return relativePathTo(rootTypePath, outputPath)
}

16
tests/esm/esm-entry.js Normal file
View File

@ -0,0 +1,16 @@
import { GraphQLSchema } from 'graphql'
import { makeSchema, queryType } from '../../dist'
const schema = makeSchema({
types: [
queryType({
definition(t) {
t.boolean('ok')
},
}),
],
})
if (!(schema instanceof GraphQLSchema)) {
throw new Error('Not a schema')
}

View File

@ -0,0 +1,30 @@
import esbuild from 'esbuild'
import path from 'path'
import vm from 'vm'
import fs from 'fs'
describe('standalone esm', () => {
it('should build the esbuild', async () => {
const out = await esbuild.build({
bundle: true,
format: 'esm',
target: 'esnext',
// minify: true,
mainFields: ['module', 'main'],
external: ['path', 'fs', 'prettier'],
entryPoints: [path.join(__dirname, 'esm-entry.js')],
outdir: path.join(__dirname, 'out'),
outExtension: { '.js': '.mjs' },
metafile: true,
})
const context = vm.createContext()
// @ts-ignore
const outPath = path.join(__dirname, 'out', 'esm-entry.mjs')
fs.writeFileSync(path.join(path.dirname(outPath), 'meta.json'), JSON.stringify(out.metafile))
const script = new vm.Script(fs.readFileSync(outPath, 'utf8'), {
filename: outPath,
})
script.runInNewContext(context)
})
})

View File

@ -26,6 +26,19 @@ import {
import { mockStream } from '../../__helpers'
import './__typegen'
export const Node = interfaceType({
name: 'Node',
definition(t) {
t.nonNull.id('id', {
resolve: (source, args, ctx, info) => `${info.parentType.name}:${source.id}`,
sourceType: 'number',
})
},
resolveType(obj: any) {
return obj.__typename
},
})
export const typeDirective = directive({
name: 'TestTypeDirective',
locations: ['OBJECT', 'INTERFACE', 'ENUM', 'SCALAR'],
@ -116,12 +129,20 @@ export const i2 = objectType({
extensionAdditionFromTypeConfig: true,
},
definition(t) {
t.implements(Node)
t.implements('I')
t.modify('hello', {
extensions: {
extensionAdditionFromModifyMethod: true,
},
})
t.string('composite', {
resolve: (source) => `${source.fieldA} ${source.fieldB}`,
sourceType: [
{ name: 'fieldA', type: 'string' },
{ name: 'fieldB', type: 'string' },
],
})
},
})
@ -180,8 +201,12 @@ export const Post = objectType({
export const User = objectType({
name: 'User',
definition(t) {
t.string('firstName')
t.string('lastName')
t.string('firstName', {
sourceType: 'string',
})
t.string('lastName', {
sourceType: 'string',
})
t.connectionField('posts', {
type: Post,
nodes() {
@ -206,8 +231,11 @@ export const User = objectType({
},
},
})
t.string('telephone', {
sourceType: { type: 'string', optional: true },
resolve: (source) => (source.telephone ? `+1 ${source.telephone}` : null),
})
},
sourceType: `{ firstName: string, lastName: string }`,
})
export const Query = extendType({

View File

@ -39,12 +39,18 @@ No-Op scalar for testing purposes only
"""
scalar MyCustomScalar @TestAllDirective
interface Node {
id: ID!
}
type OfI implements I @TestTypeDirective {
hello: String @TestFieldDirective(bool: true)
}
type OfI2 implements I {
type OfI2 implements I & Node {
composite: String
hello: String @TestFieldDirective(bool: true)
id: ID!
}
"""
@ -156,6 +162,7 @@ type User {
"""
last: Int
): PostConnection
telephone: String
}
enum UserStatus {

View File

@ -89,7 +89,10 @@ export interface NexusGenObjects {
}
OfI2: {
// root type
fieldA: string
fieldB: string
hello?: string | null // String
id: number
}
PageInfo: {
// root type
@ -117,11 +120,17 @@ export interface NexusGenObjects {
}
Query: {}
Subscription: {}
User: { firstName: string; lastName: string }
User: {
// root type
firstName: string
lastName: string
telephone?: string
}
}
export interface NexusGenInterfaces {
I: NexusGenRootTypes['OfI'] | NexusGenRootTypes['OfI2']
Node: NexusGenRootTypes['OfI2']
}
export interface NexusGenUnions {}
@ -141,7 +150,9 @@ export interface NexusGenFieldTypes {
}
OfI2: {
// field return type
composite: string | null // String
hello: string | null // String
id: string // ID!
}
PageInfo: {
// field return type
@ -192,11 +203,16 @@ export interface NexusGenFieldTypes {
firstName: string | null // String
lastName: string | null // String
posts: NexusGenRootTypes['PostConnection'] | null // PostConnection
telephone: string | null // String
}
I: {
// field return type
hello: string | null // String
}
Node: {
// field return type
id: string // ID!
}
}
export interface NexusGenFieldTypeNames {
@ -210,7 +226,9 @@ export interface NexusGenFieldTypeNames {
}
OfI2: {
// field return type name
composite: 'String'
hello: 'String'
id: 'ID'
}
PageInfo: {
// field return type name
@ -261,11 +279,16 @@ export interface NexusGenFieldTypeNames {
firstName: 'String'
lastName: 'String'
posts: 'PostConnection'
telephone: 'String'
}
I: {
// field return type name
hello: 'String'
}
Node: {
// field return type name
id: 'ID'
}
}
export interface NexusGenArgTypes {
@ -306,11 +329,12 @@ export interface NexusGenArgTypes {
export interface NexusGenAbstractTypeMembers {
I: 'OfI' | 'OfI2'
Node: 'OfI2'
}
export interface NexusGenTypeInterfaces {
OfI: 'I'
OfI2: 'I'
OfI2: 'I' | 'Node'
}
export type NexusGenObjectNames = keyof NexusGenObjects
@ -348,7 +372,7 @@ export interface NexusGenDirectiveArgs {
export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never
export type NexusGenAbstractsUsingStrategyResolveType = 'I'
export type NexusGenAbstractsUsingStrategyResolveType = 'I' | 'Node'
export type NexusGenFeaturesConfig = {
abstractTypeStrategies: {

View File

@ -292,6 +292,7 @@ it('extensions are inherited and deeply merged by field modifications', () => {
"foo2": true,
},
"nexus": NexusFieldExtension {
"_type": "NexusFieldExtension",
"config": Object {
"configFor": "outputField",
"extensions": Object {
@ -305,6 +306,7 @@ it('extensions are inherited and deeply merged by field modifications', () => {
"wrapping": undefined,
},
"hasDefinedResolver": false,
"sourceType": undefined,
},
}
`)

126
yarn.lock
View File

@ -2520,6 +2520,132 @@ es6-weak-map@^2.0.1:
es6-iterator "^2.0.3"
es6-symbol "^3.1.1"
esbuild-android-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3"
integrity sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==
esbuild-android-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz#6877566be0f82dd5a43030c0007d06ece7f7c02f"
integrity sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==
esbuild-darwin-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz#ea3caddb707d88f844b1aa1dea5ff3b0a71ef1fd"
integrity sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==
esbuild-darwin-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz#4e5eaab54df66cc319b76a2ac0e8af4e6f0d9c2f"
integrity sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==
esbuild-freebsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz#47b5abc7426eae66861490ffbb380acc67af5b15"
integrity sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==
esbuild-freebsd-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz#e8c54c8637cd44feed967ea12338b0a4da3a7b11"
integrity sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==
esbuild-linux-32@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz#229cf3246de2b7937c3ac13fac622d4d7a1344c5"
integrity sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==
esbuild-linux-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz#7c0e7226c02c42aacc5656c36977493dc1e96c4f"
integrity sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==
esbuild-linux-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz#0af1eda474b5c6cc0cace8235b74d0cb8fcf57a7"
integrity sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==
esbuild-linux-arm@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz#de4d1fa6b77cdcd00e2bb43dd0801e4680f0ab52"
integrity sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==
esbuild-linux-mips64le@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz#822c1778495f7868e990d4da47ad7281df28fd15"
integrity sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==
esbuild-linux-ppc64le@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz#55de0a9ec4a48fedfe82a63e083164d001709447"
integrity sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==
esbuild-linux-riscv64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz#cd2b7381880b2f4b21a5a598fb673492120f18a5"
integrity sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==
esbuild-linux-s390x@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz#4b319eca2a5c64637fc7397ffbd9671719cdb6bf"
integrity sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==
esbuild-netbsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz#c27cde8b5cb55dcc227943a18ab078fb98d0adbf"
integrity sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==
esbuild-openbsd-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz#af5ab2d1cb41f09064bba9465fc8bf1309150df1"
integrity sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==
esbuild-sunos-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz#db3ae20526055cf6fd5c4582676233814603ac54"
integrity sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==
esbuild-windows-32@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz#021ffceb0a3f83078262870da88a912293c57475"
integrity sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==
esbuild-windows-64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz#a4d3407b580f9faac51f61eec095fa985fb3fee4"
integrity sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==
esbuild-windows-arm64@0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz#762c0562127d8b09bfb70a3c816460742dd82880"
integrity sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==
esbuild@^0.14.48:
version "0.14.48"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.48.tgz#da5d8d25cd2d940c45ea0cfecdca727f7aee2b85"
integrity sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==
optionalDependencies:
esbuild-android-64 "0.14.48"
esbuild-android-arm64 "0.14.48"
esbuild-darwin-64 "0.14.48"
esbuild-darwin-arm64 "0.14.48"
esbuild-freebsd-64 "0.14.48"
esbuild-freebsd-arm64 "0.14.48"
esbuild-linux-32 "0.14.48"
esbuild-linux-64 "0.14.48"
esbuild-linux-arm "0.14.48"
esbuild-linux-arm64 "0.14.48"
esbuild-linux-mips64le "0.14.48"
esbuild-linux-ppc64le "0.14.48"
esbuild-linux-riscv64 "0.14.48"
esbuild-linux-s390x "0.14.48"
esbuild-netbsd-64 "0.14.48"
esbuild-openbsd-64 "0.14.48"
esbuild-sunos-64 "0.14.48"
esbuild-windows-32 "0.14.48"
esbuild-windows-64 "0.14.48"
esbuild-windows-arm64 "0.14.48"
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"