From 66bde56ea7e2e765c9819b05e03c982811f7d0e3 Mon Sep 17 00:00:00 2001 From: Paul Le Cam Date: Thu, 3 Nov 2016 11:10:02 +0000 Subject: [PATCH] First --- .babelrc | 8 +++ .gitignore | 1 + README.md | 23 ++++++++ bin/graphql-fetch-schema | 2 + lib/cli.js | 66 ++++++++++++++++++++++ lib/index.js | 115 +++++++++++++++++++++++++++++++++++++++ package.json | 30 ++++++++++ src/cli.js | 30 ++++++++++ src/index.js | 63 +++++++++++++++++++++ 9 files changed, 338 insertions(+) create mode 100644 .babelrc create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bin/graphql-fetch-schema create mode 100644 lib/cli.js create mode 100644 lib/index.js create mode 100644 package.json create mode 100644 src/cli.js create mode 100644 src/index.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..c915fc4 --- /dev/null +++ b/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["latest"], + "plugins": [ + "syntax-flow", + "transform-flow-strip-types", + "transform-runtime" + ] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..7980af0 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# graphql-fetch-schema + +Fetch a GraphQL schema from a server and write it to file + +## Usage + +```sh +graphql-fetch-schema [options] +``` + +### Options + +``` +-h, --help output usage information +-V, --version output the version number +-g, --graphql write schema.graphql file +-j, --json write schema.json file +-o, --output write to specified directory +``` + +## License + +MIT diff --git a/bin/graphql-fetch-schema b/bin/graphql-fetch-schema new file mode 100755 index 0000000..fa67b84 --- /dev/null +++ b/bin/graphql-fetch-schema @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/cli') diff --git a/lib/cli.js b/lib/cli.js new file mode 100644 index 0000000..f7b1166 --- /dev/null +++ b/lib/cli.js @@ -0,0 +1,66 @@ +'use strict'; + +var _regenerator = require('babel-runtime/regenerator'); + +var _regenerator2 = _interopRequireDefault(_regenerator); + +var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); + +var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); + +var _commander = require('commander'); + +var _commander2 = _interopRequireDefault(_commander); + +var _index = require('./index'); + +var _index2 = _interopRequireDefault(_index); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var run = function () { + var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(url, options) { + var files; + return _regenerator2.default.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + _context.prev = 0; + _context.next = 3; + return (0, _index2.default)(url, options); + + case 3: + files = _context.sent; + + files.forEach(function (file) { + console.log(file.filePath); + }); + _context.next = 10; + break; + + case 7: + _context.prev = 7; + _context.t0 = _context['catch'](0); + + console.error(_context.t0); + + case 10: + case 'end': + return _context.stop(); + } + } + }, _callee, undefined, [[0, 7]]); + })); + + return function run(_x, _x2) { + return _ref.apply(this, arguments); + }; +}(); + +_commander2.default.version('0.1.0').usage(' [options]').option('-g, --graphql', 'write schema.graphql file').option('-j, --json', 'write schema.json file').option('-o, --output ', 'write to specified directory').parse(process.argv); + +run(_commander2.default.args[0], { + graphql: !!_commander2.default.graphql, + json: !!_commander2.default.json, + outputPath: _commander2.default.output +}); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..e83ee11 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,115 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _regenerator = require('babel-runtime/regenerator'); + +var _regenerator2 = _interopRequireDefault(_regenerator); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); + +var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); + +var _promise = require('babel-runtime/core-js/promise'); + +var _promise2 = _interopRequireDefault(_promise); + +var _utilities = require('graphql/utilities'); + +var _fs = require('fs'); + +var _fs2 = _interopRequireDefault(_fs); + +var _nodeFetch = require('node-fetch'); + +var _nodeFetch2 = _interopRequireDefault(_nodeFetch); + +var _path = require('path'); + +var _path2 = _interopRequireDefault(_path); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var writeFile = function writeFile(_ref) { + var filePath = _ref.filePath, + contents = _ref.contents; + + return new _promise2.default(function (resolve, reject) { + _fs2.default.writeFile(filePath, contents, function (err) { + if (err) reject(err);else resolve(); + }); + }); +}; + +exports.default = function () { + var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(url) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var pathPrefix, res, schema, files; + return _regenerator2.default.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + // If no option is set, consider it's all + if (!options.graphql && !options.json) { + options.graphql = true; + options.json = true; + } + pathPrefix = options.outputPath || './'; + _context.next = 4; + return (0, _nodeFetch2.default)(url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: (0, _stringify2.default)({ + query: _utilities.introspectionQuery + }) + }); + + case 4: + res = _context.sent; + _context.next = 7; + return res.json(); + + case 7: + schema = _context.sent; + files = []; + + if (options.graphql) { + files.push({ + filePath: _path2.default.resolve(pathPrefix, 'schema.graphql'), + contents: (0, _utilities.printSchema)((0, _utilities.buildClientSchema)(schema.data)) + }); + } + if (options.json) { + files.push({ + filePath: _path2.default.resolve(pathPrefix, 'schema.json'), + contents: (0, _stringify2.default)(schema, null, 2) + }); + } + + _context.next = 13; + return _promise2.default.all(files.map(writeFile)); + + case 13: + return _context.abrupt('return', files); + + case 14: + case 'end': + return _context.stop(); + } + } + }, _callee, undefined); + })); + + return function (_x, _x2) { + return _ref2.apply(this, arguments); + }; +}(); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ed6cf9d --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "graphql-fetch-schema", + "version": "0.1.0", + "description": "Fetch a GraphQL schema from a server and write it to file", + "main": "lib/index.js", + "bin": { + "graphql-fetch-schema": "./bin/graphql-fetch-schema" + }, + "scripts": { + "clean": "rm -rf ./lib", + "compile": "babel src --out-dir lib", + "build": "npm run clean && npm run compile", + "start": "npm run compile" + }, + "author": "Paul Le Cam ", + "license": "MIT", + "dependencies": { + "babel-runtime": "^6.18.0", + "commander": "^2.9.0", + "graphql": "^0.7.2", + "node-fetch": "^1.6.3" + }, + "devDependencies": { + "babel-cli": "^6.18.0", + "babel-plugin-syntax-flow": "^6.18.0", + "babel-plugin-transform-flow-strip-types": "^6.18.0", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-preset-latest": "^6.16.0" + } +} diff --git a/src/cli.js b/src/cli.js new file mode 100644 index 0000000..fff75b0 --- /dev/null +++ b/src/cli.js @@ -0,0 +1,30 @@ +// @flow + +import program from 'commander' + +import fetchSchema from './index' + +const run = async (url: string, options: Object) => { + try { + const files = await fetchSchema(url, options) + files.forEach((file: Object) => { + console.log(file.filePath) + }) + } catch (err) { + console.error(err) + } +} + +program + .version('0.1.0') + .usage(' [options]') + .option('-g, --graphql', 'write schema.graphql file') + .option('-j, --json', 'write schema.json file') + .option('-o, --output ', 'write to specified directory') + .parse(process.argv) + +run(program.args[0], { + graphql: !!program.graphql, + json: !!program.json, + outputPath: program.output, +}) diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..88d9913 --- /dev/null +++ b/src/index.js @@ -0,0 +1,63 @@ +// @flow + +import { + buildClientSchema, + introspectionQuery, + printSchema, +} from 'graphql/utilities' +import fs from 'fs' +import fetch from 'node-fetch' +import path from 'path' + +type Options = { + graphql?: boolean, + json?: boolean, + outputPath?: string, +} + +const writeFile = ({filePath, contents}: {filePath: string, contents: string}) => { + return new Promise((resolve, reject) => { + fs.writeFile(filePath, contents, (err) => { + if (err) reject(err) + else resolve() + }) + }) +} + +export default async (url: string, options: Options = {}) => { + // If no option is set, consider it's all + if (!options.graphql && !options.json) { + options.graphql = true + options.json = true + } + const pathPrefix = options.outputPath || './' + + const res = await fetch(url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: introspectionQuery, + }), + }) + const schema = await res.json() + + const files = [] + if (options.graphql) { + files.push({ + filePath: path.resolve(pathPrefix, 'schema.graphql'), + contents: printSchema(buildClientSchema(schema.data)), + }) + } + if (options.json) { + files.push({ + filePath: path.resolve(pathPrefix, 'schema.json'), + contents: JSON.stringify(schema, null, 2), + }) + } + + await Promise.all(files.map(writeFile)) + return files +}