Skip to content

Commit

Permalink
feat: let graphql-tag-pluck load from astro files (#5781)
Browse files Browse the repository at this point in the history
* feat: let graphql-tag-pluck load from astro files

* Apply suggestions from code review

---------

Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
  • Loading branch information
XiNiHa and ardatan committed Jan 22, 2024
1 parent 3d476ed commit 2c6c1d6
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 151 deletions.
6 changes: 6 additions & 0 deletions .changeset/wise-dolphins-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphql-tools/code-file-loader': minor
'@graphql-tools/graphql-tag-pluck': minor
---

Add .astro file support
5 changes: 4 additions & 1 deletion packages/graphql-tag-pluck/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@astrojs/compiler": "^2.3.4",
"astrojs-compiler-sync": "^0.3.3",
"@babel/parser": "7.23.6",
"@babel/traverse": "7.23.7",
"@babel/types": "7.23.6",
Expand All @@ -75,7 +77,8 @@
"buildOptions": {
"external": [
"@vue/compiler-sfc",
"svelte2tsx"
"svelte2tsx",
"@astrojs/compiler"
]
},
"typescript": {
Expand Down
3 changes: 3 additions & 0 deletions packages/graphql-tag-pluck/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export default function generateConfig(
case '.svelte':
plugins.push('typescript', 'svelte');
break;
case '.astro':
plugins.push('typescript', 'jsx');
break;
default:
plugins.push('jsx', ...dynamicFlowPlugins);
break;
Expand Down
62 changes: 60 additions & 2 deletions packages/graphql-tag-pluck/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const supportedExtensions = [
'.flow.jsx',
'.vue',
'.svelte',
'.astro',
];

// tslint:disable-next-line: no-implicit-dependencies
Expand All @@ -159,10 +160,25 @@ function parseWithSvelte(svelte2tsx: typeof import('svelte2tsx'), fileData: stri
return fileInTsx.code;
}

// tslint:disable-next-line: no-implicit-dependencies
async function parseWithAstro(astroCompiler: typeof import('@astrojs/compiler'), fileData: string) {
const fileInTsx = await astroCompiler.transform(fileData);
return fileInTsx.code;
}

function parseWithAstroSync(
// tslint:disable-next-line: no-implicit-dependencies
astroCompiler: typeof import('astrojs-compiler-sync'),
fileData: string,
) {
const fileInTsx = astroCompiler.transform(fileData, undefined);
return fileInTsx.code;
}

/**
* Asynchronously plucks GraphQL template literals from a single file.
*
* Supported file extensions include: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.vue`, `.svelte`
* Supported file extensions include: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.vue`, `.svelte`, `.astro`
*
* @param filePath Path to the file containing the code. Required to detect the file type
* @param code The contents of the file being parsed.
Expand All @@ -180,6 +196,8 @@ export const gqlPluckFromCodeString = async (
code = await pluckVueFileScript(code);
} else if (fileExt === '.svelte') {
code = await pluckSvelteFileScript(code);
} else if (fileExt === '.astro') {
code = await pluckAstroFileScript(code);
}

return parseCode({ code, filePath, options }).map(
Expand All @@ -190,7 +208,7 @@ export const gqlPluckFromCodeString = async (
/**
* Synchronously plucks GraphQL template literals from a single file
*
* Supported file extensions include: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mjs`, `.cjs`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.vue`, `.svelte`
* Supported file extensions include: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mjs`, `.cjs`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.vue`, `.svelte`, `.astro`
*
* @param filePath Path to the file containing the code. Required to detect the file type
* @param code The contents of the file being parsed.
Expand All @@ -208,6 +226,8 @@ export const gqlPluckFromCodeStringSync = (
code = pluckVueFileScriptSync(code);
} else if (fileExt === '.svelte') {
code = pluckSvelteFileScriptSync(code);
} else if (fileExt === '.astro') {
code = pluckAstroFileScriptSync(code);
}

return parseCode({ code, filePath, options }).map(
Expand Down Expand Up @@ -285,6 +305,21 @@ const MissingSvelteTemplateCompilerError = new Error(
`),
);

const MissingAstroCompilerError = new Error(
freeText(`
GraphQL template literals cannot be plucked from a Astro template code without having the "@astrojs/compiler" package installed.
Please install it and try again.
Via NPM:
$ npm install @astrojs/compiler
Via Yarn:
$ yarn add @astrojs/compiler
`),
);

async function pluckVueFileScript(fileData: string) {
let vueTemplateCompiler: typeof import('@vue/compiler-sfc');
try {
Expand Down Expand Up @@ -334,3 +369,26 @@ function pluckSvelteFileScriptSync(fileData: string) {

return parseWithSvelte(svelte2tsx, fileData);
}

async function pluckAstroFileScript(fileData: string) {
let astroCompiler: typeof import('@astrojs/compiler');
try {
// eslint-disable-next-line import/no-extraneous-dependencies
astroCompiler = await import('@astrojs/compiler');
} catch (e: any) {
throw MissingAstroCompilerError;
}

return parseWithAstro(astroCompiler, fileData);
}

function pluckAstroFileScriptSync(fileData: string) {
let astroCompiler: typeof import('astrojs-compiler-sync');
try {
astroCompiler = require('astrojs-compiler-sync');
} catch (e: any) {
throw MissingAstroCompilerError;
}

return parseWithAstroSync(astroCompiler, fileData);
}
132 changes: 132 additions & 0 deletions packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,138 @@ describe('graphql-tag-pluck', () => {
);
});

it('should pluck graphql-tag template literals from .astro file', async () => {
const sources = await pluck(
'tmp-XXXXXX.astro',
freeText(`
---
import gql from 'graphql-tag';
let q = gql\`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
\`;
---
<div>foo</div>
`),
);

expect(sources.map(source => source.body).join('\n\n')).toEqual(
freeText(`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
`),
);
});

it('should pluck graphql-tag template literals from .astro file with 2 queries', async () => {
const sources = await pluck(
'tmp-XXXXXX.astro',
freeText(`
---
import gql from 'graphql-tag';
let q = gql\`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
\`;
let q2 = gql\`
query IndexQuery2 {
site {
siteMetadata {
title
}
}
}
\`;
---
<div>foo</div>
`),
);

expect(sources.map(source => source.body).join('\n\n')).toEqual(
freeText(`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
query IndexQuery2 {
site {
siteMetadata {
title
}
}
}
`),
);
});

it('should pluck graphql-tag template literals from .astro removing comments', async () => {
const sources = await pluck(
'tmp-XXXXXX.astro',
freeText(`
---
import gql from 'graphql-tag';
let q = gql\`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
\`;
// let q2 = gql\`
// query IndexQuery2 {
// site {
// siteMetadata {
// title
// }
// }
// }
// \`;
---
<div>foo</div>
`),
);

expect(sources.map(source => source.body).join('\n\n')).toEqual(
freeText(`
query IndexQuery {
site {
siteMetadata {
title
}
}
}
`),
);
});

it('should pluck graphql-tag template literals from .tsx file with generic jsx elements', async () => {
const sources = await pluck(
'tmp-XXXXXX.tsx',
Expand Down
3 changes: 2 additions & 1 deletion packages/loaders/code-file/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const FILE_EXTENSIONS = [
'.jsx',
'.vue',
'.svelte',
'.astro',
];

function createGlobbyOptions(options: CodeFileLoaderOptions): GlobbyOptions {
Expand All @@ -75,7 +76,7 @@ const buildIgnoreGlob = (path: string) => `!${path}`;
* ```
*
* Supported extensions include: `.ts`, `.mts`, `.cts`, `.tsx`, `.js`, `.mjs`,
* `.cjs`, `.jsx`, `.vue`, `.svelte`
* `.cjs`, `.jsx`, `.vue`, `.svelte`, `.astro`
*/
export class CodeFileLoader implements Loader<CodeFileLoaderOptions> {
private config: CodeFileLoaderConfig;
Expand Down
Loading

0 comments on commit 2c6c1d6

Please sign in to comment.