├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── CLIENT-ERRORS-SAMPLE.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── jest.config.js
├── lib
├── cli.d.ts
├── cli.js
├── cli.js.map
├── commands
│ ├── ask
│ │ ├── ask.d.ts
│ │ ├── ask.js
│ │ ├── ask.js.map
│ │ ├── createRawFileFromEntries.d.ts
│ │ ├── createRawFileFromEntries.js
│ │ ├── createRawFileFromEntries.js.map
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── index.js.map
│ │ ├── makeHeaders.d.ts
│ │ ├── makeHeaders.js
│ │ ├── makeHeaders.js.map
│ │ ├── queryServer.d.ts
│ │ ├── queryServer.js
│ │ └── queryServer.js.map
│ ├── generate
│ │ ├── checkEntries.d.ts
│ │ ├── checkEntries.js
│ │ ├── checkEntries.js.map
│ │ ├── createError.d.ts
│ │ ├── createError.js
│ │ ├── createError.js.map
│ │ ├── generate.d.ts
│ │ ├── generate.js
│ │ ├── generate.js.map
│ │ ├── generateRawClass.d.ts
│ │ ├── generateRawClass.js
│ │ ├── generateRawClass.js.map
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ └── index.js.map
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── index.d.ts
├── index.js
├── index.js.map
├── types.d.ts
├── types.js
├── types.js.map
├── utils
│ ├── fs-prophecy.d.ts
│ ├── fs-prophecy.js
│ ├── fs-prophecy.js.map
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── writeClassFile.d.ts
├── writeClassFile.js
└── writeClassFile.js.map
├── package-lock.json
├── package.json
├── src
├── _specs-utils
│ ├── index.ts
│ └── jest-fs.ts
├── cli.ts
├── commands
│ ├── ask
│ │ ├── ask.ts
│ │ ├── createRawFileFromEntries.spec.ts
│ │ ├── createRawFileFromEntries.ts
│ │ ├── index.ts
│ │ ├── makeHeaders.spec.ts
│ │ ├── makeHeaders.ts
│ │ └── queryServer.ts
│ ├── generate
│ │ ├── checkEntries.spec.ts
│ │ ├── checkEntries.ts
│ │ ├── createError.spec.ts
│ │ ├── createError.ts
│ │ ├── generate.spec.ts
│ │ ├── generate.ts
│ │ ├── generateRawClass.spec.ts
│ │ ├── generateRawClass.ts
│ │ └── index.ts
│ └── index.ts
├── index.ts
├── types.ts
├── utils
│ ├── fs-prophecy.ts
│ └── index.ts
├── writeClassFile.spec.ts
└── writeClassFile.ts
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | lib/
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | es6: true,
6 | "jest/globals": true
7 | },
8 | parser: '@typescript-eslint/parser',
9 | parserOptions: {
10 | project: './tsconfig.json',
11 | },
12 | plugins: [
13 | '@typescript-eslint',
14 | ],
15 | extends: [
16 | 'airbnb-typescript'
17 | ],
18 | };
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env*
2 | node_modules
3 | .idea
4 | .vscode
5 | *.log
6 | _generated/
7 | _generated/Errors.ts
8 | .nyc_output
9 | coverage
10 | Errors.ts
11 | errors.json
12 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: '8'
3 | cache:
4 | directories:
5 | - node_modules
6 | after_success: npm run coverage
--------------------------------------------------------------------------------
/CLIENT-ERRORS-SAMPLE.md:
--------------------------------------------------------------------------------
1 | Here you will find an example of client-side generated `Errors.ts`;
2 |
3 | ```ts
4 | /* tslint:disable */
5 | import { ApolloError } from "apollo-client";
6 | import { GraphQLError } from "graphql";
7 |
8 | export enum PropheticErrorCode {
9 | CodeLessError = 'NONE',
10 | UnknownError = "UNKNOWN",
11 | ForbiddenError = "FORBIDDEN",
12 | AuthenticationRequiredError = "AUTH_REQUIRED"
13 | }
14 |
15 | export class PropheticError {
16 | constructor(public codes: string[]){}
17 |
18 | private inCodes(code: PropheticErrorCode){ return this.codes.indexOf(code) > -1; }
19 |
20 | get isCodeLessError() { return this.inCodes(PropheticErrorCode.CodeLessError); }
21 | get isUnknownError() { return this.inCodes(PropheticErrorCode.UnknownError); }
22 | get isForbiddenError() { return this.inCodes(PropheticErrorCode.ForbiddenError); }
23 | get isAuthenticationRequiredError() { return this.inCodes(PropheticErrorCode.AuthenticationRequiredError); }
24 | }
25 |
26 | export interface Handler {
27 | (): any
28 | }
29 |
30 | export class PropheticErrorHandled {
31 | private handler: Handler = () => {}
32 |
33 | constructor(public codes: string[]){}
34 |
35 | private inCodes(code: PropheticErrorCode, handler: Handler){
36 | if(this.codes.indexOf(code) > -1){
37 | this.handler = handler
38 | }
39 |
40 | return this;
41 | }
42 |
43 | CodeLessError(handler: Handler) { return this.inCodes(PropheticErrorCode.CodeLessError, handler); }
44 | UnknownError(handler: Handler) { return this.inCodes(PropheticErrorCode.UnknownError, handler); }
45 | ForbiddenError(handler: Handler) { return this.inCodes(PropheticErrorCode.ForbiddenError, handler); }
46 | AuthenticationRequiredError(handler: Handler) { return this.inCodes(PropheticErrorCode.AuthenticationRequiredError, handler); }
47 | handle() { return this.handler(); }
48 | }
49 |
50 | const CODE_LESS_EXTENSION = { code: 'NONE'};
51 | const findCodes = (error: ApolloError | GraphQLError): PropheticErrorCode[] => {
52 | if(error instanceof ApolloError) {
53 | return error.graphQLErrors.map((gError) => findCodes(gError)[0]);
54 | } else if(error.extensions) {
55 | const { extensions: { code } = CODE_LESS_EXTENSION } = error;
56 | return [code];
57 | }
58 |
59 | return [PropheticErrorCode.CodeLessError];
60 | }
61 |
62 | export const errorHere = (error: ApolloError | GraphQLError | undefined ) => {
63 | if(!error) {
64 | return new PropheticError([]);
65 | }
66 | const codes = findCodes(error);
67 | return new PropheticError(codes);
68 | }
69 |
70 | export const isThis = (error: ApolloError | GraphQLError | undefined) => {
71 | if(!error) {
72 | return new PropheticErrorHandled([]);
73 | }
74 | const codes = findCodes(error);
75 | return new PropheticErrorHandled(codes);
76 | }
77 | ```
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 | [](https://travis-ci.com/theGlenn/apollo-prophecy)
3 |
4 | > **Working on your first Pull Request?**
5 | > You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
6 |
7 |
8 |
9 | ✊ | Grab an issue | ⏬ |
10 | 🍴 | Fork develop | ⏬ |
11 | 👨💻 | Code | ⏬ |
12 | 🛠 | Test | ⏬ |
13 | 📩 | Pull Request | ⏬ |
14 |
15 |
💥💥💥
16 |
17 |
18 | ### TODO
19 |
20 | * See [#2][i2]: Add support for third-party errors libraries like [apollo-errors](https://github.com/thebigredgeek/apollo-errors) good first issue
21 | * See [#12][i12]: Add `errors.json` file as ask command argument good first issue
22 | * See [#16][i16]: Add language specific code generation [Java/Kotlin][i13]/[Swift][i14]/[Javascript][i15]
23 | * See [#13][i13]: Java/Kotlin good first issue
24 | * See [#14][i14]: Swift good first issue
25 | * See [#15][i15]: Javascript good first issue
26 |
27 |
28 | [i2]: https://github.com/theGlenn/apollo-prophecy/issues/2
29 | [i12]: https://github.com/theGlenn/apollo-prophecy/issues/12
30 |
31 | [i13]: https://github.com/theGlenn/apollo-prophecy/issues/13
32 | [i14]: https://github.com/theGlenn/apollo-prophecy/issues/14
33 | [i15]: https://github.com/theGlenn/apollo-prophecy/issues/15
34 |
35 | [i16]: https://github.com/theGlenn/apollo-prophecy/issues/16
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Glenn Sonna
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | Apollo Prophecy
3 |
4 |
5 | 👁📟👁
6 |
You shall fail... successfully
7 |
8 |
9 |
10 | Command tool to generate errors files for your Appolo Server and Client
11 |
12 |
13 |
50 |
54 |
55 | ## 📟 Features
56 |
57 | * Generate **Server-side** **throwable** errors in your resolvers like `throw new NotAProphetError()`
58 | * Expose **machine readable** graphql errors through your api documentation
59 | * Generate **Client-side** Apollo errors **consumable** like `errorHere(error).isNotAProphetError ?`
60 |
61 | # 📋 Table of Contents
62 |
63 | * [Installation](#installation)
64 | * [Usage](#usage)
65 | * [Server Side](#server)
66 | * [Client Side](#client)
67 | * [Contributing](#contributing)
68 | * [TODO](#todo)
69 | * [Test and Miscellaneous](#run-tests)
70 |
71 | ## Installation
72 |
73 | Install with npm:
74 |
75 | ```sh
76 | npm install -g apollo-prophecy
77 | ```
78 |
79 | Install with yarn:
80 |
81 | ```sh
82 | yarn global add apollo-prophecy
83 | ```
84 |
85 | ## Usage
86 |
87 | ```
88 | Usage: apollo-prophecy [command]
89 |
90 | Commands:
91 | apollo-prophecy generate [--out]
92 | apollo-prophecy ask [--type] [--out]
93 |
94 | Options:
95 | -h, --help Show help [boolean]
96 | -v, --version Display version number [boolean]
97 | ```
98 |
99 | ### Server
100 | > ⚠️ This Project is *Only* compatible with Apollo-Server v2
101 |
102 | #### `generate` command
103 |
104 | Creates `Error.ts` from a `JSON` input file. Using `--out` param you can change the name and location.
105 |
106 | ```sh
107 | apollo-prophecy generate errors.json
108 | ```
109 |
110 | Input file entries should at least contains the keys `message` and `code`.
111 |
112 | For example given the following `errors.json` as input:
113 |
114 | ```json
115 | {
116 | "AuthenticationRequiredError": {
117 | "message": "You must be logged in to do this",
118 | "code": "AUTH_REQUIRED"
119 | },
120 | "UserNotFoundError": {
121 | "message": "No user found",
122 | "code": "USER_NOT_FOUND"
123 | },
124 | }
125 | ```
126 |
127 | Apollo Prophecy will generate the following `Errors.ts`
128 |
129 | ```ts
130 | ...
131 | export class AuthenticationRequiredError extends ProphecyError {
132 | constructor(properties?: Record) {
133 | super("AuthenticationRequiredError", "You must be logged in to do this","AUTH_REQUIRED", properties);
134 | }
135 | }
136 |
137 | export class UserNotFoundError extends ProphecyError {
138 | constructor(properties?: Record) {
139 | super("UserNotFoundError", "No user found", "USER_NOT_FOUND", properties);
140 | }
141 | }
142 | ...
143 | ```
144 |
145 | Now you can use it the following way `throw new UserNotFoundError()` in your resolvers.
146 |
147 | `apollo-prophecy` also exposes a `definitions` object and a graphql type definition named `PropheticError` so that you can expose all your errors descriptions through a resolver, [see Client](###client).
148 |
149 | ```ts
150 | ...
151 | export const definitions = [{
152 | "name": "AuthenticationRequiredError"
153 | "message": "You must be logged in to do this",
154 | "extensions": {
155 | "code": "AUTH_REQUIRED"
156 | }
157 | }, {
158 | "name": "UserNotFoundError"
159 | "message": "No user found",
160 | "extensions": {
161 | "code": "USER_NOT_FOUND"
162 | }
163 | }
164 | }];
165 |
166 | export const errorType = `
167 | type PropheticErrorExtensions {
168 | code: String
169 | }
170 |
171 | type PropheticError {
172 | message: String?
173 | extensions: PropheticErrorExtensions
174 | }
175 | `;
176 | ...
177 | ```
178 |
179 | ### Client
180 |
181 | #### `ask` command
182 |
183 | Queries the `errors` field on the specified graphql endpoint and creates an `Errors.ts` file containing helpers with **check methods** ([see Helpers](#helpers)) for all the errors exposed through the server api documentation.
184 |
185 | ```sh
186 | apollo-prophecy ask http://localhost:3000/graphql
187 | ```
188 |
189 | #### Helpers
190 |
191 | In order to easily handle erros with **Apollo-Client**, the generated `Errors.ts` exposes two helpers methods `errorHere` and `isThis`, both methods takes one paramater of type `ApolloError` or `GraphQLError`.
192 |
193 | ##### `errorHere()` function
194 |
195 | `errorHere` returns an object that has a **property** named after each errors.
196 | You can perform a simple `boolean` check on the `error` argument by calling the approiate *key*.
197 |
198 | ```ts
199 | import { errorHere } from `./_generated/Errors.ts`;
200 |
201 | ...(error) => {
202 | if(errorHere(error).isUserNotFoundError){
203 | // Do something
204 | } else if(errorHere(error).isNotAProphetError){
205 | // Do something else
206 | }
207 | }
208 | ```
209 |
210 | ##### `isThis()` function
211 |
212 | `isThis` returns an object that has a **handler** method for each errors.
213 | It perfoms a simple check on the `error` argument, if the it succeed the corresponding handler is called otherwise nothing happens.
214 |
215 | Note: Handlers can return a values.
216 |
217 | ```ts
218 | import { isThis } from `./_generated/Errors.ts`;
219 |
220 | ...(error) => {
221 | isThis(error)
222 | .UserNotFoundError(() => ...)
223 | .NotAProphetError(() => ...)
224 | .handle()
225 | }
226 | ```
227 |
228 | React example:
229 |
230 | ```tsx
231 | import { isThis } from `./_generated/Errors.ts`;
232 |
233 | ...(error) => {
234 | return
235 | {
236 | isThis(error)
237 | .UserNotFoundError(() => Could not find a user with tha name)
238 | .NotAProphetError(() => Only Prophets can perfom this kind of actions...)
239 | .handle();
240 | }
241 |
242 | }
243 | ```
244 |
245 | ## Contributing
246 | [](https://travis-ci.com/theGlenn/apollo-prophecy)
247 |
248 |
249 |
250 | ✊ | Grab an issue | ⏬ |
251 | 🍴 | fork develop | ⏬ |
252 | 👨💻 | Code | ⏬ |
253 | 🛠 | Test | ⏬ |
254 | 📩 | Pull Request | ⏬ |
255 |
256 |
💥💥💥
257 |
258 |
259 | ### TODO
260 |
261 | * See [#2][i2]: Add support for third-party errors libraries like [apollo-errors](https://github.com/thebigredgeek/apollo-errors) good first issue
262 | * See [#12][i12]: Add `errors.json` file as ask command argument good first issue
263 | * See [#16][i16]: Add language specific code generation [Java/Kotlin][i13]/[Swift][i14]/[Javascript][i15]
264 | * See [#13][i13]: Java/Kotlin good first issue
265 | * See [#14][i14]: Swift good first issue
266 | * See [#15][i15]: Javascript good first issue
267 |
268 |
269 | [i2]: https://github.com/theGlenn/apollo-prophecy/issues/2
270 | [i12]: https://github.com/theGlenn/apollo-prophecy/issues/12
271 |
272 | [i13]: https://github.com/theGlenn/apollo-prophecy/issues/13
273 | [i14]: https://github.com/theGlenn/apollo-prophecy/issues/14
274 | [i15]: https://github.com/theGlenn/apollo-prophecy/issues/15
275 |
276 | [i16]: https://github.com/theGlenn/apollo-prophecy/issues/16
277 |
278 | ### Run tests
279 |
280 | ```sh
281 | npm test
282 | ```
283 |
284 | ```sh
285 | yarn test
286 | ```
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const jestOverwrites = {
2 | roots: ['src'],
3 | testMatch: ['**/*.spec.ts'],
4 | watchPathIgnorePatterns: ['/node_modules'],
5 | };
6 |
7 | module.exports = {
8 | ...jestOverwrites,
9 | clearMocks: true,
10 | collectCoverage: true,
11 | preset: 'ts-jest'
12 | };
--------------------------------------------------------------------------------
/lib/cli.d.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | export {};
3 |
--------------------------------------------------------------------------------
/lib/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | "use strict";
3 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | var __generator = (this && this.__generator) || function (thisArg, body) {
12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14 | function verb(n) { return function (v) { return step([n, v]); }; }
15 | function step(op) {
16 | if (f) throw new TypeError("Generator is already executing.");
17 | while (_) try {
18 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
19 | if (y = 0, t) op = [0, t.value];
20 | switch (op[0]) {
21 | case 0: case 1: t = op; break;
22 | case 4: _.label++; return { value: op[1], done: false };
23 | case 5: _.label++; y = op[1]; op = [0]; continue;
24 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
25 | default:
26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30 | if (t[2]) _.ops.pop();
31 | _.trys.pop(); continue;
32 | }
33 | op = body.call(thisArg, _);
34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36 | }
37 | };
38 | var _this = this;
39 | Object.defineProperty(exports, "__esModule", { value: true });
40 | var yargs = require("yargs");
41 | var _1 = require("./");
42 | var path_1 = require("path");
43 | function handleError(error) {
44 | console.error(error);
45 | process.exit(1);
46 | }
47 | process.on('unhandledRejection', function (error) { throw error; });
48 | process.on('uncaughtException', handleError);
49 | ;
50 | yargs
51 | .command(['generate [jsonFile]', 'prophecy'], 'Generate a Typescript file containg all application errors from a JSON input', {
52 | out: {
53 | demand: true,
54 | describe: 'Output path for error file',
55 | default: './Errors.ts',
56 | normalize: true,
57 | coerce: path_1.resolve
58 | },
59 | }, function (argv) { return __awaiter(_this, void 0, void 0, function () {
60 | var _a, jsonFile, outputFilePath, intputFilePath, generatedOutputPath;
61 | return __generator(this, function (_b) {
62 | switch (_b.label) {
63 | case 0:
64 | _a = argv.jsonFile, jsonFile = _a === void 0 ? './errors.json' : _a, outputFilePath = argv.out;
65 | intputFilePath = path_1.resolve(jsonFile);
66 | return [4 /*yield*/, _1.commands.generate({ intputFilePath: intputFilePath, outputFilePath: outputFilePath })];
67 | case 1:
68 | generatedOutputPath = _b.sent();
69 | console.info('🔮 You will fail... but successfully');
70 | console.info("\u2514\u2500\u2500 \uD83D\uDC41 Prophecy available at " + generatedOutputPath);
71 | return [2 /*return*/];
72 | }
73 | });
74 | }); })
75 | .command(['ask ', 'oracles'], 'Generate a .ts file that exposes helpers for all the errors exposed through the server api', {
76 | field: {
77 | demandOption: true,
78 | describe: 'Field to query on Query type',
79 | default: 'errors',
80 | },
81 | out: {
82 | demandOption: true,
83 | describe: 'Output path for error file',
84 | default: './Errors.ts',
85 | normalize: true,
86 | coerce: path_1.resolve
87 | },
88 | }, function (argv) { return __awaiter(_this, void 0, void 0, function () {
89 | var input, outputFilePath, errorField, outputPath;
90 | return __generator(this, function (_a) {
91 | switch (_a.label) {
92 | case 0:
93 | console.info('🔮 Connecting with the oracles...');
94 | input = argv.schema, outputFilePath = argv.out, errorField = argv.field;
95 | return [4 /*yield*/, _1.commands.ask({ input: input, errorField: errorField, outputFilePath: outputFilePath })];
96 | case 1:
97 | outputPath = _a.sent();
98 | console.info('├── 🙏 You will fail... but successfully');
99 | console.info("\u2514\u2500\u2500 \uD83D\uDC41 All you need to know is available at " + outputPath);
100 | return [2 /*return*/];
101 | }
102 | });
103 | }); })
104 | .fail(function (message, error) { return handleError(error ? error : new Error(message)); })
105 | .help()
106 | .version()
107 | .strict()
108 | .argv;
109 | //# sourceMappingURL=cli.js.map
--------------------------------------------------------------------------------
/lib/cli.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,iBAuEQ;;AAvER,6BAA+B;AAE/B,uBAA8B;AAC9B,6BAA+B;AAE/B,qBAAqB,KAAK;IACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,UAAC,KAAK,IAAO,MAAM,KAAK,CAAA,CAAC,CAAC,CAAC,CAAC;AAC7D,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;AAQ5C,CAAC;AAEF,KAAK;KACF,OAAO,CACN,CAAC,qBAAqB,EAAE,UAAU,CAAC,EACnC,8EAA8E,EAC9E;IACE,GAAG,EAAE;QACH,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,4BAA4B;QACtC,OAAO,EAAE,aAAa;QACtB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,cAAO;KAChB;CACF,EACD,UAAO,IAAU;;;;;gBACP,KAAoD,IAAI,SAA9B,EAA1B,QAAQ,mBAAG,eAAe,KAAA,EAAO,cAAc,GAAK,IAAI,IAAT,CAAU;gBAC3D,cAAc,GAAG,cAAO,CAAC,QAAQ,CAAC,CAAC;gBACb,qBAAM,WAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,gBAAA,EAAE,cAAc,gBAAA,EAAE,CAAC,EAAA;;gBAAjF,mBAAmB,GAAG,SAA2D;gBACvF,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,2DAAgC,mBAAqB,CAAC,CAAC;;;;KACrE,CACF;KACA,OAAO,CACN,CAAC,cAAc,EAAE,SAAS,CAAC,EAC3B,4FAA4F,EAC5F;IACE,KAAK,EAAE;QACL,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,8BAA8B;QACxC,OAAO,EAAE,QAAQ;KAClB;IACD,GAAG,EAAE;QACH,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,4BAA4B;QACtC,OAAO,EAAE,aAAa;QACtB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,cAAO;KAChB;CACF,EACD,UAAO,IAAU;;;;;gBACf,OAAO,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;gBAClC,KAAK,GAA6C,IAAI,OAAjD,EAAO,cAAc,GAAwB,IAAI,IAA5B,EAAS,UAAU,GAAK,IAAI,MAAT,CAAU;gBACpD,qBAAM,WAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,OAAA,EAAE,UAAU,YAAA,EAAE,cAAc,gBAAA,EAAE,CAAC,EAAA;;gBAAtE,UAAU,GAAG,SAAyD;gBAC5E,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;gBACzD,OAAO,CAAC,IAAI,CAAC,0EAA+C,UAAY,CAAC,CAAC;;;;KAC3E,CACF;KACA,IAAI,CAAC,UAAC,OAAO,EAAE,KAAK,IAAK,OAAA,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAA/C,CAA+C,CAAC;KACzE,IAAI,EAAE;KACN,OAAO,EAAE;KACT,MAAM,EAAE;KACR,IAAI,CAAC"}
--------------------------------------------------------------------------------
/lib/commands/ask/ask.d.ts:
--------------------------------------------------------------------------------
1 | export interface AskArgs {
2 | input?: string;
3 | outputFilePath?: string;
4 | errorField?: string;
5 | headers?: string[];
6 | }
7 | export default function ask({ input, errorField, headers, outputFilePath }: AskArgs): Promise;
8 |
--------------------------------------------------------------------------------
/lib/commands/ask/ask.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | var __generator = (this && this.__generator) || function (thisArg, body) {
11 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13 | function verb(n) { return function (v) { return step([n, v]); }; }
14 | function step(op) {
15 | if (f) throw new TypeError("Generator is already executing.");
16 | while (_) try {
17 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
18 | if (y = 0, t) op = [0, t.value];
19 | switch (op[0]) {
20 | case 0: case 1: t = op; break;
21 | case 4: _.label++; return { value: op[1], done: false };
22 | case 5: _.label++; y = op[1]; op = [0]; continue;
23 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
24 | default:
25 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29 | if (t[2]) _.ops.pop();
30 | _.trys.pop(); continue;
31 | }
32 | op = body.call(thisArg, _);
33 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35 | }
36 | };
37 | Object.defineProperty(exports, "__esModule", { value: true });
38 | var createRawFileFromEntries_1 = require("./createRawFileFromEntries");
39 | var writeClassFile_1 = require("../../writeClassFile");
40 | var makeHeaders_1 = require("./makeHeaders");
41 | var queryServer_1 = require("./queryServer");
42 | function ask(_a) {
43 | var input = _a.input, errorField = _a.errorField, headers = _a.headers, outputFilePath = _a.outputFilePath;
44 | return __awaiter(this, void 0, void 0, function () {
45 | var urlRegex, errorEntries, rawFileContent;
46 | return __generator(this, function (_b) {
47 | switch (_b.label) {
48 | case 0:
49 | urlRegex = /^https?:\/\//i;
50 | errorEntries = [];
51 | if (!urlRegex.test(input)) return [3 /*break*/, 2];
52 | return [4 /*yield*/, queryServer_1.default(input, errorField, makeHeaders_1.makeHeaders(headers))];
53 | case 1:
54 | errorEntries = _b.sent();
55 | _b.label = 2;
56 | case 2:
57 | rawFileContent = createRawFileFromEntries_1.default(errorEntries);
58 | return [2 /*return*/, writeClassFile_1.default(rawFileContent, outputFilePath)];
59 | }
60 | });
61 | });
62 | }
63 | exports.default = ask;
64 | //# sourceMappingURL=ask.js.map
--------------------------------------------------------------------------------
/lib/commands/ask/ask.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../../src/commands/ask/ask.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uEAA+D;AAC/D,uDAAkD;AAElD,6CAA4C;AAC5C,6CAAwC;AASxC,aAAkC,EAAuD;QAArD,gBAAK,EAAE,0BAAU,EAAE,oBAAO,EAAE,kCAAc;;;;;;oBACtE,QAAQ,GAAG,eAAe,CAAC;oBAE7B,YAAY,GAAuB,EAAE,CAAA;yBACrC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAApB,wBAAoB;oBACP,qBAAM,qBAAW,CAAC,KAAK,EAAE,UAAU,EAAE,yBAAW,CAAC,OAAO,CAAC,CAAC,EAAA;;oBAAzE,YAAY,GAAG,SAA0D,CAAC;;;oBAEtE,cAAc,GAAG,kCAAqB,CAAC,YAAY,CAAC,CAAC;oBAC3D,sBAAO,wBAAc,CAAC,cAAc,EAAE,cAAc,CAAC,EAAC;;;;CACvD;AATD,sBASC"}
--------------------------------------------------------------------------------
/lib/commands/ask/createRawFileFromEntries.d.ts:
--------------------------------------------------------------------------------
1 | import { ErrorOutputEntry } from "../../types";
2 | export default function (entries: ErrorOutputEntry[]): string;
3 |
--------------------------------------------------------------------------------
/lib/commands/ask/createRawFileFromEntries.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var types_1 = require("../../types");
4 | var TopMostImportsAndConfigDef = "/* tslint:disable */ \nimport { ApolloError } from \"apollo-client\";\nimport { GraphQLError } from \"graphql\";";
5 | var PropheticErrorCodeEnumDef = "\nexport enum PropheticErrorCode {\n CodeLessError = 'NONE',\n _VALUES_\n}";
6 | var PropheticErrorDef = "\nexport class PropheticError {\n constructor(public codes: string[]){}\n\n private inCodes(code: PropheticErrorCode){ return this.codes.indexOf(code) > -1; }\n\n get isCodeLessError() { return this.inCodes(PropheticErrorCode.CodeLessError); }\n _FUNCTIONS_\n}";
7 | var PropheticErrorGetterDef = "get is$_ENUM_$() { return this.inCodes(PropheticErrorCode.$_ENUM_$); }";
8 | var PropheticErrorHandledDef = "\nexport interface Handler {\n (): any\n}\n\nexport class PropheticErrorHandled {\n private handler: Handler = () => {}\n\n constructor(public codes: string[]){}\n\n private inCodes(code: PropheticErrorCode, handler: Handler){\n if(this.codes.indexOf(code) > -1){\n this.handler = handler\n }\n\n return this;\n }\n\n CodeLessError(handler: Handler) { return this.inCodes(PropheticErrorCode.CodeLessError, handler); }\n _FUNCTIONS_\n handle() { return this.handler(); }\n}";
9 | var PropheticErrorHandlerDef = "$_ENUM_$(handler: Handler) { return this.inCodes(PropheticErrorCode.$_ENUM_$, handler); }";
10 | var BottomExportedMethods = "\nconst CODE_LESS_EXTENSION = { code: 'NONE'};\nconst findCodes = (error: ApolloError | GraphQLError): PropheticErrorCode[] => {\n if(error instanceof ApolloError) {\n return error.graphQLErrors.map((gError) => findCodes(gError)[0]);\n } else if(error.extensions) {\n const { extensions: { code } = CODE_LESS_EXTENSION } = error;\n return [code];\n }\n\n return [PropheticErrorCode.CodeLessError];\n}\n\nexport const errorHere = (error: ApolloError | GraphQLError | undefined ) => {\n if(!error) {\n return new PropheticError([]);\n }\n const codes = findCodes(error);\n return new PropheticError(codes);\n}\n\nexport const isThis = (error: ApolloError | GraphQLError | undefined) => {\n if(!error) {\n return new PropheticErrorHandled([]);\n }\n const codes = findCodes(error);\n return new PropheticErrorHandled(codes);\n}";
11 | var toNameAndCodeTupleArray = function (entriesArray) {
12 | var entries = types_1.toErrorEntries(entriesArray);
13 | return Object.keys(entries).map(function (key) {
14 | var _a = entries[key].extensions, extensions = _a === void 0 ? { code: undefined } : _a;
15 | return [key, extensions.code];
16 | }).filter(function (_a) {
17 | var _ = _a[0], code = _a[1];
18 | return code !== undefined;
19 | });
20 | };
21 | function default_1(entries) {
22 | var nameAndCodeTuples = toNameAndCodeTupleArray(entries);
23 | var enums = nameAndCodeTuples.map(function (_a) {
24 | var name = _a[0], code = _a[1];
25 | return name + " = \"" + code + "\"";
26 | }).join(',\n ');
27 | var errorDefFun = nameAndCodeTuples.map(function (_a) {
28 | var name = _a[0];
29 | return "" + PropheticErrorGetterDef.replace("$_ENUM_$", name).replace("$_ENUM_$", name);
30 | }).join('\n ');
31 | var errorHandledFun = nameAndCodeTuples.map(function (_a) {
32 | var name = _a[0];
33 | return "" + PropheticErrorHandlerDef.replace("$_ENUM_$", name).replace("$_ENUM_$", name);
34 | }).join('\n ');
35 | return TopMostImportsAndConfigDef + "\n " + PropheticErrorCodeEnumDef.replace('_VALUES_', enums) + "\n " + PropheticErrorDef.replace('_FUNCTIONS_', errorDefFun) + "\n " + PropheticErrorHandledDef.replace('_FUNCTIONS_', errorHandledFun) + "\n " + BottomExportedMethods;
36 | }
37 | exports.default = default_1;
38 | //# sourceMappingURL=createRawFileFromEntries.js.map
--------------------------------------------------------------------------------
/lib/commands/ask/createRawFileFromEntries.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"createRawFileFromEntries.js","sourceRoot":"","sources":["../../../src/commands/ask/createRawFileFromEntries.ts"],"names":[],"mappings":";;AAAA,qCAAwF;AAExF,IAAM,0BAA0B,GAAG,kHAEK,CAAA;AAExC,IAAM,yBAAyB,GAAG,8EAIhC,CAAC;AAEH,IAAM,iBAAiB,GAAG,0QAQxB,CAAC;AAEH,IAAM,uBAAuB,GAAG,wEAAwE,CAAC;AAEzG,IAAM,wBAAwB,GAAG,gfAqB/B,CAAA;AACF,IAAM,wBAAwB,GAAG,2FAA2F,CAAC;AAE7H,IAAM,qBAAqB,GAAG,q1BA2B5B,CAAA;AAEF,IAAM,uBAAuB,GAAG,UAAC,YAAgC;IAC/D,IAAM,OAAO,GAAG,sBAAc,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,GAAG;QAC1B,IAAA,4BAAgC,EAAhC,qDAAgC,CAAkB;QAC1D,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAqB,CAAA;IACnD,CAAC,CAAC,CAAC,MAAM,CAAC,UAAC,EAAS;YAAR,SAAC,EAAE,YAAI;QAAM,OAAA,IAAI,KAAK,SAAS;IAAlB,CAAkB,CAAC,CAAC;AAC/C,CAAC,CAAA;AAED,mBAAwB,OAA2B;IACjD,IAAM,iBAAiB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAC,EAAY;YAAX,YAAI,EAAE,YAAI;QAAM,OAAG,IAAI,aAAO,IAAI,OAAG;IAArB,CAAqB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE3F,IAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAC,EAAM;YAAL,YAAI;QAC9C,OAAO,KAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAG,CAAC;IAC1F,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,IAAM,eAAe,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAC,EAAM;YAAL,YAAI;QAClD,OAAO,KAAG,wBAAwB,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAG,CAAC;IAC3F,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAU,0BAA0B,YAClC,yBAAyB,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,YACpD,iBAAiB,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,YACrD,wBAAwB,CAAC,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,YAChE,qBAAuB,CAAC;AAC5B,CAAC;AAjBD,4BAiBC"}
--------------------------------------------------------------------------------
/lib/commands/ask/index.d.ts:
--------------------------------------------------------------------------------
1 | export { default as ask } from "./ask";
2 |
--------------------------------------------------------------------------------
/lib/commands/ask/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var ask_1 = require("./ask");
4 | exports.ask = ask_1.default;
5 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/commands/ask/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/ask/index.ts"],"names":[],"mappings":";;AAAA,6BAAuC;AAA9B,oBAAA,OAAO,CAAO"}
--------------------------------------------------------------------------------
/lib/commands/ask/makeHeaders.d.ts:
--------------------------------------------------------------------------------
1 | export declare const makeHeaders: (headers?: string[]) => {};
2 |
--------------------------------------------------------------------------------
/lib/commands/ask/makeHeaders.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | // https://github.com/apollographql/apollo-codegen/blob/master/packages/apollo-codegen/src/cli.ts
4 | exports.makeHeaders = function (headers) {
5 | if (headers === void 0) { headers = []; }
6 | var additionalHeaders = {};
7 | for (var _i = 0, headers_1 = headers; _i < headers_1.length; _i++) {
8 | var header = headers_1[_i];
9 | var separator = header.indexOf(":");
10 | var name_1 = header.substring(0, separator).trim();
11 | var value = header.substring(separator + 1).trim();
12 | if (!(name_1 && value)) {
13 | throw new Error('Headers should be specified as "Name: Value"');
14 | }
15 | additionalHeaders[name_1] = value;
16 | }
17 | return additionalHeaders;
18 | };
19 | //# sourceMappingURL=makeHeaders.js.map
--------------------------------------------------------------------------------
/lib/commands/ask/makeHeaders.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"makeHeaders.js","sourceRoot":"","sources":["../../../src/commands/ask/makeHeaders.ts"],"names":[],"mappings":";;AAAA,iGAAiG;AACpF,QAAA,WAAW,GAAG,UAAC,OAAsB;IAAtB,wBAAA,EAAA,YAAsB;IAChD,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAC3B,KAAqB,UAAO,EAAP,mBAAO,EAAP,qBAAO,EAAP,IAAO,EAAE;QAAzB,IAAM,MAAM,gBAAA;QACf,IAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACtC,IAAM,MAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,IAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrD,IAAI,CAAC,CAAC,MAAI,IAAI,KAAK,CAAC,EAAE;YACpB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;SACjE;QACD,iBAAiB,CAAC,MAAI,CAAC,GAAG,KAAK,CAAC;KACjC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC,CAAA"}
--------------------------------------------------------------------------------
/lib/commands/ask/queryServer.d.ts:
--------------------------------------------------------------------------------
1 | import { ErrorOutputEntry } from '../../types';
2 | declare type Headers = {
3 | [name: string]: string;
4 | };
5 | export default function (serverUri: string, field: string, headers: Headers): Promise;
6 | export {};
7 |
--------------------------------------------------------------------------------
/lib/commands/ask/queryServer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
4 | return cooked;
5 | };
6 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7 | return new (P || (P = Promise))(function (resolve, reject) {
8 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
11 | step((generator = generator.apply(thisArg, _arguments || [])).next());
12 | });
13 | };
14 | var __generator = (this && this.__generator) || function (thisArg, body) {
15 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
16 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
17 | function verb(n) { return function (v) { return step([n, v]); }; }
18 | function step(op) {
19 | if (f) throw new TypeError("Generator is already executing.");
20 | while (_) try {
21 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
22 | if (y = 0, t) op = [0, t.value];
23 | switch (op[0]) {
24 | case 0: case 1: t = op; break;
25 | case 4: _.label++; return { value: op[1], done: false };
26 | case 5: _.label++; y = op[1]; op = [0]; continue;
27 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
28 | default:
29 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
30 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
31 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
32 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
33 | if (t[2]) _.ops.pop();
34 | _.trys.pop(); continue;
35 | }
36 | op = body.call(thisArg, _);
37 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
38 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
39 | }
40 | };
41 | Object.defineProperty(exports, "__esModule", { value: true });
42 | var graphql_tag_1 = require("graphql-tag");
43 | var node_fetch_1 = require("node-fetch");
44 | var apollo_link_1 = require("apollo-link");
45 | var apollo_link_http_1 = require("apollo-link-http");
46 | var makeOperation = function (erroType) { return ({
47 | query: graphql_tag_1.default(templateObject_1 || (templateObject_1 = __makeTemplateObject(["query {\n ", " {\n name\n message\n extensions {\n code\n }\n }\n }\n "], ["query {\n ", " {\n name\n message\n extensions {\n code\n }\n }\n }\n "])), erroType),
48 | }); };
49 | function exeuteServerQuery(serverUri, type, headers) {
50 | var operation = makeOperation(type);
51 | var link = new apollo_link_http_1.HttpLink({ uri: serverUri, fetch: node_fetch_1.default, headers: headers });
52 | return apollo_link_1.makePromise(apollo_link_1.execute(link, operation));
53 | }
54 | function default_1(serverUri, field, headers) {
55 | if (field === void 0) { field = 'errors'; }
56 | return __awaiter(this, void 0, void 0, function () {
57 | var result, e_1, errors;
58 | return __generator(this, function (_a) {
59 | switch (_a.label) {
60 | case 0:
61 | _a.trys.push([0, 2, , 3]);
62 | return [4 /*yield*/, exeuteServerQuery(serverUri, field, headers)];
63 | case 1:
64 | result = _a.sent();
65 | return [3 /*break*/, 3];
66 | case 2:
67 | e_1 = _a.sent();
68 | throw e_1;
69 | case 3:
70 | if (result.errors) {
71 | throw new Error("Errors occured querying \"" + field + "\": " + result.errors);
72 | }
73 | if (!result.data || !result.data[field]) {
74 | throw new Error("No Errors found to generate on query field " + field);
75 | }
76 | errors = result.data[field];
77 | return [2 /*return*/, errors];
78 | }
79 | });
80 | });
81 | }
82 | exports.default = default_1;
83 | var templateObject_1;
84 | //# sourceMappingURL=queryServer.js.map
--------------------------------------------------------------------------------
/lib/commands/ask/queryServer.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"queryServer.js","sourceRoot":"","sources":["../../../src/commands/ask/queryServer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA8B;AAC9B,yCAA+B;AAC/B,2CAAmD;AACnD,qDAA4C;AAG5C,IAAM,aAAa,GAAG,UAAC,QAAgB,IAAK,OAAA,CAAC;IAC3C,KAAK,EAAE,qBAAG,8KAAA,eACN,EAAQ,0FAQX,KARG,QAAQ,CAQX;CACF,CAAC,EAX0C,CAW1C,CAAC;AAIH,2BAA2B,SAAiB,EAAE,IAAY,EAAE,OAAgB;IAC1E,IAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACtC,IAAM,IAAI,GAAG,IAAI,2BAAQ,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,sBAAA,EAAE,OAAO,SAAA,EAAE,CAAC,CAAC;IAE9D,OAAO,yBAAW,CAAC,qBAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,mBAA8B,SAAiB,EAAE,KAAwB,EAAE,OAAgB;IAA1C,sBAAA,EAAA,gBAAwB;;;;;;;oBAG5D,qBAAM,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAA;;oBAA3D,MAAM,GAAG,SAAkD,CAAC;;;;oBAE5D,MAAM,GAAC,CAAC;;oBAGV,IAAI,MAAM,CAAC,MAAM,EAAE;wBACjB,MAAM,IAAI,KAAK,CAAC,+BAA4B,KAAK,YAAM,MAAM,CAAC,MAAQ,CAAC,CAAC;qBACzE;oBAED,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;wBACvC,MAAM,IAAI,KAAK,CAAC,gDAA8C,KAAO,CAAC,CAAC;qBACxE;oBAEK,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAClC,sBAAO,MAA4B,EAAC;;;;CACrC;AAlBD,4BAkBC"}
--------------------------------------------------------------------------------
/lib/commands/generate/checkEntries.d.ts:
--------------------------------------------------------------------------------
1 | import { JsonInputErrorEntryRecord } from '../../types';
2 | declare const _default: (inputEntries: JsonInputErrorEntryRecord) => JsonInputErrorEntryRecord;
3 | export default _default;
4 |
--------------------------------------------------------------------------------
/lib/commands/generate/checkEntries.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.default = (function (inputEntries) {
4 | var checks = Object.keys(inputEntries).map(function (key) {
5 | var entry = inputEntries[key];
6 | return { name: key, hasCodeKey: entry.code !== undefined };
7 | }).filter(function (_a) {
8 | var hasCodeKey = _a.hasCodeKey;
9 | return !hasCodeKey;
10 | });
11 | if (checks.length > 0) {
12 | var concernedNames = checks.map(function (_a) {
13 | var name = _a.name;
14 | return name;
15 | }).join();
16 | throw Error("[CodeKeyImperative] No \"code\" key found for: [" + concernedNames + "]");
17 | }
18 | return inputEntries;
19 | });
20 | //# sourceMappingURL=checkEntries.js.map
--------------------------------------------------------------------------------
/lib/commands/generate/checkEntries.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"checkEntries.js","sourceRoot":"","sources":["../../../src/commands/generate/checkEntries.ts"],"names":[],"mappings":";;AAEA,mBAAe,UAAC,YAAuC;IACrD,IAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,UAAA,GAAG;QAC9C,IAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAA;IAC5D,CAAC,CAAC,CAAC,MAAM,CAAC,UAAC,EAAc;YAAZ,0BAAU;QAAO,OAAA,CAAC,UAAU;IAAX,CAAW,CAAC,CAAC;IAE3C,IAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;QACpB,IAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,UAAC,EAAQ;gBAAN,cAAI;YAAO,OAAA,IAAI;QAAJ,CAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,MAAM,KAAK,CAAC,qDAAiD,cAAc,MAAG,CAAC,CAAC;KACjF;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,EAAA"}
--------------------------------------------------------------------------------
/lib/commands/generate/createError.d.ts:
--------------------------------------------------------------------------------
1 | export declare const PropheticErrorTextDef = "class PropheticError extends ApolloError {\n constructor(name: string, message: string, code?: string, properties?: Record) {\n super(message, code, properties);\n\n // Set the prototype explicitly.\n // https://stackoverflow.com/a/41102306\n Object.setPrototypeOf(this, SyntaxError.prototype);\n Object.defineProperty(this, 'name', { value: name });\n }\n}";
2 | export default function (name: string, message: string, code: string, properties?: Record): string;
3 |
--------------------------------------------------------------------------------
/lib/commands/generate/createError.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.PropheticErrorTextDef = "class PropheticError extends ApolloError {\n constructor(name: string, message: string, code?: string, properties?: Record) {\n super(message, code, properties);\n\n // Set the prototype explicitly.\n // https://stackoverflow.com/a/41102306\n Object.setPrototypeOf(this, SyntaxError.prototype);\n Object.defineProperty(this, 'name', { value: name });\n }\n}";
4 | function default_1(name, message, code, properties) {
5 | return "export class " + name + " extends PropheticError {\n constructor(properties?: Record) {\n super(\"" + name + "\", \"" + message + "\", \"" + code + "\", properties);\n }\n}";
6 | }
7 | exports.default = default_1;
8 | //# sourceMappingURL=createError.js.map
--------------------------------------------------------------------------------
/lib/commands/generate/createError.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"createError.js","sourceRoot":"","sources":["../../../src/commands/generate/createError.ts"],"names":[],"mappings":";;AAOa,QAAA,qBAAqB,GAAG,qYASnC,CAAA;AAEF,mBAAwB,IAAY,EAAE,OAAe,EAAE,IAAY,EAAE,UAAgC;IACnG,OAAO,kBAAgB,IAAI,kGAEhB,IAAI,cAAO,OAAO,cAAO,IAAI,6BAExC,CAAA;AACF,CAAC;AAND,4BAMC"}
--------------------------------------------------------------------------------
/lib/commands/generate/generate.d.ts:
--------------------------------------------------------------------------------
1 | export interface ProphecyArgs {
2 | intputFilePath: string;
3 | outputFilePath?: string;
4 | }
5 | export default function generate(args: ProphecyArgs): Promise;
6 |
--------------------------------------------------------------------------------
/lib/commands/generate/generate.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | var __generator = (this && this.__generator) || function (thisArg, body) {
11 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13 | function verb(n) { return function (v) { return step([n, v]); }; }
14 | function step(op) {
15 | if (f) throw new TypeError("Generator is already executing.");
16 | while (_) try {
17 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
18 | if (y = 0, t) op = [0, t.value];
19 | switch (op[0]) {
20 | case 0: case 1: t = op; break;
21 | case 4: _.label++; return { value: op[1], done: false };
22 | case 5: _.label++; y = op[1]; op = [0]; continue;
23 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
24 | default:
25 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29 | if (t[2]) _.ops.pop();
30 | _.trys.pop(); continue;
31 | }
32 | op = body.call(thisArg, _);
33 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35 | }
36 | };
37 | Object.defineProperty(exports, "__esModule", { value: true });
38 | var generateRawClass_1 = require("./generateRawClass");
39 | var writeClassFile_1 = require("../../writeClassFile");
40 | var checkEntries_1 = require("./checkEntries");
41 | var utils_1 = require("./../../utils");
42 | function generate(args) {
43 | return __awaiter(this, void 0, void 0, function () {
44 | var intputFilePath, outputFilePath, entries, rawClassContent;
45 | return __generator(this, function (_a) {
46 | intputFilePath = args.intputFilePath, outputFilePath = args.outputFilePath;
47 | entries = checkEntries_1.default(utils_1.fs.readJsonDef(intputFilePath));
48 | rawClassContent = generateRawClass_1.default(entries);
49 | return [2 /*return*/, writeClassFile_1.default(rawClassContent, outputFilePath)];
50 | });
51 | });
52 | }
53 | exports.default = generate;
54 | //# sourceMappingURL=generate.js.map
--------------------------------------------------------------------------------
/lib/commands/generate/generate.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/commands/generate/generate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uDAAkD;AAClD,uDAAkD;AAClD,+CAA0C;AAC1C,uCAAmC;AAOnC,kBAAuC,IAAkB;;;;YAC/C,cAAc,GAAsB,IAAI,eAA1B,EAAE,cAAc,GAAM,IAAI,eAAV,CAAW;YAC3C,OAAO,GAAG,sBAAY,CAAC,UAAE,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;YACvD,eAAe,GAAG,0BAAgB,CAAC,OAAO,CAAC,CAAC;YAClD,sBAAO,wBAAc,CAAC,eAAe,EAAE,cAAc,CAAC,EAAC;;;CACxD;AALD,2BAKC"}
--------------------------------------------------------------------------------
/lib/commands/generate/generateRawClass.d.ts:
--------------------------------------------------------------------------------
1 | import { JsonInputErrorEntryRecord, JsonInputErrorEntry } from '../../types';
2 | export declare type ScalarType = "Boolean" | "Int" | "Float" | "String";
3 | export declare type ScalarTypesMap = {
4 | [key: string]: ScalarType;
5 | };
6 | export declare function toRawClassesArray(entries: JsonInputErrorEntryRecord): string[];
7 | export declare const exludeMessageAndName: (entry: JsonInputErrorEntry) => string[];
8 | export declare function toScalarTypesMap(entries: JsonInputErrorEntryRecord): ScalarTypesMap[];
9 | export declare function generatePropheticErrorType(typesArray: ScalarTypesMap[]): string;
10 | export default function (entries: JsonInputErrorEntryRecord): string;
11 |
--------------------------------------------------------------------------------
/lib/commands/generate/generateRawClass.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __rest = (this && this.__rest) || function (s, e) {
3 | var t = {};
4 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5 | t[p] = s[p];
6 | if (s != null && typeof Object.getOwnPropertySymbols === "function")
7 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
8 | t[p[i]] = s[p[i]];
9 | return t;
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | var createError_1 = require("./createError");
13 | var types_1 = require("../../types");
14 | function scalarGQLTpeFromValue(value) {
15 | switch (typeof value) {
16 | case "string":
17 | return "String";
18 | case "boolean":
19 | return "Boolean";
20 | case "number":
21 | if (value % 1 === 0) {
22 | return "Int";
23 | }
24 | else {
25 | return "Float";
26 | }
27 | default:
28 | return null;
29 | }
30 | }
31 | function toRawClassesArray(entries) {
32 | return Object.keys(entries).map(function (key) {
33 | var _a = entries[key], message = _a.message, code = _a.code, rest = __rest(_a, ["message", "code"]);
34 | return createError_1.default(key, message, code, rest);
35 | });
36 | }
37 | exports.toRawClassesArray = toRawClassesArray;
38 | exports.exludeMessageAndName = function (entry) { return Object.keys(entry).filter(function (key) { return key !== 'message' || 'name'; }); };
39 | function toScalarTypesMap(entries) {
40 | return Object.values(entries).map(function (entry) { return Object.keys(entry).filter(function (key) { return key !== 'message'; }).reduce(function (prev, entryFieldKey) {
41 | var fieldValue = entry[entryFieldKey];
42 | var fieldType = scalarGQLTpeFromValue(fieldValue);
43 | prev[entryFieldKey] = fieldType;
44 | return prev;
45 | }, {}); }, {});
46 | }
47 | exports.toScalarTypesMap = toScalarTypesMap;
48 | function generatePropheticErrorType(typesArray) {
49 | var fieldsReduced = typesArray.filter(function (type) { return type; }).reduce(function (prev, typesMap) {
50 | var isFirst = prev === {};
51 | for (var key in typesMap) {
52 | var fieldType = typesMap[key];
53 | var isNullableType = true;
54 | if (!isFirst && prev[key] && prev[key].isNullableType) {
55 | if (prev[key].isNullableType !== true) {
56 | prev[key].isNullableType = prev[key].isNullableType;
57 | }
58 | else {
59 | prev[key].isNullableType = false;
60 | }
61 | }
62 | var value = { type: fieldType, isNullableType: isNullableType };
63 | prev[key] = value;
64 | }
65 | return prev;
66 | }, {});
67 | var fields = Object.entries(fieldsReduced).map(function (_a) {
68 | var name = _a[0], _b = _a[1], type = _b.type, isNullableType = _b.isNullableType;
69 | return name + ": " + type + (isNullableType ? '?' : '');
70 | });
71 | return "\n type PropheticErrorExtensions {\n " + fields.join('\n ') + "\n }\n \n type PropheticError {\n name: String\n message: String?\n extensions: PropheticErrorExtensions\n }\n ";
72 | }
73 | exports.generatePropheticErrorType = generatePropheticErrorType;
74 | function default_1(entries) {
75 | var rawErrorClasses = toRawClassesArray(entries).join('\n');
76 | var fieldsTypesMapArray = toScalarTypesMap(entries);
77 | var rawPropheticErrorAndExtensionsType = generatePropheticErrorType(fieldsTypesMapArray);
78 | var errorsList = types_1.toOutputErrors(entries);
79 | var classFile = "\n import { ApolloError } from 'apollo-server'\n\n export const errorsList = " + JSON.stringify(errorsList, null, 2) + ";\n export const errorType = `" + rawPropheticErrorAndExtensionsType + "`;\n \n " + createError_1.PropheticErrorTextDef + "\n \n " + rawErrorClasses + "\n ";
80 | return classFile;
81 | }
82 | exports.default = default_1;
83 | //# sourceMappingURL=generateRawClass.js.map
--------------------------------------------------------------------------------
/lib/commands/generate/generateRawClass.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"generateRawClass.js","sourceRoot":"","sources":["../../../src/commands/generate/generateRawClass.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,6CAAkE;AAClE,qCAA6F;AAK7F,+BAA+B,KAAU;IACvC,QAAQ,OAAO,KAAK,EAAE;QACpB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAA;QACjB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAA;QAClB,KAAK,QAAQ;YACX,IAAG,KAAK,GAAG,CAAC,KAAK,CAAC,EAAC;gBACjB,OAAO,KAAK,CAAA;aACb;iBAAM;gBACL,OAAO,OAAO,CAAA;aACf;QACH;YACE,OAAO,IAAI,CAAC;KACf;AACH,CAAC;AAED,2BAAkC,OAAkC;IAClE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,GAAG;QAClC,IAAM,iBAAyC,EAAvC,oBAAO,EAAE,cAAI,EAAE,sCAAwB,CAAC;QAChD,OAAO,qBAAW,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC;AALD,8CAKC;AAEY,QAAA,oBAAoB,GAAG,UAAC,KAA0B,IAAK,OAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAA,GAAG,IAAI,OAAA,GAAG,KAAK,SAAS,IAAI,MAAM,EAA3B,CAA2B,CAAC,EAA7D,CAA6D,CAAA;AACjI,0BAAiC,OAAkC;IACjE,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,KAAK,IAAK,OAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAA,GAAG,IAAI,OAAA,GAAG,KAAK,SAAS,EAAjB,CAAiB,CAAC,CAAC,MAAM,CAAC,UAAC,IAAI,EAAE,aAAa;QAC1H,IAAM,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC;QACxC,IAAM,SAAS,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,EAAE,CAAC,EALuC,CAKvC,EAAC,EAAE,CAAC,CAAC;AACb,CAAC;AAPD,4CAOC;AAKD,oCAA2C,UAA4B;IACrE,IAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,UAAA,IAAI,IAAI,OAAA,IAAI,EAAJ,CAAI,CAAC,CAAC,MAAM,CAAC,UAAC,IAAwB,EAAE,QAAQ;QAC9F,IAAM,OAAO,GAAG,IAAI,KAAK,EAAE,CAAA;QAE3B,KAAK,IAAI,GAAG,IAAI,QAAQ,EAAE;YACxB,IAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,cAAc,GAAG,IAAI,CAAC;YAC1B,IAAG,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE;gBACpD,IAAG,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,KAAK,IAAI,EAAE;oBACpC,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC;iBACrD;qBAAK;oBACJ,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,GAAG,KAAK,CAAA;iBACjC;aACF;YAED,IAAM,KAAK,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,gBAAA,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;SACnB;QACD,OAAO,IAAI,CAAC;IACd,CAAC,EAAC,EAAE,CAAuB,CAAA;IAG3B,IAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,UAAC,EAAiC;YAAhC,YAAI,EAAE,UAAwB,EAAtB,cAAI,EAAE,kCAAc;QAC7E,OAAU,IAAI,UAAK,IAAI,IAAG,cAAc,CAAC,CAAC,CAAC,GAAG,CAAA,CAAC,CAAC,EAAE,CAAE,CAAA;IACtD,CAAC,CAAC,CAAC;IAEH,OAAO,kDAED,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,gJAQ5B,CAAA;AACH,CAAC;AArCD,gEAqCC;AAED,mBAAyB,OAAkC;IACzD,IAAM,eAAe,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAM,mBAAmB,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtD,IAAM,kCAAkC,GAAG,0BAA0B,CAAC,mBAAmB,CAAC,CAAC;IAC3F,IAAM,UAAU,GAAG,sBAAc,CAAC,OAAO,CAAC,CAAC;IAE3C,IAAM,SAAS,GAAG,oFAGU,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,uCAClC,kCAAkC,kBAE7D,mCAAqB,gBAErB,eAAe,SAChB,CAAA;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAjBD,4BAiBC"}
--------------------------------------------------------------------------------
/lib/commands/generate/index.d.ts:
--------------------------------------------------------------------------------
1 | export { default as generate } from "./generate";
2 |
--------------------------------------------------------------------------------
/lib/commands/generate/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var generate_1 = require("./generate");
4 | exports.generate = generate_1.default;
5 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/commands/generate/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/generate/index.ts"],"names":[],"mappings":";;AAAA,uCAAiD;AAAxC,8BAAA,OAAO,CAAY"}
--------------------------------------------------------------------------------
/lib/commands/index.d.ts:
--------------------------------------------------------------------------------
1 | export { generate } from './generate';
2 | export { ask } from './ask';
3 |
--------------------------------------------------------------------------------
/lib/commands/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var generate_1 = require("./generate");
4 | exports.generate = generate_1.generate;
5 | var ask_1 = require("./ask");
6 | exports.ask = ask_1.ask;
7 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/commands/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";;AAAA,uCAAqC;AAA5B,8BAAA,QAAQ,CAAA;AACjB,6BAA2B;AAAlB,oBAAA,GAAG,CAAA"}
--------------------------------------------------------------------------------
/lib/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as commands from './commands';
2 | import * as utils from './utils';
3 | import * as types from './types';
4 | export { commands, utils, types };
5 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var commands = require("./commands");
4 | exports.commands = commands;
5 | var utils = require("./utils");
6 | exports.utils = utils;
7 | var types = require("./types");
8 | exports.types = types;
9 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,qCAAuC;AAI9B,4BAAQ;AAHjB,+BAAiC;AAGd,sBAAK;AAFxB,+BAAiC;AAEP,sBAAK"}
--------------------------------------------------------------------------------
/lib/types.d.ts:
--------------------------------------------------------------------------------
1 | export declare type JsonInputErrorEntry = {
2 | message: string;
3 | code: string;
4 | [key: string]: any;
5 | };
6 | export declare type ErrorOutputEntry = {
7 | name: string;
8 | message?: string;
9 | extensions: {
10 | code: string;
11 | [key: string]: any;
12 | };
13 | };
14 | export declare type JsonInputErrorEntryRecord = {
15 | [key: string]: JsonInputErrorEntry;
16 | };
17 | export declare type JsonOutputEntriesRecord = {
18 | [key: string]: ErrorOutputEntry;
19 | };
20 | export declare function toErrorEntries(entries: ErrorOutputEntry[]): JsonOutputEntriesRecord;
21 | export declare function toOutputErrors(entries: JsonInputErrorEntryRecord): ErrorOutputEntry[];
22 |
--------------------------------------------------------------------------------
/lib/types.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __assign = (this && this.__assign) || Object.assign || function(t) {
3 | for (var s, i = 1, n = arguments.length; i < n; i++) {
4 | s = arguments[i];
5 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6 | t[p] = s[p];
7 | }
8 | return t;
9 | };
10 | var __rest = (this && this.__rest) || function (s, e) {
11 | var t = {};
12 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13 | t[p] = s[p];
14 | if (s != null && typeof Object.getOwnPropertySymbols === "function")
15 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
16 | t[p[i]] = s[p[i]];
17 | return t;
18 | };
19 | Object.defineProperty(exports, "__esModule", { value: true });
20 | function toErrorEntries(entries) {
21 | return entries.reduce(function (map, entry) {
22 | map[entry.name] = entry;
23 | return map;
24 | }, {});
25 | }
26 | exports.toErrorEntries = toErrorEntries;
27 | function toOutputErrors(entries) {
28 | return Object.keys(entries).map(function (key) {
29 | var _a = entries[key], name = _a.name, message = _a.message, code = _a.code, rest = __rest(_a, ["name", "message", "code"]);
30 | return {
31 | name: name || key,
32 | message: message,
33 | extensions: __assign({ code: code }, rest)
34 | };
35 | });
36 | }
37 | exports.toOutputErrors = toOutputErrors;
38 | //# sourceMappingURL=types.js.map
--------------------------------------------------------------------------------
/lib/types.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,wBAA+B,OAA2B;IACxD,OAAO,OAAO,CAAC,MAAM,CAAC,UAAC,GAAG,EAAE,KAAK;QAC/B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACxB,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAA6B,CAAC,CAAC;AACpC,CAAC;AALD,wCAKC;AAED,wBAA+B,OAAkC;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,GAAG;QAClC,IAAM,iBAA+C,EAA7C,cAAI,EAAE,oBAAO,EAAE,cAAI,EAAE,8CAAwB,CAAC;QACtD,OAAO;YACL,IAAI,EAAE,IAAI,IAAI,GAAG;YACjB,OAAO,EAAE,OAAO;YAChB,UAAU,aACR,IAAI,MAAA,IACD,IAAI,CACR;SACkB,CAAA;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAZD,wCAYC"}
--------------------------------------------------------------------------------
/lib/utils/fs-prophecy.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import * as fs from 'fs';
3 | import * as jsonfile from 'jsonfile';
4 | import { JsonInputErrorEntry } from '../types';
5 | export declare const writeFile: (path: fs.PathLike, content: string) => void;
6 | export declare const mkdirs: (path: fs.PathLike) => any;
7 | export declare const rmrf: (path: fs.PathLike) => any;
8 | export declare function readJsonDef(filePath: jsonfile.Path): JsonInputErrorEntry;
9 |
--------------------------------------------------------------------------------
/lib/utils/fs-prophecy.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var fs = require("fs");
4 | var rimraf = require("rimraf");
5 | var mkdirp = require("mkdirp");
6 | var jsonfile = require("jsonfile");
7 | exports.writeFile = function (path, content) { return fs.writeFileSync(path, content); };
8 | exports.mkdirs = function (path) { return mkdirp.sync(path); };
9 | exports.rmrf = function (path) { return rimraf.sync(path); };
10 | function readJsonDef(filePath) {
11 | return jsonfile.readFileSync(filePath);
12 | }
13 | exports.readJsonDef = readJsonDef;
14 | //# sourceMappingURL=fs-prophecy.js.map
--------------------------------------------------------------------------------
/lib/utils/fs-prophecy.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"fs-prophecy.js","sourceRoot":"","sources":["../../src/utils/fs-prophecy.ts"],"names":[],"mappings":";;AAAA,uBAAyB;AACzB,+BAAiC;AACjC,+BAAiC;AACjC,mCAAqC;AAGxB,QAAA,SAAS,GAAG,UAAC,IAAkB,EAAE,OAAe,IAAK,OAAA,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAA/B,CAA+B,CAAC;AACrF,QAAA,MAAM,GAAG,UAAC,IAAiB,IAAK,OAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAjB,CAAiB,CAAC;AAClD,QAAA,IAAI,GAAG,UAAC,IAAiB,IAAK,OAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAjB,CAAiB,CAAC;AAC7D,qBAA4B,QAAuB;IACjD,OAAO,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAwB,CAAC;AAChE,CAAC;AAFD,kCAEC"}
--------------------------------------------------------------------------------
/lib/utils/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as fs from './fs-prophecy';
2 | export { fs };
3 |
--------------------------------------------------------------------------------
/lib/utils/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var fs = require("./fs-prophecy");
4 | exports.fs = fs;
5 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/utils/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;AAAA,kCAAoC;AAGlC,gBAAE"}
--------------------------------------------------------------------------------
/lib/writeClassFile.d.ts:
--------------------------------------------------------------------------------
1 | declare const _default: (content: string, output?: string) => string;
2 | export default _default;
3 |
--------------------------------------------------------------------------------
/lib/writeClassFile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var path_1 = require("path");
4 | var utils_1 = require("./utils");
5 | exports.default = (function (content, output) {
6 | if (output === void 0) { output = '_generated'; }
7 | var outputPath = path_1.normalize(output);
8 | var fileExtension = path_1.parse(outputPath).ext;
9 | var fileSpecified = (fileExtension !== null && fileExtension !== undefined) && fileExtension.length > 0;
10 | var fileIsTS = fileExtension === '.ts';
11 | if (fileSpecified && !fileIsTS) {
12 | throw new Error('.ts file expected as output');
13 | }
14 | var outputFile = fileSpecified ? path_1.parse(outputPath).base : 'Errors.ts';
15 | var outputDirectory = fileSpecified ? path_1.parse(outputPath).dir : outputPath;
16 | utils_1.fs.mkdirs(outputDirectory);
17 | var outputFilePath = path_1.normalize(outputDirectory + "/" + outputFile);
18 | utils_1.fs.writeFile(outputFilePath, content);
19 | return outputFilePath;
20 | });
21 | //# sourceMappingURL=writeClassFile.js.map
--------------------------------------------------------------------------------
/lib/writeClassFile.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"writeClassFile.js","sourceRoot":"","sources":["../src/writeClassFile.ts"],"names":[],"mappings":";;AAAA,6BAAyC;AACzC,iCAA6B;AAE7B,mBAAe,UAAC,OAAe,EAAE,MAA6B;IAA7B,uBAAA,EAAA,qBAA6B;IAC5D,IAAM,UAAU,GAAG,gBAAS,CAAC,MAAM,CAAC,CAAC;IACrC,IAAM,aAAa,GAAG,YAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC;IAC5C,IAAM,aAAa,GAAG,CAAC,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,SAAS,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1G,IAAM,QAAQ,GAAG,aAAa,KAAK,KAAK,CAAC;IAEzC,IAAG,aAAa,IAAI,CAAC,QAAQ,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;KAChD;IAED,IAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,YAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;IACxE,IAAM,eAAe,GAAG,aAAa,CAAC,CAAC,CAAC,YAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;IAE3E,UAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAE3B,IAAM,cAAc,GAAG,gBAAS,CAAI,eAAe,SAAI,UAAY,CAAC,CAAC;IACrE,UAAE,CAAC,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAEtC,OAAO,cAAc,CAAC;AACxB,CAAC,EAAA"}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "apollo-prophecy",
3 | "version": "0.2.3-0",
4 | "description": "Generate Spec compliant and shareable errors for Apollo Client/Server from JSON or Graphql Schema",
5 | "main": "./lib/index.js",
6 | "bin": "./lib/cli.js",
7 | "scripts": {
8 | "test": "jest --collectCoverage",
9 | "test:watch": "jest --watch --runInBand --detectOpenHandles --coverage --env=node",
10 | "coverage": "jest --collectCoverage && cat ./coverage/lcov.info | coveralls",
11 | "build": "rm -rf lib && tsc",
12 | "cli": "ts-node src/cli.ts",
13 | "preversion": "npm test",
14 | "version": "npm run build && git add -A lib",
15 | "postversion": "git push && git push --tags && rm -rf lib",
16 | "patch-release": "npm version patch && npm publish && git push --follow-tags",
17 | "prepatch-release": "npm version prepatch && npm publish && git push --follow-tags"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/theGlenn/apollo-pythian.git"
22 | },
23 | "keywords": [
24 | "apollo",
25 | "graphql",
26 | "errors",
27 | "apollo-client",
28 | "apollo-server"
29 | ],
30 | "author": "Glenn Sonna",
31 | "license": "MIT",
32 | "bugs": {
33 | "url": "https://github.com/theGlenn/apollo-pythian/issues"
34 | },
35 | "homepage": "https://github.com/theGlenn/apollo-pythian#readme",
36 | "dependencies": {
37 | "@types/rimraf": "^3.0.0",
38 | "apollo-link": "^1.2.2",
39 | "apollo-link-http": "^1.5.4",
40 | "apollo-server": "^2.0.0-beta.5",
41 | "graphql": "^15.3.0",
42 | "graphql-tag": "^2.9.2",
43 | "jsonfile": "^4.0.0",
44 | "mkdirp": "^1.0.4",
45 | "node-fetch": "^2.1.2",
46 | "rimraf": "^2.6.2",
47 | "yargs": "^11.0.0"
48 | },
49 | "devDependencies": {
50 | "@types/chai": "^4.1.3",
51 | "@types/chai-fs": "^2.0.2",
52 | "@types/express": "^4.16.0",
53 | "@types/graphql": "^0.13.1",
54 | "@types/jest": "^24.0.21",
55 | "@types/jsonfile": "^4.0.1",
56 | "@types/minimist": "^1.2.0",
57 | "@types/mkdirp": "^1.0.1",
58 | "@types/mocha": "^5.2.0",
59 | "@types/node": "^10.3.0",
60 | "@types/yargs": "^11.0.0",
61 | "@typescript-eslint/eslint-plugin": "^4.5.0",
62 | "@typescript-eslint/parser": "^4.5.0",
63 | "chai": "^4.1.2",
64 | "chai-fs": "^2.0.0",
65 | "coveralls": "^3.1.0",
66 | "eslint": "^7.12.0",
67 | "eslint-config-airbnb-typescript": "^12.0.0",
68 | "jest": "^24.9.0",
69 | "source-map-support": "^0.5.6",
70 | "ts-jest": "^24.1.0",
71 | "ts-node": "^8.3.0",
72 | "typescript": "^3.7.5"
73 | },
74 | "resolutions": {
75 | "**@types/mocha": "^5.2.0",
76 | "**@types/express": "^4.16.3"
77 | },
78 | "nyc": {
79 | "extension": [
80 | ".ts",
81 | ".tsx"
82 | ],
83 | "exclude": [
84 | "lib",
85 | "**/*.d.ts",
86 | "coverage"
87 | ],
88 | "reporter": [
89 | "html"
90 | ],
91 | "all": true
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/_specs-utils/index.ts:
--------------------------------------------------------------------------------
1 | import * as os from 'os';
2 | import * as osFs from 'fs';
3 | import * as path from 'path';
4 |
5 | export const mkdirTmp = () => {
6 | const tmpDir = os.tmpdir();
7 | const dirLocation = path.join(tmpDir, 'apollo-prophetic-test-');
8 | return osFs.mkdtempSync(dirLocation);
9 | };
10 |
11 | export const tmpErrorFilePath = (fileName: string) => path.join(mkdirTmp(), fileName);
12 | export const removeWhiteSpaces = (text: string) => text.replace(/[^a-zA-Z]/g, "");
13 |
14 | export const entries = {
15 | UnknownError: {
16 | "message": "An unknown error has occurred! Please try again later",
17 | "code": "UNKNOWN"
18 | },
19 | ForbiddenError: {
20 | "message": "You are not allowed to do this",
21 | "code": "FORBIDDEN",
22 | },
23 | };
24 |
25 | export * as jestFS from './jest-fs';
--------------------------------------------------------------------------------
/src/_specs-utils/jest-fs.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 |
3 | declare global {
4 | namespace jest {
5 | interface Matchers {
6 | toBePath(): R;
7 | toBeDirectory(): R;
8 | toBeDirectoryWithFiles(files: string[]): R;
9 | }
10 | }
11 | }
12 |
13 | expect.extend({
14 | toBePath(received) {
15 | const pass = fs.existsSync(received);
16 | const failMessage = this.isNot
17 | ? "expected #{this} not to exist"
18 | : "expected #{this} to exist";
19 |
20 | const message = pass ? "" : failMessage;
21 | return { pass, actual: received, message: () => message };
22 | },
23 |
24 | toBeDirectory(received) {
25 | expect(received).toEqual(expect.any(String));
26 | expect(received).toBePath();
27 |
28 | const pass = fs.statSync(received).isDirectory();
29 | const failMessage = this.isNot
30 | ? "Expected Not: to be directory"
31 | : "Expected: to be directory";
32 |
33 | const message = pass ? "good" : failMessage;
34 | return { pass, actual: received, message: () => message };
35 | },
36 |
37 | toBeDirectoryWithFiles(received, actual) {
38 | expect(received).toBeDirectory();
39 |
40 | const files = fs.readdirSync(received);
41 | expect(files).toEqual(expect.arrayContaining(actual));
42 | return { pass: true, actual: received, message: () => "good" };
43 | },
44 | });
45 |
--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | import * as yargs from 'yargs';
3 | import { ParsedArgs } from 'minimist';
4 | import { commands } from './';
5 | import { resolve } from 'path';
6 |
7 | function handleError(error) {
8 | console.error(error);
9 | process.exit(1);
10 | }
11 |
12 | process.on('unhandledRejection', (error) => { throw error });
13 | process.on('uncaughtException', handleError);
14 |
15 | interface Args extends ParsedArgs {
16 | jsonFile?: string
17 |
18 | out?: string
19 | field?: string
20 | headers?: string
21 | };
22 |
23 | yargs
24 | .command(
25 | ['generate [jsonFile]', 'prophecy'],
26 | 'Generate a Typescript file containg all application errors from a JSON input',
27 | {
28 | out: {
29 | demand: true,
30 | describe: 'Output path for error file',
31 | default: './Errors.ts',
32 | normalize: true,
33 | coerce: resolve
34 | },
35 | },
36 | async (argv: Args) => {
37 | const { jsonFile = './errors.json', out: outputFilePath } = argv;
38 | const intputFilePath = resolve(jsonFile);
39 | const generatedOutputPath = await commands.generate({ intputFilePath, outputFilePath });
40 | console.info('🔮 You will fail... but successfully');
41 | console.info(`└── 👁 Prophecy available at ${generatedOutputPath}`);
42 | }
43 | )
44 | .command(
45 | ['ask ', 'oracles'],
46 | 'Generate a .ts file that exposes helpers for all the errors exposed through the server api',
47 | {
48 | field: {
49 | demandOption: true,
50 | describe: 'Field to query on Query type',
51 | default: 'errors',
52 | },
53 | out: {
54 | demandOption: true,
55 | describe: 'Output path for error file',
56 | default: './Errors.ts',
57 | normalize: true,
58 | coerce: resolve
59 | },
60 | },
61 | async (argv: Args) => {
62 | console.info('🔮 Connecting with the oracles...');
63 | const { schema: input, out: outputFilePath, field: errorField } = argv;
64 | const outputPath = await commands.ask({ input, errorField, outputFilePath });
65 | console.info('├── 🙏 You will fail... but successfully');
66 | console.info(`└── 👁 All you need to know is available at ${outputPath}`);
67 | }
68 | )
69 | .fail((message, error) => handleError(error ? error : new Error(message)))
70 | .help()
71 | .version()
72 | .strict()
73 | .argv;
--------------------------------------------------------------------------------
/src/commands/ask/ask.ts:
--------------------------------------------------------------------------------
1 | import createFileFromEntries from "./createRawFileFromEntries";
2 | import writeClassFile from "../../writeClassFile";
3 | import { ErrorOutputEntry } from "../../types";
4 | import { makeHeaders } from "./makeHeaders";
5 | import queryServer from "./queryServer";
6 |
7 | export interface AskArgs {
8 | input?: string,
9 | outputFilePath?: string,
10 | errorField?: string
11 | headers?: string[]
12 | }
13 |
14 | export default async function ask({ input, errorField, headers, outputFilePath }: AskArgs) {
15 | const urlRegex = /^https?:\/\//i;
16 |
17 | let errorEntries: ErrorOutputEntry[] = []
18 | if (urlRegex.test(input)) {
19 | errorEntries = await queryServer(input, errorField, makeHeaders(headers));
20 | }
21 | const rawFileContent = createFileFromEntries(errorEntries);
22 | return writeClassFile(rawFileContent, outputFilePath);
23 | }
--------------------------------------------------------------------------------
/src/commands/ask/createRawFileFromEntries.spec.ts:
--------------------------------------------------------------------------------
1 | import createRawFileFromEntries from './createRawFileFromEntries'
2 |
3 | const errors = [{
4 | "name": "UnknownError",
5 | "message": "An unknown error has occurred! Please try again later",
6 | extensions: {
7 | "code": "UNKNOWN"
8 | }
9 | }, {
10 | "name": "ForbiddenError",
11 | "message": "You are not allowed to do this",
12 | extensions: {
13 | "code": "FORBIDDEN"
14 | }
15 | }, {
16 | "name": "AuthenticationRequiredError",
17 | "message": "You must be logged in to do this",
18 | extensions: {
19 | "code": "AUTH_REQUIRED"
20 | }
21 | }];
22 |
23 | const expectedFile = `/* tslint:disable */
24 | import { ApolloError } from "apollo-client";
25 | import { GraphQLError } from "graphql";
26 |
27 | export enum PropheticErrorCode {
28 | CodeLessError = 'NONE',
29 | UnknownError = "UNKNOWN",
30 | ForbiddenError = "FORBIDDEN",
31 | AuthenticationRequiredError = "AUTH_REQUIRED"
32 | }
33 |
34 | export class PropheticError {
35 | constructor(public codes: string[]){}
36 |
37 | private inCodes(code: PropheticErrorCode){ return this.codes.indexOf(code) > -1; }
38 |
39 | get isCodeLessError() { return this.inCodes(PropheticErrorCode.CodeLessError); }
40 | get isUnknownError() { return this.inCodes(PropheticErrorCode.UnknownError); }
41 | get isForbiddenError() { return this.inCodes(PropheticErrorCode.ForbiddenError); }
42 | get isAuthenticationRequiredError() { return this.inCodes(PropheticErrorCode.AuthenticationRequiredError); }
43 | }
44 |
45 | export interface Handler {
46 | (): any
47 | }
48 |
49 | export class PropheticErrorHandled {
50 | private handler: Handler = () => {}
51 |
52 | constructor(public codes: string[]){}
53 |
54 | private inCodes(code: PropheticErrorCode, handler: Handler){
55 | if(this.codes.indexOf(code) > -1){
56 | this.handler = handler
57 | }
58 |
59 | return this;
60 | }
61 |
62 | CodeLessError(handler: Handler) { return this.inCodes(PropheticErrorCode.CodeLessError, handler); }
63 | UnknownError(handler: Handler) { return this.inCodes(PropheticErrorCode.UnknownError, handler); }
64 | ForbiddenError(handler: Handler) { return this.inCodes(PropheticErrorCode.ForbiddenError, handler); }
65 | AuthenticationRequiredError(handler: Handler) { return this.inCodes(PropheticErrorCode.AuthenticationRequiredError, handler); }
66 | handle() { return this.handler(); }
67 | }
68 |
69 | const CODE_LESS_EXTENSION = { code: 'NONE'};
70 | const findCodes = (error: ApolloError | GraphQLError): PropheticErrorCode[] => {
71 | if(error instanceof ApolloError) {
72 | return error.graphQLErrors.map((gError) => findCodes(gError)[0]);
73 | } else if(error.extensions) {
74 | const { extensions: { code } = CODE_LESS_EXTENSION } = error;
75 | return [code];
76 | }
77 |
78 | return [PropheticErrorCode.CodeLessError];
79 | }
80 |
81 | export const errorHere = (error: ApolloError | GraphQLError | undefined ) => {
82 | if(!error) {
83 | return new PropheticError([]);
84 | }
85 | const codes = findCodes(error);
86 | return new PropheticError(codes);
87 | }
88 |
89 | export const isThis = (error: ApolloError | GraphQLError | undefined) => {
90 | if(!error) {
91 | return new PropheticErrorHandled([]);
92 | }
93 | const codes = findCodes(error);
94 | return new PropheticErrorHandled(codes);
95 | }`
96 |
97 | describe('createRawFile', () => {
98 | it('Should correctly generate raw file', () => {
99 | const errorsRawFile = createRawFileFromEntries(errors);
100 | expect(errorsRawFile).toEqual(expectedFile);
101 | });
102 | });
--------------------------------------------------------------------------------
/src/commands/ask/createRawFileFromEntries.ts:
--------------------------------------------------------------------------------
1 | import { JsonOutputEntriesRecord, ErrorOutputEntry, toErrorEntries } from "../../types";
2 |
3 | const TopMostImportsAndConfigDef = `/* tslint:disable */
4 | import { ApolloError } from "apollo-client";
5 | import { GraphQLError } from "graphql";`
6 |
7 | const PropheticErrorCodeEnumDef = `
8 | export enum PropheticErrorCode {
9 | CodeLessError = 'NONE',
10 | _VALUES_
11 | }`;
12 |
13 | const PropheticErrorDef = `
14 | export class PropheticError {
15 | constructor(public codes: string[]){}
16 |
17 | private inCodes(code: PropheticErrorCode){ return this.codes.indexOf(code) > -1; }
18 |
19 | get isCodeLessError() { return this.inCodes(PropheticErrorCode.CodeLessError); }
20 | _FUNCTIONS_
21 | }`;
22 |
23 | const PropheticErrorGetterDef = "get is$_ENUM_$() { return this.inCodes(PropheticErrorCode.$_ENUM_$); }";
24 |
25 | const PropheticErrorHandledDef = `
26 | export interface Handler {
27 | (): any
28 | }
29 |
30 | export class PropheticErrorHandled {
31 | private handler: Handler = () => {}
32 |
33 | constructor(public codes: string[]){}
34 |
35 | private inCodes(code: PropheticErrorCode, handler: Handler){
36 | if(this.codes.indexOf(code) > -1){
37 | this.handler = handler
38 | }
39 |
40 | return this;
41 | }
42 |
43 | CodeLessError(handler: Handler) { return this.inCodes(PropheticErrorCode.CodeLessError, handler); }
44 | _FUNCTIONS_
45 | handle() { return this.handler(); }
46 | }`
47 | const PropheticErrorHandlerDef = "$_ENUM_$(handler: Handler) { return this.inCodes(PropheticErrorCode.$_ENUM_$, handler); }";
48 |
49 | const BottomExportedMethods = `
50 | const CODE_LESS_EXTENSION = { code: 'NONE'};
51 | const findCodes = (error: ApolloError | GraphQLError): PropheticErrorCode[] => {
52 | if(error instanceof ApolloError) {
53 | return error.graphQLErrors.map((gError) => findCodes(gError)[0]);
54 | } else if(error.extensions) {
55 | const { extensions: { code } = CODE_LESS_EXTENSION } = error;
56 | return [code];
57 | }
58 |
59 | return [PropheticErrorCode.CodeLessError];
60 | }
61 |
62 | export const errorHere = (error: ApolloError | GraphQLError | undefined ) => {
63 | if(!error) {
64 | return new PropheticError([]);
65 | }
66 | const codes = findCodes(error);
67 | return new PropheticError(codes);
68 | }
69 |
70 | export const isThis = (error: ApolloError | GraphQLError | undefined) => {
71 | if(!error) {
72 | return new PropheticErrorHandled([]);
73 | }
74 | const codes = findCodes(error);
75 | return new PropheticErrorHandled(codes);
76 | }`
77 |
78 | const toNameAndCodeTupleArray = (entriesArray: ErrorOutputEntry[]) => {
79 | const entries = toErrorEntries(entriesArray);
80 | return Object.keys(entries).map((key) => {
81 | const { extensions = { code: undefined } } = entries[key];
82 | return [key, extensions.code] as [string, string]
83 | }).filter(([_, code]) => code !== undefined);
84 | }
85 |
86 | export default function(entries: ErrorOutputEntry[]) {
87 | const nameAndCodeTuples = toNameAndCodeTupleArray(entries);
88 | const enums = nameAndCodeTuples.map(([name, code]) => `${name} = "${code}"`).join(',\n ');
89 |
90 | const errorDefFun = nameAndCodeTuples.map(([name]) => {
91 | return `${PropheticErrorGetterDef.replace("$_ENUM_$", name).replace("$_ENUM_$", name)}`;
92 | }).join('\n ');
93 |
94 | const errorHandledFun = nameAndCodeTuples.map(([name]) => {
95 | return `${PropheticErrorHandlerDef.replace("$_ENUM_$", name).replace("$_ENUM_$", name)}`;
96 | }).join('\n ');
97 |
98 | return `${TopMostImportsAndConfigDef}
99 | ${PropheticErrorCodeEnumDef.replace('_VALUES_', enums)}
100 | ${PropheticErrorDef.replace('_FUNCTIONS_', errorDefFun)}
101 | ${PropheticErrorHandledDef.replace('_FUNCTIONS_', errorHandledFun)}
102 | ${BottomExportedMethods}`;
103 | }
--------------------------------------------------------------------------------
/src/commands/ask/index.ts:
--------------------------------------------------------------------------------
1 | export { default as ask } from "./ask";
2 |
--------------------------------------------------------------------------------
/src/commands/ask/makeHeaders.spec.ts:
--------------------------------------------------------------------------------
1 | import { makeHeaders } from './makeHeaders';
2 |
3 | describe('makeHeader', () => {
4 | it('Should create header', () => {
5 | const headers = makeHeaders(['Authorization: Bearer uoauzeaouhenaoea']);
6 | expect(headers).toEqual({
7 | Authorization: 'Bearer uoauzeaouhenaoea',
8 | });
9 | });
10 |
11 | it('Should create empty header', () => {
12 | const headers = makeHeaders();
13 | expect(headers).toEqual({});
14 | });
15 |
16 | it('Should throw -> Headers should be specified as "Name: Value"', () => {
17 | expect(() => makeHeaders(['Authorization Bearer uoauzeaouhenaoea'])).toThrow('Headers should be specified as "Name: Value"');
18 | });
19 | });
--------------------------------------------------------------------------------
/src/commands/ask/makeHeaders.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/apollographql/apollo-codegen/blob/master/packages/apollo-codegen/src/cli.ts
2 | export const makeHeaders = (headers: string[] = []) => {
3 | let additionalHeaders: { [key: string]: string } = {};
4 | for (const header of headers) {
5 | const separator = header.indexOf(":");
6 | const name = header.substring(0, separator).trim();
7 | const value = header.substring(separator + 1).trim();
8 | if (!(name && value)) {
9 | throw new Error('Headers should be specified as "Name: Value"');
10 | }
11 | additionalHeaders[name] = value;
12 | }
13 | return additionalHeaders;
14 | };
15 |
--------------------------------------------------------------------------------
/src/commands/ask/queryServer.ts:
--------------------------------------------------------------------------------
1 | import gql from 'graphql-tag';
2 | import fetch from 'node-fetch';
3 | import { execute, makePromise } from 'apollo-link';
4 | import { HttpLink } from 'apollo-link-http';
5 | import { toErrorEntries, ErrorOutputEntry } from '../../types';
6 |
7 | const makeOperation = (erroType: string) => ({
8 | query: gql`query {
9 | ${erroType} {
10 | name
11 | message
12 | extensions {
13 | code
14 | }
15 | }
16 | }
17 | `,
18 | });
19 |
20 | type Headers = {[name: string]: string}
21 |
22 | function exeuteServerQuery(serverUri: string, type: string, headers: Headers) {
23 | const operation = makeOperation(type);
24 | const link = new HttpLink({ uri: serverUri, fetch, headers });
25 |
26 | return makePromise(execute(link, operation));
27 | }
28 |
29 | export default async function(serverUri: string, field: string = 'errors', headers: Headers) {
30 | let result;
31 | try {
32 | result = await exeuteServerQuery(serverUri, field, headers);
33 | } catch(e) {
34 | throw e;
35 | }
36 |
37 | if (result.errors) {
38 | throw new Error(`Errors occured querying "${field}": ${result.errors}`);
39 | }
40 |
41 | if (!result.data || !result.data[field]) {
42 | throw new Error(`No Errors found to generate on query field ${field}`);
43 | }
44 |
45 | const errors = result.data[field];
46 | return errors as ErrorOutputEntry[];
47 | }
--------------------------------------------------------------------------------
/src/commands/generate/checkEntries.spec.ts:
--------------------------------------------------------------------------------
1 | import checkEntries from "./checkEntries";
2 | import { entries } from '../../_specs-utils';
3 |
4 | const mockReadFromFile = () => JSON.parse(`{
5 | "UnknownError": {
6 | "message": "An unknown error has occurred! Please try again later",
7 | "code": "UNKNOWN"
8 | },
9 | "NoCodeError": {
10 | "message": "You are not allowed to do this"
11 | }
12 | }`);
13 |
14 | describe('checkEntries', () => {
15 | it('Should positevely check the entries and return them', () => {
16 | expect(checkEntries(entries)).toEqual(entries);
17 | });
18 |
19 | it('Should throw No "code" key found', () => {
20 | const checkEntriesMock = () => checkEntries(mockReadFromFile())
21 | expect(checkEntriesMock).toThrow('[CodeKeyImperative] No "code" key found for: [NoCodeError]');
22 | });
23 | });
--------------------------------------------------------------------------------
/src/commands/generate/checkEntries.ts:
--------------------------------------------------------------------------------
1 | import { JsonInputErrorEntryRecord } from '../../types';
2 |
3 | export default (inputEntries: JsonInputErrorEntryRecord) => {
4 | const checks = Object.keys(inputEntries).map(key => {
5 | const entry = inputEntries[key];
6 | return { name: key, hasCodeKey: entry.code !== undefined }
7 | }).filter(({ hasCodeKey }) => !hasCodeKey);
8 |
9 | if(checks.length > 0) {
10 | const concernedNames = checks.map(({ name }) => name).join();
11 | throw Error(`[CodeKeyImperative] No "code" key found for: [${concernedNames}]`);
12 | }
13 | return inputEntries;
14 | }
15 |
--------------------------------------------------------------------------------
/src/commands/generate/createError.spec.ts:
--------------------------------------------------------------------------------
1 | import createError from './createError'
2 | import { removeWhiteSpaces } from '../../_specs-utils';
3 |
4 | describe('createError', () => {
5 | it('Should create Special error classs string', () => {
6 | const SpecialError = createError("SpecialError", "Very special", "SPECIAL");
7 | const expectedClass = `
8 | export class SpecialError extends PropheticError {
9 | constructor(properties?: Record) {
10 | super("SpecialError", "Very special", "SPECIAL", properties);
11 | }
12 | }
13 | `;
14 | expect(removeWhiteSpaces(SpecialError)).toEqual(removeWhiteSpaces(expectedClass));
15 | });
16 | });
--------------------------------------------------------------------------------
/src/commands/generate/createError.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApolloServer,
3 | ApolloError,
4 | toApolloError,
5 | gql,
6 | } from 'apollo-server';
7 |
8 | export const PropheticErrorTextDef = `class PropheticError extends ApolloError {
9 | constructor(name: string, message: string, code?: string, properties?: Record) {
10 | super(message, code, properties);
11 |
12 | // Set the prototype explicitly.
13 | // https://stackoverflow.com/a/41102306
14 | Object.setPrototypeOf(this, SyntaxError.prototype);
15 | Object.defineProperty(this, 'name', { value: name });
16 | }
17 | }`
18 |
19 | export default function(name: string, message: string, code: string, properties?: Record) {
20 | return `export class ${name} extends PropheticError {
21 | constructor(properties?: Record) {
22 | super("${name}", "${message}", "${code}", properties);
23 | }
24 | }`
25 | }
--------------------------------------------------------------------------------
/src/commands/generate/generate.spec.ts:
--------------------------------------------------------------------------------
1 | import '../../_specs-utils/jest-fs';
2 | import fs from 'fs';
3 | import generate from './generate';
4 |
5 | import * as path from 'path';
6 | import { entries, mkdirTmp } from '../../_specs-utils';
7 | import { fs as fsu } from '../../utils';
8 |
9 |
10 | describe('generate', () => {
11 | let tmpFolder: string;
12 | let errorsJsonInputFile: string;
13 | let errorsTsOutputFile: string;
14 |
15 | beforeAll(() => {
16 | tmpFolder = mkdirTmp();
17 | errorsJsonInputFile = path.join(tmpFolder, 'errors.json');
18 | errorsTsOutputFile = path.join(tmpFolder, 'Errors.ts');
19 | fsu.mkdirs(tmpFolder);
20 | fsu.writeFile(errorsJsonInputFile, JSON.stringify(entries));
21 | });
22 |
23 | it(`Should create the "Errors.ts" file in tmp folder`, async () => {
24 | const pathName = await generate({ intputFilePath: errorsJsonInputFile, outputFilePath: errorsTsOutputFile });
25 |
26 | expect(tmpFolder).toBeDirectoryWithFiles(['Errors.ts', 'errors.json']);
27 | // ((expect(tmpFolder).to.be.a) as any).directory(tmpFolder).and.not.empty;
28 | // ((expect(tmpFolder).to.be.a) as any).directory(tmpFolder).with.files(['Errors.ts', 'errors.json']);
29 | });
30 | });
--------------------------------------------------------------------------------
/src/commands/generate/generate.ts:
--------------------------------------------------------------------------------
1 | import generateRawClass from './generateRawClass';
2 | import writeClassFile from '../../writeClassFile';
3 | import checkEntries from './checkEntries';
4 | import { fs } from './../../utils';
5 |
6 | export interface ProphecyArgs {
7 | intputFilePath: string,
8 | outputFilePath?: string,
9 | }
10 |
11 | export default async function generate(args: ProphecyArgs) {
12 | const { intputFilePath, outputFilePath } = args;
13 | const entries = checkEntries(fs.readJsonDef(intputFilePath));
14 | const rawClassContent = generateRawClass(entries);
15 | return writeClassFile(rawClassContent, outputFilePath);
16 | }
--------------------------------------------------------------------------------
/src/commands/generate/generateRawClass.spec.ts:
--------------------------------------------------------------------------------
1 | import { toRawClassesArray,toScalarTypesMap, generatePropheticErrorType } from './generateRawClass'
2 | import { removeWhiteSpaces } from '../../_specs-utils';
3 |
4 | const errors = {
5 | UnknownError: {
6 | "message": "An unknown error has occurred! Please try again later",
7 | "code": "UNKNOWN"
8 | },
9 | ForbiddenError: {
10 | "message": "You are not allowed to do this",
11 | "code": "FORBIDDEN",
12 | },
13 | AuthenticationRequiredError: {
14 | "message": "You must be logged in to do this",
15 | "code": "AUTH_REQUIRED"
16 | },
17 | };
18 |
19 | const expectedTypes = [ { code: "String" }, { code: "String" }, { code: "String" }];
20 | const expectedOutputClass = `export class ForbiddenError extends PropheticError {
21 | constructor(properties?: Record) {
22 | super("ForbiddenError", "You are not allowed to do this", "FORBIDDEN", properties);
23 | }
24 | }`
25 | describe('generateRawClass', () => {
26 | it('toRawClassesArray should correctly returns string classes definition', () => {
27 | const rawClasses = toRawClassesArray(errors);
28 | expect(rawClasses).toHaveLength(3);
29 | expect(rawClasses[1]).toEqual(expectedOutputClass);
30 | });
31 |
32 | it('Should correctly create the GraphQL Type Definition string', () => {
33 | const scalarTypesArray = toScalarTypesMap(errors);
34 | const rawGraphqlTypes = generatePropheticErrorType(scalarTypesArray);
35 |
36 | expect(removeWhiteSpaces(rawGraphqlTypes)).toEqual(removeWhiteSpaces(`
37 | type PropheticErrorExtensions {
38 | code: String?
39 | }
40 |
41 | type PropheticError {
42 | name: String
43 | message: String?
44 | extensions: PropheticErrorExtensions
45 | }`));
46 | });
47 |
48 | it('Should correctly map object fields to the right type', () => {
49 | const scalarTypesArray = toScalarTypesMap(errors);
50 | expect(scalarTypesArray).toEqual(expectedTypes);
51 | });
52 | });
--------------------------------------------------------------------------------
/src/commands/generate/generateRawClass.ts:
--------------------------------------------------------------------------------
1 | import createError, { PropheticErrorTextDef } from './createError'
2 | import { JsonInputErrorEntryRecord, JsonInputErrorEntry, toOutputErrors } from '../../types';
3 |
4 | export type ScalarType = "Boolean" | "Int" | "Float" | "String"
5 | export type ScalarTypesMap = {[key: string]: ScalarType};
6 |
7 | function scalarGQLTpeFromValue(value: any): ScalarType | null {
8 | switch (typeof value) {
9 | case "string":
10 | return "String"
11 | case "boolean":
12 | return "Boolean"
13 | case "number":
14 | if(value % 1 === 0){
15 | return "Int"
16 | } else {
17 | return "Float"
18 | }
19 | default:
20 | throw new Error(`Non scalar type define for "${value}" type is ${typeof value}`);
21 | }
22 | }
23 |
24 | export function toRawClassesArray(entries: JsonInputErrorEntryRecord) {
25 | return Object.keys(entries).map((key) => {
26 | const { message, code, ...rest } = entries[key];
27 | return createError(key, message, code, rest);
28 | });
29 | }
30 |
31 | export function toScalarTypesMap(entries: JsonInputErrorEntryRecord): ScalarTypesMap[] {
32 | const initial: ScalarTypesMap = {};
33 | return Object.values(entries).map((entry) => Object.keys(entry).filter(key => key !== 'message').reduce((prev, entryFieldKey) => {
34 | const fieldValue = entry[entryFieldKey];
35 | const fieldType = scalarGQLTpeFromValue(fieldValue);
36 | if (fieldType) prev[entryFieldKey] = fieldType;
37 |
38 | return prev;
39 | }, initial),{});
40 | }
41 |
42 | type TypeDefinition = { type: string, isNullableType: boolean }
43 | type TypeDefinitionsMap = {[key: string]: TypeDefinition }
44 |
45 | export function generatePropheticErrorType(typesArray: ScalarTypesMap[]) {
46 | const fieldsReduced = typesArray.filter(type => type).reduce((prev: TypeDefinitionsMap, typesMap) => {
47 | const isFirst = prev === {}
48 |
49 | for (let key in typesMap) {
50 | const fieldType = typesMap[key];
51 | let isNullableType = true;
52 | if(!isFirst && prev[key] && prev[key].isNullableType) {
53 | if(prev[key].isNullableType !== true) {
54 | prev[key].isNullableType = prev[key].isNullableType;
55 | } else{
56 | prev[key].isNullableType = false
57 | }
58 | }
59 |
60 | const value = { type: fieldType, isNullableType };
61 | prev[key] = value;
62 | }
63 | return prev;
64 | },{}) as TypeDefinitionsMap
65 |
66 |
67 | const fields = Object.entries(fieldsReduced).map(([name, { type, isNullableType } ]) => {
68 | return `${name}: ${type}${isNullableType ? '?': ''}`
69 | });
70 |
71 | return `
72 | type PropheticErrorExtensions {
73 | ${fields.join('\n ')}
74 | }
75 |
76 | type PropheticError {
77 | name: String
78 | message: String?
79 | extensions: PropheticErrorExtensions
80 | }
81 | `
82 | }
83 |
84 | export default function generateRawClass (entries: JsonInputErrorEntryRecord) {
85 | const rawErrorClasses = toRawClassesArray(entries).join('\n');
86 | const fieldsTypesMapArray = toScalarTypesMap(entries);
87 | const rawPropheticErrorAndExtensionsType = generatePropheticErrorType(fieldsTypesMapArray);
88 | const errorsList = toOutputErrors(entries);
89 |
90 | const classFile = `
91 | import { ApolloError } from 'apollo-server'
92 |
93 | export const errorsList = ${JSON.stringify(errorsList, null, 2)};
94 | export const errorType = \`${rawPropheticErrorAndExtensionsType}\`;
95 |
96 | ${PropheticErrorTextDef}
97 |
98 | ${rawErrorClasses}
99 | `
100 | return classFile;
101 | }
--------------------------------------------------------------------------------
/src/commands/generate/index.ts:
--------------------------------------------------------------------------------
1 | export { default as generate } from "./generate";
2 |
--------------------------------------------------------------------------------
/src/commands/index.ts:
--------------------------------------------------------------------------------
1 | export { generate } from './generate'
2 | export { ask } from './ask'
3 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as commands from './commands';
2 | import * as utils from './utils';
3 | import * as types from './types';
4 |
5 | export { commands, utils, types };
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export type JsonInputErrorEntry = {
2 | message: string
3 | code: string
4 | [key:string]: any
5 | }
6 |
7 | export type ErrorOutputEntry = {
8 | name: string
9 | message?: string
10 | extensions: {
11 | code: string
12 | [key:string]: any
13 | }
14 | }
15 |
16 | export type JsonInputErrorEntryRecord = { [key:string]: JsonInputErrorEntry }
17 | export type JsonOutputEntriesRecord = { [key:string]: ErrorOutputEntry }
18 |
19 | export function toErrorEntries(entries: ErrorOutputEntry[]) {
20 | return entries.reduce((map, entry) => {
21 | map[entry.name] = entry;
22 | return map;
23 | }, {} as JsonOutputEntriesRecord);
24 | }
25 |
26 | export function toOutputErrors(entries: JsonInputErrorEntryRecord) {
27 | return Object.keys(entries).map((key) => {
28 | const { name, message, code, ...rest } = entries[key];
29 | return {
30 | name: name || key,
31 | message: message,
32 | extensions: {
33 | code,
34 | ...rest
35 | }
36 | } as ErrorOutputEntry
37 | });
38 | }
--------------------------------------------------------------------------------
/src/utils/fs-prophecy.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as rimraf from 'rimraf';
3 | import * as mkdirp from 'mkdirp';
4 | import * as jsonfile from 'jsonfile';
5 | import { JsonInputErrorEntry } from '../types';
6 |
7 | export const writeFile = (path: string, content: string) => fs.writeFileSync(path, content);
8 | export const mkdirs = (path: string) => mkdirp.sync(path);
9 | export const rmrf = (path: string) => rimraf.sync(path);
10 | export function readJsonDef(filePath: jsonfile.Path) {
11 | return jsonfile.readFileSync(filePath) as JsonInputErrorEntry;
12 | }
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import * as fs from './fs-prophecy';
2 |
3 | export {
4 | fs
5 | }
6 |
--------------------------------------------------------------------------------
/src/writeClassFile.spec.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import * as chai from 'chai';
3 | import chaiFS from 'chai-fs';
4 |
5 | import writeClassFile from './writeClassFile'
6 | import { fs } from './utils';
7 |
8 | import { mkdirTmp, tmpErrorFilePath } from './_specs-utils';
9 |
10 | chai.use(chaiFS);
11 | const { expect } = chai;
12 |
13 | describe('createClassFile', () => {
14 | it('Should create a folder with the "Errors.ts" file in it', () => {
15 | const tmpDirPath = mkdirTmp();
16 | const tmpErrorsPath = path.join(tmpDirPath, 'Errors.ts');
17 | writeClassFile("class SpecialError {}", tmpDirPath);
18 | ((expect(tmpDirPath).to.be.a) as any).directory(tmpDirPath).and.not.empty;
19 | ((expect(tmpDirPath).to.be.a) as any).directory(tmpDirPath).with.files(['Errors.ts']);
20 | ((expect(tmpErrorsPath).to.be.a) as any).to.be.a.file().with.content("class SpecialError {}");
21 |
22 | fs.rmrf(tmpDirPath);
23 | });
24 |
25 | it('Should create a folder with the "Errs.ts file" in it', () => {
26 | const tmpDirPath = tmpErrorFilePath('Errs.ts');
27 | writeClassFile("class SpecialError {}", tmpDirPath);
28 | ((expect(tmpDirPath).to.be.a) as any).to.be.a.file().and.not.empty;
29 | ((expect(tmpDirPath).to.be.a) as any).to.be.a.file().with.content("class SpecialError {}");
30 |
31 | fs.rmrf(tmpDirPath);
32 | });
33 |
34 | it('Should throw .ts file expected as output', () => {
35 | const tmpDirPath = tmpErrorFilePath('Errors.js');
36 | const writeClassFileThrow = () => writeClassFile("class SpecialError {}", tmpDirPath);
37 | expect(writeClassFileThrow).to.throw(".ts file expected as output");
38 |
39 | fs.rmrf(tmpDirPath);
40 | });
41 | });
--------------------------------------------------------------------------------
/src/writeClassFile.ts:
--------------------------------------------------------------------------------
1 | import { parse , normalize } from 'path';
2 | import { fs } from './utils';
3 |
4 | export default (content: string, output: string = '_generated') => {
5 | const outputPath = normalize(output);
6 | const fileExtension = parse(outputPath).ext;
7 | const fileSpecified = (fileExtension !== null && fileExtension !== undefined) && fileExtension.length > 0;
8 | const fileIsTS = fileExtension === '.ts';
9 |
10 | if(fileSpecified && !fileIsTS) {
11 | throw new Error('.ts file expected as output');
12 | }
13 |
14 | const outputFile = fileSpecified ? parse(outputPath).base : 'Errors.ts';
15 | const outputDirectory = fileSpecified ? parse(outputPath).dir : outputPath;
16 |
17 | fs.mkdirs(outputDirectory);
18 |
19 | const outputFilePath = normalize(`${outputDirectory}/${outputFile}`);
20 | fs.writeFile(outputFilePath, content);
21 |
22 | return outputFilePath;
23 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "types": ["node", "jest"],
6 | "moduleResolution": "node",
7 | "lib": [ "es6", "esnext" ],
8 | "esModuleInterop": true,
9 | "noImplicitAny": true,
10 | "declaration": true,
11 | "sourceMap": true,
12 | "pretty": true,
13 | "rootDir": "src",
14 | "outDir": "lib",
15 | "skipLibCheck": true,
16 | "resolveJsonModule": true,
17 | "strict": true
18 | },
19 | "exclude": [
20 | "lib",
21 | "test",
22 | "**/*.spec.ts",
23 | "**/*.check.ts",
24 | "./node_modules",
25 | "node_modules",
26 | "_generated",
27 | "_specs-utils"
28 | ]
29 | }
--------------------------------------------------------------------------------