From 46cf942f88f64983aa5807ebc566893bf6b2eaf2 Mon Sep 17 00:00:00 2001 From: Evan Schneider Date: Wed, 21 Jun 2017 18:31:26 -0400 Subject: [PATCH 1/3] Concat document definitions --- src/index.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index e0ba03c0..c08aa62d 100644 --- a/src/index.js +++ b/src/index.js @@ -157,10 +157,12 @@ function gql(/* arguments */) { // We always get literals[0] and then matching post literals for each arg given var result = (typeof(literals) === "string") ? literals : literals[0]; + var definitions = []; for (var i = 1; i < args.length; i++) { if (args[i] && args[i].kind && args[i].kind === 'Document') { result += args[i].loc.source.body; + definitions = definitions.concat(args[i].definitions) } else { result += args[i]; } @@ -168,7 +170,21 @@ function gql(/* arguments */) { result += literals[i]; } - return parseDocument(result); + var doc = parseDocument(result); + + var names = {}; + doc.definitions = doc.definitions.concat(definitions).filter(function(def) { + if (def.kind !== 'FragmentDefinition') return true; + var name = def.name.value + if (names[name]) { + return false; + } else { + names[name] = true; + return true; + } + }) + + return doc; } // Support typescript, which isn't as nice as Babel about default exports From a255bd638c5fa561dc1226429a6ca973171772fd Mon Sep 17 00:00:00 2001 From: Evan Schneider Date: Wed, 21 Jun 2017 19:32:06 -0400 Subject: [PATCH 2/3] Add test for interpolating nested imports --- test.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test.js b/test.js index 08145f9d..e5a08325 100644 --- a/test.js +++ b/test.js @@ -70,6 +70,37 @@ const assert = require('chai').assert; assert.equal(definitions[1].kind, 'FragmentDefinition'); }); + it('correctly interpolates imports of other files through the webpack loader', () => { + const query = `#import "./fragment_definition.graphql" + fragment BooksAuthor on Book { + author { + ...authorDetails + } + } + `; + const jsSource = loader.call({ cacheable() {} }, query); + + const oldRequire = require; + const module = { exports: undefined }; + const require = (path) => { + assert.equal(path, './fragment_definition.graphql'); + return gql` + fragment authorDetails on Author { + firstName + lastName + }`; + }; + + eval(jsSource); + + const document = gql`query { ...BooksAuthor } ${module.exports}`; + assert.equal(document.kind, 'Document'); + assert.equal(document.definitions.length, 3); + assert.equal(document.definitions[0].kind, 'OperationDefinition'); + assert.equal(document.definitions[1].kind, 'FragmentDefinition'); + assert.equal(document.definitions[2].kind, 'FragmentDefinition'); + }); + it('does not complain when presented with normal comments', (done) => { assert.doesNotThrow(() => { const query = `#normal comment From 038a9a65f489524d9c09ec230aa0e5ea534a9672 Mon Sep 17 00:00:00 2001 From: Evan Schneider Date: Thu, 22 Jun 2017 17:38:15 -0400 Subject: [PATCH 3/3] Use processFragments for extra definitions --- loader.js | 19 ++++++++++++++++--- src/index.js | 35 +++++++++++++++++++++-------------- test.js | 11 ++++++----- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/loader.js b/loader.js index e7bbad9c..5c5a10f3 100644 --- a/loader.js +++ b/loader.js @@ -41,10 +41,23 @@ function expandImports(source, doc) { module.exports = function(source) { this.cacheable(); - const doc = gql`${source}`; + const doc = gql(source, true); + + if (doc.definitions) { + for (var i = 0; i < doc.definitions.length; i++) { + if (doc.definitions[i].loc) { + doc.definitions[i].loc = { + start: doc.definitions[i].loc.start, + end: doc.definitions[i].loc.end, + source: doc.definitions[i].loc.source + } + } + } + } + const outputCode = ` - var doc = ${JSON.stringify(doc)}; - doc.loc.source = ${JSON.stringify(doc.loc.source)}; + var doc = ${JSON.stringify(doc, null, 4)}; + doc.loc.source = ${JSON.stringify(doc.loc.source, null, 4)}; `; const importOutputCode = expandImports(source, doc); diff --git a/src/index.js b/src/index.js index c08aa62d..fd9e2e29 100644 --- a/src/index.js +++ b/src/index.js @@ -128,7 +128,7 @@ function stripLoc(doc, removeLocAtThisLevel) { return doc; } -function parseDocument(doc) { +function parseDocument(doc, asImport) { var cacheKey = normalize(doc); if (docCache[cacheKey]) { @@ -143,7 +143,12 @@ function parseDocument(doc) { // check that all "new" fragments inside the documents are consistent with // existing fragments of the same name parsed = processFragments(parsed); - parsed = stripLoc(parsed, false); + if (asImport) { + parsed.definitions = stripLoc(parsed.definitions, false); + } + else { + parsed = stripLoc(parsed, false); + } docCache[cacheKey] = parsed; return parsed; @@ -152,6 +157,10 @@ function parseDocument(doc) { // XXX This should eventually disallow arbitrary string interpolation, like Relay does function gql(/* arguments */) { var args = Array.prototype.slice.call(arguments); + var asImport = args[args.length - 1] === true; + if (asImport) { + args = args.slice(0, -1); + } var literals = args[0]; @@ -170,20 +179,18 @@ function gql(/* arguments */) { result += literals[i]; } - var doc = parseDocument(result); - - var names = {}; - doc.definitions = doc.definitions.concat(definitions).filter(function(def) { - if (def.kind !== 'FragmentDefinition') return true; - var name = def.name.value - if (names[name]) { - return false; - } else { - names[name] = true; - return true; - } + definitions = definitions.filter(function (def) { + return def.kind === 'FragmentDefinition' && def.loc }) + var doc = parseDocument(result, asImport || definitions.length); + + + if (definitions.length > 0) { + doc.definitions = doc.definitions.concat(definitions) + doc = processFragments(doc) + } + return doc; } diff --git a/test.js b/test.js index e5a08325..d0494daa 100644 --- a/test.js +++ b/test.js @@ -71,10 +71,11 @@ const assert = require('chai').assert; }); it('correctly interpolates imports of other files through the webpack loader', () => { - const query = `#import "./fragment_definition.graphql" + const query =`#import "./fragment_definition.graphql" + fragment BooksAuthor on Book { author { - ...authorDetails + ...AuthorDetails } } `; @@ -84,11 +85,11 @@ const assert = require('chai').assert; const module = { exports: undefined }; const require = (path) => { assert.equal(path, './fragment_definition.graphql'); - return gql` - fragment authorDetails on Author { + return gql(` + fragment AuthorDetails on Author { firstName lastName - }`; + }`, true); }; eval(jsSource);