graphql-ruby-client
Advanced tools
Comparing version 1.5.0 to 1.6.0
@@ -29,5 +29,5 @@ var sync = require("../sync") | ||
} | ||
sync(options) | ||
expect(url).toEqual("bogus") | ||
return sync(options).then(function() { | ||
expect(url).toEqual("bogus") | ||
}) | ||
}) | ||
@@ -46,11 +46,11 @@ }) | ||
} | ||
sync(options) | ||
return sync(options).then(function() { | ||
expect(payload.operations).toMatchSnapshot() | ||
expect(payload.operations).toMatchSnapshot() | ||
options.glob += "**/*.graphql" | ||
sync(options) | ||
// Get the same result, even when the glob already has a file extension | ||
expect(payload.operations).toMatchSnapshot() | ||
options.glob += "**/*.graphql" | ||
return sync(options).then(function() { | ||
// Get the same result, even when the glob already has a file extension | ||
expect(payload.operations).toMatchSnapshot() | ||
}) | ||
}) | ||
}) | ||
@@ -71,5 +71,5 @@ | ||
} | ||
sync(options) | ||
expect(payload.operations).toMatchSnapshot() | ||
return sync(options).then(function() { | ||
expect(payload.operations).toMatchSnapshot() | ||
}) | ||
}) | ||
@@ -88,5 +88,5 @@ }) | ||
} | ||
sync(options) | ||
expect(payload.operations).toMatchSnapshot() | ||
return sync(options).then(function () { | ||
expect(payload.operations).toMatchSnapshot() | ||
}) | ||
}) | ||
@@ -106,5 +106,5 @@ }) | ||
} | ||
sync(options) | ||
expect(payload.operations).toMatchSnapshot() | ||
return sync(options).then(function () { | ||
expect(payload.operations).toMatchSnapshot() | ||
}) | ||
}) | ||
@@ -122,8 +122,26 @@ | ||
} | ||
sync(options) | ||
return sync(options).then(function() { | ||
expect(payload.operations).toMatchSnapshot() | ||
}) | ||
}) | ||
}) | ||
expect(payload.operations).toMatchSnapshot() | ||
describe("Promise result", () => { | ||
it("Yields the payload and generated code", () => { | ||
var options = { | ||
client: "test-1", | ||
path: "./__tests__/project", | ||
url: "bogus", | ||
quiet: true, | ||
send: (sendPayload, opts) => { }, | ||
} | ||
return sync(options).then(function(payload) { | ||
expect(payload.operations.length).toEqual(5) | ||
var generatedCode = fs.readFileSync("./OperationStoreClient.js", "utf8") | ||
expect(payload.generatedCode).toEqual(generatedCode) | ||
fs.unlinkSync("./OperationStoreClient.js") | ||
}) | ||
}) | ||
}) | ||
describe("Sync output", () => { | ||
@@ -138,9 +156,9 @@ it("Generates a usable artifact for middleware", () => { | ||
} | ||
sync(options) | ||
var generatedCode = fs.readFileSync("./OperationStoreClient.js", "utf8") | ||
expect(generatedCode).toMatch('"GetStuff": "5f0da489cf508a7c65ff5fa144e50545"') | ||
expect(generatedCode).toMatch('module.exports = OperationStoreClient') | ||
expect(generatedCode).toMatch('var _client = "test-1"') | ||
fs.unlinkSync("./OperationStoreClient.js") | ||
return sync(options).then(function() { | ||
var generatedCode = fs.readFileSync("./OperationStoreClient.js", "utf8") | ||
expect(generatedCode).toMatch('"GetStuff": "5f0da489cf508a7c65ff5fa144e50545"') | ||
expect(generatedCode).toMatch('module.exports = OperationStoreClient') | ||
expect(generatedCode).toMatch('var _client = "test-1"') | ||
fs.unlinkSync("./OperationStoreClient.js") | ||
}) | ||
}) | ||
@@ -157,9 +175,9 @@ | ||
} | ||
sync(options) | ||
var generatedCode = fs.readFileSync("./__crazy_outfile.js", "utf8") | ||
expect(generatedCode).toMatch('"GetStuff": "5f0da489cf508a7c65ff5fa144e50545"') | ||
expect(generatedCode).toMatch('module.exports = OperationStoreClient') | ||
expect(generatedCode).toMatch('var _client = "test-2"') | ||
fs.unlinkSync("./__crazy_outfile.js") | ||
return sync(options).then(function() { | ||
var generatedCode = fs.readFileSync("./__crazy_outfile.js", "utf8") | ||
expect(generatedCode).toMatch('"GetStuff": "5f0da489cf508a7c65ff5fa144e50545"') | ||
expect(generatedCode).toMatch('module.exports = OperationStoreClient') | ||
expect(generatedCode).toMatch('var _client = "test-2"') | ||
fs.unlinkSync("./__crazy_outfile.js") | ||
}) | ||
}) | ||
@@ -178,5 +196,5 @@ }) | ||
} | ||
sync(options) | ||
expect(spy.mock.calls).toMatchSnapshot() | ||
return sync(options).then(function() { | ||
expect(spy.mock.calls).toMatchSnapshot() | ||
}) | ||
}) | ||
@@ -194,5 +212,5 @@ | ||
} | ||
sync(options) | ||
expect(spy.mock.calls).toMatchSnapshot() | ||
return sync(options).then(function() { | ||
expect(spy.mock.calls).toMatchSnapshot() | ||
}) | ||
}) | ||
@@ -206,3 +224,3 @@ }) | ||
it("prints failure", () => { | ||
it("prints failure and sends the message to the promise", () => { | ||
var spyConsoleLog = console.log | ||
@@ -227,3 +245,4 @@ var spyConsoleError = console.error | ||
return syncPromise.then(() => { | ||
return syncPromise.catch((errmsg) => { | ||
expect(errmsg).toEqual("Sync failed: GetStuff: something") | ||
expect(spyConsoleLog.mock.calls).toMatchSnapshot() | ||
@@ -230,0 +249,0 @@ expect(spyConsoleError.mock.calls).toMatchSnapshot() |
# graphql-ruby-client | ||
## 1.6.0 (19 Nov 2018) | ||
- Fix unused requires #1943 | ||
- Add `generateClient` function to generate code _without_ the HTTP call #1941 | ||
## 1.5.0 (27 October 2018) | ||
@@ -4,0 +9,0 @@ |
13
cli.js
@@ -51,12 +51,9 @@ #!/usr/bin/env node | ||
if (result instanceof Promise){ | ||
result.then(function(res) { | ||
if (res === false) { | ||
process.exit(1) | ||
} | ||
}) | ||
} else if (result === false) { | ||
result.then(function(res) { | ||
process.exit(0) | ||
}).catch(function(_err) { | ||
// The error is logged by the function | ||
process.exit(1) | ||
} | ||
}) | ||
} | ||
} |
var sync = require("./sync") | ||
var generateClient = require("./sync/generateClient").generateClient | ||
module.exports = { | ||
sync: sync, | ||
generateClient: generateClient, | ||
} |
{ | ||
"name": "graphql-ruby-client", | ||
"version": "1.5.0", | ||
"version": "1.6.0", | ||
"description": "JavaScript client for graphql-ruby", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -1,2 +0,2 @@ | ||
var { generateClient, JS_TYPE } = require("../generateClient") | ||
var { generateClientCode, JS_TYPE } = require("../generateClient") | ||
var fs = require("fs") | ||
@@ -6,4 +6,7 @@ | ||
// Generate some code and write it to a file | ||
var exampleMap = { a: "b", "c-d": "e-f" } | ||
var jsCode = generateClient("example-client", exampleMap, JS_TYPE) | ||
var exampleOperations = [ | ||
{name: "a", alias: "b"}, | ||
{name: "c-d", alias: "e-f"} | ||
] | ||
var jsCode = generateClientCode("example-client", exampleOperations, JS_TYPE) | ||
var filename = "./" + mapName + ".js" | ||
@@ -10,0 +13,0 @@ fs.writeFileSync(filename, jsCode) |
@@ -1,2 +0,2 @@ | ||
var { generateClient, JSON_TYPE } = require("../generateClient") | ||
var { generateClientCode, JSON_TYPE } = require("../generateClient") | ||
var fs = require("fs") | ||
@@ -6,4 +6,8 @@ | ||
// Generate some code and write it to a file | ||
var exampleMap = { a: "b", "c-d": "e-f" } | ||
var json = generateClient("example-client", exampleMap, JSON_TYPE) | ||
var exampleOperations = [ | ||
{name: "a", alias: "b"}, | ||
{name: "c-d", alias: "e-f"} | ||
] | ||
var json = generateClientCode("example-client", exampleOperations, JSON_TYPE) | ||
var filename = "./" + mapName + ".json" | ||
@@ -10,0 +14,0 @@ fs.writeFileSync(filename, json) |
@@ -1,3 +0,7 @@ | ||
var sendPayload = require("./sendPayload") | ||
var md5 = require("./md5") | ||
var glob = require("glob") | ||
var prepareRelay = require("./prepareRelay") | ||
var prepareIsolatedFiles = require("./prepareIsolatedFiles") | ||
var prepareProject = require("./prepareProject") | ||
@@ -16,2 +20,61 @@ var generateJs = require("./outfileGenerators/js") | ||
/** | ||
* Generate a JavaScript client module based on local `.graphql` files. | ||
* | ||
* See {gatherOperations} and {generateClientCode} for options. | ||
* @return {String} The generated JavaScript code | ||
*/ | ||
function generateClient(options) { | ||
var payload = gatherOperations(options) | ||
var generatedCode = generateClientCode(options.clientName, payload.operations, options.clientType) | ||
return generatedCode | ||
} | ||
/** | ||
* Parse files in the specified path and generate an alias for each operation. | ||
* | ||
* @param {Object} options | ||
* @param {String} options.path - A glob to recursively search for `.graphql` files (Default is `./`) | ||
* @param {String} options.mode - If `"file"`, treat each file separately. If `"project"`, concatenate all files and extract each operation. If `"relay"`, treat it as relay-compiler output | ||
* @param {Boolean} options.addTypename - Indicates if the "__typename" field are automatically added to your queries | ||
* @param {String} options.clientType - The type of the generated code (i.e., json, js) | ||
* @param {String} options.client - the Client ID that these operations belong to | ||
* @param {Function} options.hash - A custom hash function for query strings with the signature `options.hash(string) => digest` (Default is `md5(string) => digest`) | ||
* @return {Array} Array of operations with name and alias | ||
*/ | ||
function gatherOperations(options) { | ||
var graphqlGlob = options.path || "./" | ||
var hashFunc = options.hash || md5 | ||
var filesMode = options.mode || (graphqlGlob.indexOf("__generated__") > -1 ? "relay" : "project") | ||
var clientName = options.client | ||
var clientType = options.clientType | ||
var addTypename = options.addTypename | ||
// Check for file ext already, add it if missing | ||
var containsFileExt = graphqlGlob.indexOf(".graphql") > -1 || graphqlGlob.indexOf(".gql") > -1 | ||
if (!containsFileExt) { | ||
graphqlGlob = graphqlGlob + "**/*.graphql*" | ||
} | ||
var payload = { | ||
operations: [] | ||
} | ||
var filenames = glob.sync(graphqlGlob, {}) | ||
if (filesMode == "relay") { | ||
payload.operations = prepareRelay(filenames) | ||
} else { | ||
if (filesMode === "file") { | ||
payload.operations = prepareIsolatedFiles(filenames, addTypename) | ||
} else if (filesMode === "project") { | ||
payload.operations = prepareProject(filenames, addTypename) | ||
} else { | ||
throw new Error("Unexpected mode: " + filesMode) | ||
} | ||
// Update the operations with the hash of the body | ||
payload.operations.forEach(function(op) { | ||
op.alias = hashFunc(op.body) | ||
}) | ||
} | ||
return payload | ||
} | ||
/** | ||
* Given a map of { name => alias } pairs, generate outfile based on type. | ||
@@ -23,3 +86,3 @@ * @param {String} clientName - the client ID that this map belongs to | ||
*/ | ||
function generateClient(clientName, nameToAlias, type) { | ||
function generateClientCode(clientName, operations, type) { | ||
if (!clientName) { | ||
@@ -29,2 +92,7 @@ throw new Error("Client name is required to generate a persisted alias lookup map"); | ||
var nameToAlias = {} | ||
operations.forEach(function(op) { | ||
nameToAlias[op.name] = op.alias | ||
}) | ||
// Build up the map | ||
@@ -49,4 +117,6 @@ var keyValuePairs = "{" | ||
generateClient, | ||
generateClientCode, | ||
gatherOperations, | ||
JS_TYPE, | ||
JSON_TYPE, | ||
} |
@@ -1,2 +0,1 @@ | ||
var md5 = require("./md5") | ||
var sendPayload = require("./sendPayload") | ||
@@ -6,4 +5,3 @@ var prepareRelay = require("./prepareRelay") | ||
var prepareProject = require("./prepareProject") | ||
var { generateClient } = require("./generateClient") | ||
var printResponse = require("./printResponse") | ||
var { generateClientCode, gatherOperations } = require("./generateClient") | ||
var Logger = require("./logger") | ||
@@ -29,3 +27,3 @@ | ||
* @param {Function} options.hash - A custom hash function for query strings with the signature `options.hash(string) => digest` (Default is `md5(string) => digest`) | ||
* @return {void} | ||
* @return {Promise} Rejects with an Error or String if something goes wrong. Resolves with the operation payload if successful. | ||
*/ | ||
@@ -42,4 +40,6 @@ function sync(options) { | ||
} | ||
var graphqlGlob = options.path || "./" | ||
var hashFunc = options.hash || md5 | ||
var clientName = options.client | ||
if (!clientName) { | ||
throw new Error("Client name must be provided for sync") | ||
} | ||
var encryptionKey = options.secret | ||
@@ -49,5 +49,14 @@ if (encryptionKey) { | ||
} | ||
var sendFunc = options.send || sendPayload | ||
var filesMode = options.mode || (graphqlGlob.indexOf("__generated__") > -1 ? "relay" : "project") | ||
var payload = gatherOperations({ | ||
path: options.path, | ||
hash: options.hash, | ||
mode: options.mode, | ||
addTypename: options.addTypename, | ||
clientType: options.outfileType, | ||
client: clientName, | ||
}) | ||
var outfile | ||
@@ -62,87 +71,83 @@ if (options.outfile) { | ||
var clientName = options.client | ||
if (!clientName) { | ||
throw new Error("Client name must be provided for sync") | ||
} | ||
return new Promise(function(resolve, reject) { | ||
if (payload.operations.length === 0) { | ||
logger.log("No operations found in " + graphqlGlob + ", not syncing anything") | ||
resolve(payload) | ||
} else { | ||
logger.log("Syncing " + payload.operations.length + " operations to " + logger.bright(url) + "...") | ||
var sendOpts = { | ||
url: url, | ||
client: clientName, | ||
secret: encryptionKey, | ||
} | ||
var sendPromise = Promise.resolve(sendFunc(payload, sendOpts)) | ||
return sendPromise.then(function(response) { | ||
var responseData | ||
if (response) { | ||
try { | ||
responseData = JSON.parse(response) | ||
var aliasToNameMap = {} | ||
// Check for file ext already, add it if missing | ||
var containsFileExt = graphqlGlob.indexOf(".graphql") > -1 || graphqlGlob.indexOf(".gql") > -1 | ||
if (!containsFileExt) { | ||
graphqlGlob = graphqlGlob + "**/*.graphql*" | ||
} | ||
payload.operations.forEach(function(op) { | ||
aliasToNameMap[op.alias] = op.name | ||
}) | ||
var payload = { | ||
operations: [] | ||
} | ||
var failed = responseData.failed.length | ||
// These might get overriden for status output | ||
var notModified = responseData.not_modified.length | ||
var added = responseData.added.length | ||
if (failed) { | ||
// Override these to reflect reality | ||
notModified = 0 | ||
added = 0 | ||
} | ||
var filenames = glob.sync(graphqlGlob, {}) | ||
var addedColor = added ? "green" : "dim" | ||
logger.log(" " + logger.colorize(addedColor, added + " added")) | ||
var notModifiedColor = notModified ? "reset" : "dim" | ||
if (filesMode == "relay") { | ||
payload.operations = prepareRelay(filenames) | ||
} else { | ||
if (filesMode === "file") { | ||
payload.operations = prepareIsolatedFiles(filenames, options.addTypename) | ||
} else if (filesMode === "project") { | ||
payload.operations = prepareProject(filenames, options.addTypename) | ||
} else { | ||
throw new Error("Unexpected mode: " + filesMode) | ||
} | ||
// Update the operations with the hash of the body | ||
payload.operations.forEach(function(op) { | ||
op.alias = hashFunc(op.body) | ||
}) | ||
} | ||
logger.log(" " + logger.colorize(notModifiedColor, notModified + " not modified")) | ||
var failedColor = failed ? "red" : "dim" | ||
logger.log(" " + logger.colorize(failedColor, failed + " failed")) | ||
if (payload.operations.length === 0) { | ||
logger.log("No operations found in " + graphqlGlob + ", not syncing anything") | ||
} else { | ||
logger.log("Syncing " + payload.operations.length + " operations to " + logger.bright(url) + "...") | ||
var writeArtifacts = function(response) { | ||
var nameToAliasMap = {} | ||
var aliasToNameMap = {} | ||
payload.operations.forEach(function(op) { | ||
nameToAliasMap[op.name] = op.alias | ||
aliasToNameMap[op.alias] = op.name | ||
}) | ||
var responseData | ||
if (response) { | ||
try { | ||
responseData = JSON.parse(response) | ||
printResponse(responseData, aliasToNameMap, logger) | ||
if (responseData.failed.length) { | ||
return false | ||
if (failed) { | ||
logger.error("Sync failed, errors:") | ||
var failedOperationAlias, failedOperationName, errors | ||
var allErrors = [] | ||
for (failedOperationAlias in responseData.errors) { | ||
failedOperationName = aliasToNameMap[failedOperationAlias] | ||
logger.error(" " + failedOperationName + ":") | ||
errors = responseData.errors[failedOperationAlias] | ||
errors.forEach(function(errMessage) { | ||
allErrors.push(failedOperationName + ": " + errMessage) | ||
logger.error(" " + logger.colorize("red", "✘") + " " + errMessage) | ||
}) | ||
} | ||
reject("Sync failed: " + allErrors.join(", ")) | ||
return | ||
} | ||
} catch (err) { | ||
logger.log("Failed to print sync result:", err) | ||
reject(err) | ||
return | ||
} | ||
} catch (err) { | ||
logger.log("Failed to print sync result:", err) | ||
} | ||
} | ||
var generatedCode = generateClient(clientName, nameToAliasMap, options.outfileType) | ||
logger.log("Generating client module in " + logger.colorize("bright", outfile) + "...") | ||
fs.writeFileSync(outfile, generatedCode, "utf8") | ||
logger.log(logger.green("✓ Done!")) | ||
} | ||
var sendOpts = { | ||
url: url, | ||
client: clientName, | ||
secret: encryptionKey, | ||
} | ||
var maybePromise = sendFunc(payload, sendOpts) | ||
if (maybePromise instanceof Promise) { | ||
return maybePromise.then(writeArtifacts).catch(function(err) { | ||
var generatedCode = generateClientCode(clientName, payload.operations, options.outfileType) | ||
payload.generatedCode = generatedCode | ||
logger.log("Generating client module in " + logger.colorize("bright", outfile) + "...") | ||
fs.writeFileSync(outfile, generatedCode, "utf8") | ||
logger.log(logger.green("✓ Done!")) | ||
resolve(payload) | ||
return | ||
}).catch(function(err) { | ||
logger.error(logger.colorize("red", "Sync failed:")) | ||
logger.error(err) | ||
return false | ||
reject(err) | ||
return | ||
}) | ||
} else { | ||
return writeArtifacts() | ||
} | ||
} | ||
}) | ||
} | ||
module.exports = sync |
@@ -5,3 +5,2 @@ var http = require("http") | ||
var crypto = require('crypto') | ||
var printResponse = require("./printResponse") | ||
@@ -8,0 +7,0 @@ /** |
Sorry, the diff of this file is not supported yet
160686
59
2240