Skip to content

Commit 0858fde

Browse files
authored
feat(generator): ability to control import extension (#1284)
1 parent d19d399 commit 0858fde

File tree

6 files changed

+123
-22
lines changed

6 files changed

+123
-22
lines changed

src/generator/config/config.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
import { expect } from 'vitest'
2+
import { describe } from 'vitest'
23
import { test } from '../../../tests/_/helpers.js'
34
import { createConfig } from './config.js'
5+
import type { ConfigInitSchemaSdl } from './configInit.js'
6+
7+
const schema: ConfigInitSchemaSdl = {
8+
type: `sdl`,
9+
sdl: `type Query { ok: Boolean }`,
10+
}
11+
12+
describe(`import format`, () => {
13+
test(`defaults to jsExtension`, async () => {
14+
const config = await createConfig({ schema })
15+
expect(config.importFormat).toEqual(`jsExtension`)
16+
})
17+
test(`noExtension`, async () => {
18+
const customPathFile = `./tests/_/fixtures/custom.graphql`
19+
const config = await createConfig({
20+
schema: { type: `sdlFile`, dirOrFilePath: customPathFile },
21+
importFormat: `noExtension`,
22+
})
23+
expect(config.importFormat).toEqual(`noExtension`)
24+
})
25+
})
426

527
test(`can load schema from custom path`, async () => {
628
const customPathFile = `./tests/_/fixtures/custom.graphql`

src/generator/config/config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import type { Extension } from '../extension/types.js'
1111
import {
1212
type ConfigInit,
1313
type ConfigInitLibraryPaths,
14+
type InputImportFormat,
1415
type InputLint,
1516
type InputOutputCase,
1617
libraryPathKeys,
1718
} from './configInit.js'
18-
import { defaultLibraryPaths, defaultNamespace, defaultOutputCase } from './defaults.js'
19+
import { defaultImportFormat, defaultLibraryPaths, defaultNamespace, defaultOutputCase } from './defaults.js'
1920
import { defaultName } from './defaults.js'
2021

2122
export interface Config {
@@ -43,6 +44,7 @@ export interface Config {
4344
}
4445
formatter: Formatter
4546
extensions: Extension[]
47+
importFormat: InputImportFormat
4648
paths: {
4749
project: {
4850
inputs: {
@@ -201,6 +203,7 @@ To suppress this warning disable formatting in one of the following ways:
201203
return {
202204
fs,
203205
name,
206+
importFormat: configInit.importFormat ?? defaultImportFormat,
204207
nameNamespace,
205208
extensions: configInit.extensions ?? [],
206209
outputCase,

src/generator/config/configInit.ts

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,39 @@ export const OutputCase = {
2020
} as const
2121
export type InputOutputCase = keyof typeof OutputCase
2222

23+
export const ImportFormat = {
24+
jsExtension: `jsExtension`,
25+
tsExtension: `tsExtension`,
26+
noExtension: `noExtension`,
27+
} as const
28+
export type InputImportFormat = keyof typeof ImportFormat
29+
30+
export interface ConfigInitSchemaSdl {
31+
type: `sdl`
32+
sdl: string
33+
}
34+
export interface ConfigInitSchemaInstance {
35+
type: `instance`
36+
instance: Grafaid.Schema.Schema
37+
}
38+
export interface ConfigInitSchemaSdlFile {
39+
type: `sdlFile`
40+
/**
41+
* Defaults to the source directory if set, otherwise the current working directory.
42+
*/
43+
dirOrFilePath?: string
44+
}
45+
export interface ConfigInitSchemaUrl {
46+
type: `url`
47+
url: URL
48+
options?: InputIntrospectionOptions
49+
}
50+
51+
export type ConfigInitSchema =
52+
| ConfigInitSchemaSdl
53+
| ConfigInitSchemaInstance
54+
| ConfigInitSchemaSdlFile
55+
| ConfigInitSchemaUrl
2356
export interface ConfigInit {
2457
/**
2558
* File system API to use.
@@ -66,25 +99,13 @@ export interface ConfigInit {
6699
*/
67100
currentWorkingDirectory?: string
68101
/**
69-
* The schema to use for generation. Can be an existing SDL file on disk, a schema instance already in memory, or an endpoint that will be introspected.
102+
* The schema to use for generation. Can be one of:
103+
*
104+
* 1. An existing SDL file on disk,
105+
* 2. A schema instance already in memory,
106+
* 3. An endpoint that will be introspected.
70107
*/
71-
schema: {
72-
type: 'sdl'
73-
sdl: string
74-
} | {
75-
type: 'instance'
76-
instance: Grafaid.Schema.Schema
77-
} | {
78-
type: 'sdlFile'
79-
/**
80-
* Defaults to the source directory if set, otherwise the current working directory.
81-
*/
82-
dirOrFilePath?: string
83-
} | {
84-
type: 'url'
85-
url: URL
86-
options?: InputIntrospectionOptions
87-
}
108+
schema: ConfigInitSchema
88109
/**
89110
* If the schema comes from a non-sdl-file source like a GraphQL endpoint URL, should a derived SDL file be written to disk?
90111
*
@@ -136,6 +157,23 @@ export interface ConfigInit {
136157
* If not set, Graffle will look for a file called `scalars.ts` in the project directory.
137158
*/
138159
scalars?: string
160+
/**
161+
* How should import identifiers be generated? Can be one of:
162+
*
163+
* 1. `jsExtension` e.g. `import ... from './bar.js'`
164+
* 2. `tsExtension` e.g. `import ... from './bar.ts'`
165+
* 3. `noExtension` e.g. `import ... from './bar'`
166+
*
167+
* @defaultValue `jsExtension`
168+
*
169+
* @remarks
170+
*
171+
* A user request for this option can be found at https://github.com/graffle-js/graffle/issues/1282.
172+
*
173+
* There is a planned feature to have a default be dynamic according to the state of your project's tsconfig.json.
174+
* See https://github.com/graffle-js/graffle/issues/1283.
175+
*/
176+
importFormat?: InputImportFormat
139177
/**
140178
* Override import paths to graffle package within the generated code.
141179
* Used by Graffle test suite to have generated clients point to source

src/generator/config/defaults.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ConfigInitLibraryPaths, InputOutputCase } from './configInit.js'
1+
import type { ConfigInitLibraryPaths, InputImportFormat, InputOutputCase } from './configInit.js'
22

33
export const defaultNamespace = `Graffle`
44

@@ -13,3 +13,5 @@ export const defaultLibraryPaths = {
1313
} satisfies ConfigInitLibraryPaths
1414

1515
export const defaultOutputCase: InputOutputCase = `kebab`
16+
17+
export const defaultImportFormat: InputImportFormat = `jsExtension`

src/generator/generator/generate.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,35 @@ import { globby } from 'globby'
22
import * as Memfs from 'memfs'
33
import { readFile } from 'node:fs/promises'
44
import * as Path from 'node:path'
5-
import { expect, test } from 'vitest'
5+
import { describe, expect, test } from 'vitest'
6+
import type { ConfigInitSchemaSdl } from '../_.js'
67
import { generate } from './generate.js'
78

9+
const schema: ConfigInitSchemaSdl = {
10+
type: `sdl`,
11+
sdl: `type Query { ok: Boolean }`,
12+
}
13+
14+
describe(`importFormat`, () => {
15+
test(`default is jsExtension`, async () => {
16+
await generate({
17+
fs: Memfs.fs.promises as any,
18+
schema,
19+
})
20+
const SchemaTs = Memfs.fs.readFileSync(`./graffle/modules/schema.ts`, `utf8`)
21+
expect(SchemaTs).toMatch(/import.*".\/data.js"/)
22+
})
23+
test(`noExtension`, async () => {
24+
await generate({
25+
fs: Memfs.fs.promises as any,
26+
schema,
27+
importFormat: `noExtension`,
28+
})
29+
const SchemaTs = Memfs.fs.readFileSync(`./graffle/modules/schema.ts`, `utf8`)
30+
expect(SchemaTs).toMatch(/import.*".\/data"/)
31+
})
32+
})
33+
834
test(`kitchen-sink generated modules`, async () => {
935
const basePath = `./tests/_/schemas/kitchen-sink/graffle`
1036
const filePaths = await globby(`${basePath}/**/*.ts`)

src/generator/helpers/moduleGenerator.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { camelCase, kebabCase, pascalCase, snakeCase } from 'es-toolkit'
2+
import { casesExhausted } from '../../lib/prelude.js'
23
import type { Config } from '../config/config.js'
34
import {
45
createCodeGenerator,
@@ -61,7 +62,16 @@ export const getFileName = (config: Config, generator: ModuleGenerator | Generat
6162

6263
export const getImportName = (config: Config, generator: ModuleGenerator | GeneratedModule) => {
6364
const name = getBaseName(config, generator)
64-
return `${name}.js`
65+
switch (config.importFormat) {
66+
case `jsExtension`:
67+
return `${name}.js`
68+
case `tsExtension`:
69+
return `${name}.ts`
70+
case `noExtension`:
71+
return name
72+
default:
73+
throw casesExhausted(config.importFormat)
74+
}
6575
}
6676

6777
export const caseFormatters = {

0 commit comments

Comments
 (0)