Skip to content

Commit 4dcd10e

Browse files
committed
fix(visitor-plugin-common): Escape special characters when emitting template literals
Fixes #10480
1 parent c87b779 commit 4dcd10e

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
import gqlTag from 'graphql-tag';
2020
import { BaseVisitor, ParsedConfig, RawConfig } from './base-visitor.js';
2121
import { LoadedFragment, ParsedImport } from './types.js';
22-
import { buildScalarsFromConfig, unique, flatten, getConfigValue, groupBy } from './utils.js';
22+
import { asTemplateLiteral, buildScalarsFromConfig, unique, flatten, getConfigValue, groupBy } from './utils.js';
2323
import { FragmentImport, ImportDeclaration, generateFragmentImportStatement } from './imports.js';
2424

2525
gqlTag.enableExperimentalFragmentVariables();
@@ -350,10 +350,13 @@ export class ClientSideBaseVisitor<
350350
const fragmentNames = this._extractFragments(node, includeNestedFragments);
351351
const fragments = this._transformFragments(fragmentNames);
352352

353-
const doc = this._prepareDocument(`
354-
${print(node).split('\\').join('\\\\') /* Re-escape escaped values in GraphQL syntax */}
355-
${this._includeFragments(fragments)}`);
353+
// Re-escape escaped values in GraphQL syntax.
354+
const docLiteralContents = print(node).split('\\').join('\\\\');
355+
const fragmentLiteralContents = this._includeFragments(fragments);
356356

357+
const doc = this._prepareDocument(`
358+
${docLiteralContents}
359+
${fragmentLiteralContents}`);
357360
if (this.config.documentMode === DocumentMode.documentNode) {
358361
let gqlObj = gqlTag([doc]);
359362

@@ -414,8 +417,9 @@ export class ClientSideBaseVisitor<
414417
}
415418

416419
if (this.config.documentMode === DocumentMode.string) {
420+
const escapedLiteralContents = asTemplateLiteral(doc).slice(1, -1);
417421
if (node.kind === Kind.FRAGMENT_DEFINITION) {
418-
return `new TypedDocumentString(\`${doc}\`, ${JSON.stringify({ fragmentName: node.name.value })})`;
422+
return `new TypedDocumentString(\`${escapedLiteralContents}\`, ${JSON.stringify({ fragmentName: node.name.value })})`;
419423
}
420424

421425
if (this._onExecutableDocumentNode && node.kind === Kind.OPERATION_DEFINITION) {
@@ -425,16 +429,21 @@ export class ClientSideBaseVisitor<
425429
if (this._omitDefinitions === true) {
426430
return `{${`"__meta__":${JSON.stringify(meta)},`.slice(0, -1)}}`;
427431
}
428-
return `new TypedDocumentString(\`${doc}\`, ${JSON.stringify(meta)})`;
432+
return `new TypedDocumentString(\`${escapedLiteralContents}\`, ${JSON.stringify(meta)})`;
429433
}
430434
}
431435

432-
return `new TypedDocumentString(\`${doc}\`)`;
436+
return `new TypedDocumentString(\`${escapedLiteralContents}\`)`;
433437
}
434438

439+
const escapedLiteralContentsPrefix = asTemplateLiteral(docLiteralContents).slice(1, -1);
440+
const escapedDoc = this._prepareDocument(`
441+
${escapedLiteralContentsPrefix}
442+
${fragmentLiteralContents}`);
443+
435444
const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag');
436445

437-
return (gqlImport.propName || 'gql') + '`' + doc + '`';
446+
return (gqlImport.propName || 'gql') + '`' + escapedDoc + '`';
438447
}
439448

440449
protected _getGraphQLCodegenMetadata(

packages/plugins/other/visitor-plugin-common/src/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import { parseMapper } from './mappers.js';
2828
import { DEFAULT_SCALARS } from './scalars.js';
2929
import { NormalizedScalarsMap, ParsedScalarsMap, ScalarsMap, FragmentDirectives, LoadedFragment } from './types.js';
3030

31+
export const asTemplateLiteral = str => '`' + str.replace(/[`\\]|[$][{]/g, '\\$&') + '`';
32+
3133
export const getConfigValue = <T = any>(value: T, defaultValue: T): T => {
3234
if (value === null || value === undefined) {
3335
return defaultValue;

0 commit comments

Comments
 (0)