diff --git a/packages/gatsby/src/internal-plugins/query-runner/__tests__/query-compiler.js b/packages/gatsby/src/internal-plugins/query-runner/__tests__/query-compiler.js new file mode 100644 index 0000000000000..6da385f8dde73 --- /dev/null +++ b/packages/gatsby/src/internal-plugins/query-runner/__tests__/query-compiler.js @@ -0,0 +1,100 @@ +jest.mock(`glob`, () => { + const sync = jest.fn().mockImplementation(() => []) + return { + sync, + } +}) +const path = require(`path`) +const glob = require(`glob`) +const { resolveThemes, Runner } = require(`../query-compiler`) + +const base = path.resolve(``) + +describe(`Runner`, () => { + beforeEach(() => { + glob.sync.mockClear() + }) + + it(`returns a file parser instance`, async () => { + const runner = new Runner(base, [], {}) + + const parser = await runner.parseEverything() + + expect(parser).toEqual(new Map()) + }) + + describe(`expected directories`, () => { + it(`compiles src directory`, async () => { + const runner = new Runner(base, [], {}) + + await runner.parseEverything() + + expect(glob.sync).toHaveBeenCalledWith( + expect.stringContaining(path.join(base, `src`)), + expect.any(Object) + ) + }) + + it(`compiles fragments directory`, async () => { + const runner = new Runner(base, [], {}) + + await runner.parseEverything() + + expect(glob.sync).toHaveBeenCalledWith( + expect.stringContaining(path.join(base, `src`)), + expect.any(Object) + ) + }) + + it(`compiles themes directory(s)`, async () => { + const theme = `gatsby-theme-whatever` + const runner = new Runner( + base, + [path.join(base, `node_modules`, theme)], + {} + ) + + await runner.parseEverything() + + expect(glob.sync).toHaveBeenCalledWith( + expect.stringContaining(path.join(base, `node_modules`, theme)), + expect.any(Object) + ) + }) + }) +}) + +describe(`resolveThemes`, () => { + it(`returns empty array if zero themes detected`, () => { + ;[ + [], + [{ resolve: path.join(base, `gatsby-plugin-whatever`) }], + undefined, + ].forEach(testRun => { + expect(resolveThemes(testRun)).toEqual([]) + }) + }) + + it(`returns plugins matching gatsby-theme prefix`, () => { + const theme = `gatsby-theme-example` + expect( + resolveThemes([ + { + resolve: path.join(base, `gatsby-theme-example`), + }, + ]) + ).toEqual([expect.stringContaining(theme)]) + }) + + it(`handles scoped packages`, () => { + const theme = `@dschau/gatsby-theme-example` + + expect( + resolveThemes([ + { + resolve: path.join(base, theme), + }, + ]) + ).toEqual([expect.stringContaining(theme.split(`/`).join(path.sep))]) + }) +}) diff --git a/packages/gatsby/src/internal-plugins/query-runner/query-compiler.js b/packages/gatsby/src/internal-plugins/query-runner/query-compiler.js index e37e85e3829ab..002a888a50419 100644 --- a/packages/gatsby/src/internal-plugins/query-runner/query-compiler.js +++ b/packages/gatsby/src/internal-plugins/query-runner/query-compiler.js @@ -64,15 +64,24 @@ const validationRules = [ let lastRunHadErrors = null const overlayErrorID = `graphql-compiler` +const resolveThemes = (plugins = []) => + plugins.reduce((merged, plugin) => { + if (plugin.resolve.includes(`gatsby-theme-`)) { + merged.push(plugin.resolve) + } + return merged + }, []) + class Runner { - baseDir: string + base: string + additional: string[] schema: GraphQLSchema errors: string[] fragmentsDir: string - constructor(baseDir: string, fragmentsDir: string, schema: GraphQLSchema) { - this.baseDir = baseDir - this.fragmentsDir = fragmentsDir + constructor(base: string, additional: string[], schema: GraphQLSchema) { + this.base = base + this.additional = additional this.schema = schema } @@ -91,14 +100,21 @@ class Runner { } async parseEverything() { - // FIXME: this should all use gatsby's configuration to determine parsable - // files (and how to parse them) - let files = glob.sync(`${this.fragmentsDir}/**/*.+(t|j)s?(x)`, { - nodir: true, - }) - files = files.concat( - glob.sync(`${this.baseDir}/**/*.+(t|j)s?(x)`, { nodir: true }) - ) + const filesRegex = path.join(`/**`, `*.+(t|j)s?(x)`) + let files = [ + path.join(this.base, `src`), + path.join(this.base, `.cache`, `fragments`), + ] + .concat(this.additional.map(additional => path.join(additional, `src`))) + .reduce( + (merged, folderPath) => + merged.concat( + glob.sync(path.join(folderPath, filesRegex), { + nodir: true, + }) + ), + [] + ) files = files.filter(d => !d.match(/\.d\.ts$/)) files = files.map(normalize) @@ -217,16 +233,13 @@ class Runner { return compiledNodes } } -export { Runner } +export { Runner, resolveThemes } export default async function compile(): Promise> { - const { program, schema } = store.getState() + // TODO: swap plugins to themes + const { program, schema, plugins } = store.getState() - const runner = new Runner( - `${program.directory}/src`, - `${program.directory}/.cache/fragments`, - schema - ) + const runner = new Runner(program.directory, resolveThemes(plugins), schema) const queries = await runner.compileAll()