Skip to content

Commit

Permalink
feat: object imports
Browse files Browse the repository at this point in the history
Closes #4
  • Loading branch information
kbrandwijk authored Jan 6, 2018
1 parent a8a587e commit c8c4aef
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 15 deletions.
2 changes: 1 addition & 1 deletion fixtures/import-all/a.graphql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# import B from "b.graphql"
# import * from "b.graphql"

type A {
# test 1
Expand Down
160 changes: 160 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,166 @@ type C2 {
t.is(importSchema('fixtures/import-all/a.graphql'), expectedSDL)
})

test('importSchema: import all from objects', t => {
const schemaC = `
type C1 {
id: ID!
}
type C2 {
id: ID!
}
type C3 {
id: ID!
}`

const schemaB = `
# import * from 'schemaC'
type B {
hello: String!
c1: C1
c2: C2
}`

const schemaA = `
# import B from 'schemaB'
type A {
# test 1
first: String @first
second: Float
b: B
}`

const schemas = {
schemaA, schemaB, schemaC
}

const expectedSDL = `\
type A {
first: String @first
second: Float
b: B
}
type B {
hello: String!
c1: C1
c2: C2
}
type C1 {
id: ID!
}
type C2 {
id: ID!
}
`
t.is(importSchema(schemaA, schemas), expectedSDL)
})

test(`importSchema: single object schema`, t => {
const schemaA = `
type A {
field: String
}`

const expectedSDL = `\
type A {
field: String
}
`

t.is(importSchema(schemaA), expectedSDL)
})

test(`importSchema: import all mix 'n match`, t => {
const schemaB = `
# import C1, C2 from 'fixtures/import-all/c.graphql'
type B {
hello: String!
c1: C1
c2: C2
}`

const schemaA = `
# import * from "schemaB"
type A {
# test 1
first: String @first
second: Float
b: B
}`

const schemas = {
schemaB
}

const expectedSDL = `\
type A {
first: String @first
second: Float
b: B
}
type B {
hello: String!
c1: C1
c2: C2
}
type C1 {
id: ID!
}
type C2 {
id: ID!
}
`
t.is(importSchema(schemaA, schemas), expectedSDL)
})

test(`importSchema: import all mix 'n match 2`, t => {

const schemaA = `
# import * from "fixtures/import-all/b.graphql"
type A {
# test 1
first: String @first
second: Float
b: B
}`

const expectedSDL = `\
type A {
first: String @first
second: Float
b: B
}
type B {
hello: String!
c1: C1
c2: C2
}
type C1 {
id: ID!
}
type C2 {
id: ID!
}
`
t.is(importSchema(schemaA), expectedSDL)
})

test('importSchema: unions', t => {
const expectedSDL = `\
type A {
Expand Down
31 changes: 17 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export interface RawModule {
from: string
}

/**
* Read a schema file from disk
*
* @param f Filename
* @returns File contents
*/
const read: (f: string) => string =
(f: string): string => fs.readFileSync(f, { encoding: 'utf8' })
const read = (schema: string, schemas?: { [key: string]: string }) => {
if (isFile(schema)) {
return fs.readFileSync(schema, { encoding: 'utf8' })
}
return schemas ? schemas[schema] : schema
}

const isFile = f => f.endsWith('.graphql')

/**
* Parse a single import line and extract imported types and schema filename
Expand Down Expand Up @@ -68,15 +68,16 @@ export function parseSDL(sdl: string): RawModule[] {
* @param filePath File path to the initial schema file
* @returns Single bundled schema with all imported types
*/
export function importSchema(filePath: string): string {
const sdl = read(filePath)
export function importSchema(schema: string, schemas?: { [key: string]: string }): string {
const sdl = read(schema, schemas) || schema
const document = parse(sdl, { noLocation: true })

// Recursively process the imports, starting by importing all types from the initial schema
let { allDefinitions, typeDefinitions } = collectDefinitions(
['*'],
sdl,
path.resolve(filePath)
schema,
schemas
)

// Post processing of the final schema (missing types, unused types, etc.)
Expand Down Expand Up @@ -125,14 +126,15 @@ function collectDefinitions(
imports: string[],
sdl: string,
filePath: string,
schemas?: { [key: string]: string },
processedFiles: Set<string> = new Set(),
typeDefinitions: TypeDefinitionNode[][] = [],
allDefinitions: TypeDefinitionNode[][] = []
): {
allDefinitions: TypeDefinitionNode[][]
typeDefinitions: TypeDefinitionNode[][]
} {
const key = path.resolve(filePath)
const key = isFile(filePath) ? path.resolve(filePath) : filePath
const dirname = path.dirname(filePath)

// Get TypeDefinitionNodes from current schema
Expand All @@ -159,12 +161,13 @@ function collectDefinitions(
// Process each file (recursively)
rawModules.forEach(m => {
// If it was not yet processed (in case of circular dependencies)
const moduleFilePath = path.resolve(path.join(dirname, m.from))
const moduleFilePath = isFile(filePath) ? path.resolve(path.join(dirname, m.from)) : m.from
if (!processedFiles.has(moduleFilePath)) {
collectDefinitions(
m.imports,
read(moduleFilePath),
read(moduleFilePath, schemas),
moduleFilePath,
schemas,
processedFiles,
typeDefinitions,
allDefinitions
Expand Down

0 comments on commit c8c4aef

Please sign in to comment.