Skip to content

Commit c98d5c9

Browse files
committed
Add option to pluck from custom Vue block
1 parent 27c0e41 commit c98d5c9

File tree

3 files changed

+148
-12
lines changed

3 files changed

+148
-12
lines changed

packages/graphql-tag-pluck/src/index.ts

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ export interface GraphQLTagPluckOptions {
9090
* The magic comment anchor to look for when parsing GraphQL strings. Defaults to `graphql`.
9191
*/
9292
gqlMagicComment?: string;
93+
/**
94+
* The name of a custom Vue block that contains raw GraphQL to be plucked.
95+
*/
96+
gqlVueBlock?: string;
9397
/**
9498
* Allows to use a global identifier instead of a module import.
9599
* ```js
@@ -122,6 +126,23 @@ function parseWithVue(vueTemplateCompiler: typeof import('@vue/compiler-sfc'), f
122126
: '';
123127
}
124128

129+
function customBlockFromVue(
130+
// tslint:disable-next-line: no-implicit-dependencies
131+
vueTemplateCompiler: typeof import('@vue/compiler-sfc'),
132+
fileData: string,
133+
filePath: string,
134+
blockType: string
135+
): Source | undefined {
136+
const { descriptor } = vueTemplateCompiler.parse(fileData);
137+
138+
const block = descriptor.customBlocks.find(b => b.type === blockType);
139+
if (block === undefined) {
140+
return;
141+
}
142+
143+
return new Source(block.content.trim(), filePath, block.loc.start);
144+
}
145+
125146
// tslint:disable-next-line: no-implicit-dependencies
126147
function parseWithSvelte(svelte2tsx: typeof import('svelte2tsx'), fileData: string) {
127148
const fileInTsx = svelte2tsx.svelte2tsx(fileData);
@@ -145,13 +166,22 @@ export const gqlPluckFromCodeString = async (
145166
validate({ code, options });
146167

147168
const fileExt = extractExtension(filePath);
169+
170+
let blockSource;
148171
if (fileExt === '.vue') {
172+
if (options.gqlVueBlock) {
173+
blockSource = await pluckVueFileCustomBlock(code, filePath, options.gqlVueBlock);
174+
}
149175
code = await pluckVueFileScript(code);
150176
} else if (fileExt === '.svelte') {
151177
code = await pluckSvelteFileScript(code);
152178
}
153179

154-
return parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start));
180+
const sources = parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start));
181+
if (blockSource) {
182+
sources.push(blockSource);
183+
}
184+
return sources;
155185
};
156186

157187
/**
@@ -171,13 +201,22 @@ export const gqlPluckFromCodeStringSync = (
171201
validate({ code, options });
172202

173203
const fileExt = extractExtension(filePath);
204+
205+
let blockSource;
174206
if (fileExt === '.vue') {
207+
if (options.gqlVueBlock) {
208+
blockSource = pluckVueFileCustomBlockSync(code, filePath, options.gqlVueBlock);
209+
}
175210
code = pluckVueFileScriptSync(code);
176211
} else if (fileExt === '.svelte') {
177212
code = pluckSvelteFileScriptSync(code);
178213
}
179214

180-
return parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start));
215+
const sources = parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start));
216+
if (blockSource) {
217+
sources.push(blockSource);
218+
}
219+
return sources;
181220
};
182221

183222
export function parseCode({
@@ -250,31 +289,44 @@ const MissingSvelteTemplateCompilerError = new Error(
250289
`)
251290
);
252291

253-
async function pluckVueFileScript(fileData: string) {
254-
let vueTemplateCompiler: typeof import('@vue/compiler-sfc');
292+
async function loadVueCompilerSync() {
255293
try {
256294
// eslint-disable-next-line import/no-extraneous-dependencies
257-
vueTemplateCompiler = await import('@vue/compiler-sfc');
295+
return await import('@vue/compiler-sfc');
258296
} catch (e: any) {
259297
throw MissingVueTemplateCompilerError;
260298
}
261-
262-
return parseWithVue(vueTemplateCompiler, fileData);
263299
}
264300

265-
function pluckVueFileScriptSync(fileData: string) {
266-
let vueTemplateCompiler: typeof import('@vue/compiler-sfc');
267-
301+
function loadVueCompilerAsync() {
268302
try {
269303
// eslint-disable-next-line import/no-extraneous-dependencies
270-
vueTemplateCompiler = require('@vue/compiler-sfc');
304+
return require('@vue/compiler-sfc');
271305
} catch (e: any) {
272306
throw MissingVueTemplateCompilerError;
273307
}
308+
}
274309

310+
async function pluckVueFileScript(fileData: string) {
311+
const vueTemplateCompiler = await loadVueCompilerSync();
275312
return parseWithVue(vueTemplateCompiler, fileData);
276313
}
277314

315+
function pluckVueFileScriptSync(fileData: string) {
316+
const vueTemplateCompiler = loadVueCompilerAsync();
317+
return parseWithVue(vueTemplateCompiler, fileData);
318+
}
319+
320+
async function pluckVueFileCustomBlock(fileData: string, filePath: string, blockType: string) {
321+
const vueTemplateCompiler = await loadVueCompilerSync();
322+
return customBlockFromVue(vueTemplateCompiler, fileData, filePath, blockType);
323+
}
324+
325+
function pluckVueFileCustomBlockSync(fileData: string, filePath: string, blockType: string) {
326+
const vueTemplateCompiler = loadVueCompilerAsync();
327+
return customBlockFromVue(vueTemplateCompiler, fileData, filePath, blockType);
328+
}
329+
278330
async function pluckSvelteFileScript(fileData: string) {
279331
let svelte2tsx: typeof import('svelte2tsx');
280332
try {

packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,86 @@ describe('graphql-tag-pluck', () => {
17331733
);
17341734
});
17351735

1736+
it('should be able to specify a custom Vue block to pluck from', async () => {
1737+
const sources = await pluck(
1738+
'tmp-XXXXXX.vue',
1739+
freeText(`
1740+
<template lang="pug">
1741+
<div>test</div>
1742+
</template>
1743+
1744+
<script lang="ts">
1745+
import { defineComponent } from 'vue'
1746+
import gql from 'graphql-tag';
1747+
1748+
export default defineComponent({
1749+
name: 'TestComponent',
1750+
setup(){
1751+
return {
1752+
pageQuery: gql\`
1753+
query IndexQuery {
1754+
site {
1755+
siteMetadata {
1756+
title
1757+
}
1758+
}
1759+
}
1760+
\`
1761+
}
1762+
}
1763+
})
1764+
1765+
// export const pageQuery = gql\`
1766+
// query OtherQuery {
1767+
// site {
1768+
// siteMetadata {
1769+
// title
1770+
// }
1771+
// }
1772+
// }
1773+
// \`;
1774+
</script>
1775+
1776+
<style lang="scss">
1777+
.test { color: red };
1778+
</style>
1779+
1780+
<graphql lang="gql">
1781+
query CustomBlockQuery {
1782+
site {
1783+
siteMetadata {
1784+
title
1785+
}
1786+
}
1787+
}
1788+
</graphql>
1789+
`),
1790+
{
1791+
gqlVueBlock: 'graphql',
1792+
}
1793+
);
1794+
1795+
expect(sources.map(source => source.body).join('\n\n')).toEqual(
1796+
freeText(`
1797+
query IndexQuery {
1798+
site {
1799+
siteMetadata {
1800+
title
1801+
}
1802+
}
1803+
}
1804+
1805+
query CustomBlockQuery {
1806+
site {
1807+
siteMetadata {
1808+
title
1809+
}
1810+
}
1811+
}
1812+
`)
1813+
);
1814+
});
1815+
17361816
it('should be able to specify the package name of which the GraphQL identifier should be imported from', async () => {
17371817
const sources = await pluck(
17381818
'tmp-XXXXXX.js',

website/docs/graphql-tag-pluck.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Template literals leaded by magic comments will also be extracted :-)
7979
`
8080
```
8181

82-
supported file extensions are: `.js`, `.jsx`, `.ts`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.graphqls`, `.graphql`, `.gqls`, `.gql`.
82+
supported file extensions are: `.js`, `.jsx`, `.ts`, `.tsx`, `.flow`, `.flow.js`, `.flow.jsx`, `.vue`, `.graphqls`, `.graphql`, `.gqls`, `.gql`.
8383

8484
### Options
8585

@@ -89,6 +89,10 @@ It is recommended to look at the [source code](https://github.com/ardatan/graphq
8989

9090
The magic comment anchor to look for when parsing GraphQL strings. Defaults to `graphql`, which may be translated into `/* GraphQL */` in code.
9191

92+
- **`gqlVueBlock`**
93+
94+
The name of a custom Vue block that contains raw GraphQL to be plucked.
95+
9296
- **`globalGqlIdentifierName`**
9397

9498
Allows to use a global identifier instead of a module import.

0 commit comments

Comments
 (0)