UNPKG

10.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tslib_1 = require("tslib");
4const code_file_loader_1 = require("@graphql-toolkit/code-file-loader");
5const git_loader_1 = require("@graphql-toolkit/git-loader");
6const github_loader_1 = require("@graphql-toolkit/github-loader");
7const apollo_engine_loader_1 = require("@graphql-toolkit/apollo-engine-loader");
8const prisma_loader_1 = require("@graphql-toolkit/prisma-loader");
9const fs_extra_1 = require("fs-extra");
10const fs_1 = require("fs");
11const path_1 = require("path");
12const core_1 = require("@graphback/core");
13const graphql_migrations_1 = require("graphql-migrations");
14const codegen_client_1 = require("@graphback/codegen-client");
15const codegen_resolvers_1 = require("@graphback/codegen-resolvers");
16const codegen_schema_1 = require("@graphback/codegen-schema");
17const listr_1 = tslib_1.__importDefault(require("listr"));
18const inquirer_1 = require("inquirer");
19const chokidar_1 = tslib_1.__importDefault(require("chokidar"));
20const debounce_1 = tslib_1.__importDefault(require("debounce"));
21const graphql_1 = require("graphql");
22const FormatExtensionMap = {
23 'ts': 'ts',
24 'js': 'js',
25 'gql': 'graphql',
26};
27function writeFile(path, data) {
28 return new Promise(async (resolve, reject) => {
29 await fs_extra_1.ensureFile(path);
30 fs_1.writeFile(path, data, err => {
31 if (err) {
32 reject(err);
33 }
34 resolve();
35 });
36 });
37}
38exports.writeFile = writeFile;
39function globPromise(glob, options = {}) {
40 return new Promise(async (resolve, reject) => {
41 const { default: globAsync } = await Promise.resolve().then(() => tslib_1.__importStar(require('glob')));
42 globAsync(glob, options, (err, data) => {
43 if (err) {
44 reject(err);
45 }
46 resolve(data);
47 });
48 });
49}
50exports.globPromise = globPromise;
51async function createSchemaFile(cwd, generatedSchema, config) {
52 const extension = FormatExtensionMap[config.generator.schema.format];
53 return writeFile(path_1.join(cwd, config.folders.schema, 'generated.' + extension), generatedSchema);
54}
55exports.createSchemaFile = createSchemaFile;
56async function createResolversFiles(cwd, resolvers, config) {
57 const extension = FormatExtensionMap[config.generator.resolvers.format];
58 return Promise.all(resolvers.types.map(typeResolver => writeFile(path_1.join(cwd, config.folders.resolvers, 'generated', typeResolver.name + '.' + extension), typeResolver.output)));
59}
60exports.createResolversFiles = createResolversFiles;
61async function createBackendFiles(cwd, inputContext, config) {
62 const resolvers = codegen_resolvers_1.createResolvers(inputContext, config.generator.resolvers);
63 const schema = codegen_schema_1.createSchema(inputContext, config.generator.schema);
64 await Promise.all([
65 createSchemaFile(cwd, schema, config),
66 createResolversFiles(cwd, resolvers, config)
67 ]);
68}
69exports.createBackendFiles = createBackendFiles;
70async function createFragments(cwd, generated, config) {
71 const extension = FormatExtensionMap[config.generator.client.format];
72 return Promise.all(generated.fragments.map((fragment) => writeFile(path_1.join(cwd, config.folders.client, 'generated', 'fragments', fragment.name + '.' + extension), fragment.implementation)));
73}
74exports.createFragments = createFragments;
75async function createQueries(cwd, generated, config) {
76 const extension = FormatExtensionMap[config.generator.client.format];
77 return Promise.all(generated.queries.map(query => writeFile(path_1.join(cwd, config.folders.client, 'generated', 'queries', query.name + '.' + extension), query.implementation)));
78}
79exports.createQueries = createQueries;
80async function createMutations(cwd, generated, config) {
81 const extension = FormatExtensionMap[config.generator.client.format];
82 return Promise.all(generated.mutations.map(mutation => writeFile(path_1.join(cwd, config.folders.client, 'generated', 'mutations', mutation.name + '.' + extension), mutation.implementation)));
83}
84exports.createMutations = createMutations;
85async function createSubscriptions(cwd, generated, config) {
86 const extension = FormatExtensionMap[config.generator.client.format];
87 return Promise.all(generated.subscriptions.map(subscription => writeFile(path_1.join(cwd, config.folders.client, 'generated', 'subscriptions', subscription.name + '.' + extension), subscription.implementation)));
88}
89exports.createSubscriptions = createSubscriptions;
90async function createClientFiles(cwd, inputContext, config) {
91 const generated = await codegen_client_1.createClient(inputContext, { output: config.generator.client.format });
92 await Promise.all([
93 createFragments(cwd, generated, config),
94 createQueries(cwd, generated, config),
95 createMutations(cwd, generated, config),
96 createSubscriptions(cwd, generated, config),
97 ]);
98}
99exports.createClientFiles = createClientFiles;
100async function createDatabaseMigration(schema, config) {
101 const dbConfig = {
102 client: config.db.database,
103 connection: config.db.dbConfig,
104 };
105 await graphql_migrations_1.migrateDB(dbConfig, schema);
106}
107exports.createDatabaseMigration = createDatabaseMigration;
108exports.runGeneration = async ({ db, client, backend, silent }, cwd, generateConfig, schemaString) => {
109 const tasks = [];
110 if (backend || client) {
111 // Creates model context that is shared with all generators to provide results
112 const inputContext = core_1.graphQLInputContext.createModelContext(schemaString, generateConfig.graphqlCRUD);
113 if (backend) {
114 tasks.push({
115 title: 'Generating Backend Schema and Resolvers',
116 task: () => createBackendFiles(cwd, inputContext, generateConfig),
117 });
118 }
119 if (client) {
120 tasks.push({
121 title: 'Generating Client-side Operations',
122 task: () => createClientFiles(cwd, inputContext, generateConfig),
123 });
124 }
125 }
126 if (db) {
127 tasks.push({
128 title: 'Running Database Migration',
129 task: () => createDatabaseMigration(schemaString, generateConfig),
130 });
131 }
132 const listr = new listr_1.default(tasks, {
133 renderer: silent ? 'silent' : 'default',
134 // it doesn't stop when one of tasks failed, to finish at least some of outputs
135 exitOnError: false,
136 // run 4 at once
137 concurrent: 4,
138 });
139 await listr.run();
140};
141const GenerateExtension = api => {
142 // Schema
143 api.loaders.schema.register(new code_file_loader_1.CodeFileLoader());
144 api.loaders.schema.register(new git_loader_1.GitLoader());
145 api.loaders.schema.register(new github_loader_1.GithubLoader());
146 api.loaders.schema.register(new apollo_engine_loader_1.ApolloEngineLoader());
147 api.loaders.schema.register(new prisma_loader_1.PrismaLoader());
148 return {
149 name: 'generate'
150 };
151};
152exports.plugin = {
153 init({ program, loadProjectConfig, reportError }) {
154 program
155 .command('generate')
156 .option('--db')
157 .option('--client')
158 .option('--backend')
159 .option('--silent')
160 .option('-w, --watch', 'Watch for changes and execute generation automatically')
161 .action(async (cliFlags) => {
162 try {
163 const config = await loadProjectConfig({
164 extensions: [GenerateExtension]
165 });
166 const generateConfig = await config.extension('generate');
167 if (!generateConfig) {
168 throw new Error(`You should provide a valid 'generate' config to generate schema from data model`);
169 }
170 if (!generateConfig.folders) {
171 throw new Error(`'generate' config missing 'folders' section that is required`);
172 }
173 if (!cliFlags.db && !cliFlags.client && !cliFlags.backend) {
174 const { selections } = await inquirer_1.prompt([
175 {
176 type: 'checkbox',
177 name: 'selections',
178 message: 'What do you want to generate?',
179 choices: [
180 {
181 value: 'backend',
182 name: 'Backend Schema and Resolvers',
183 },
184 {
185 value: 'client',
186 name: 'Client-Side Operation',
187 }, {
188 value: 'db',
189 name: 'Database Creation and Migration',
190 }
191 ]
192 }
193 ]);
194 cliFlags.db = selections.includes('db');
195 cliFlags.client = selections.includes('client');
196 cliFlags.backend = selections.includes('backend');
197 }
198 const debouncedExec = debounce_1.default(async () => {
199 try {
200 const schemaDocument = await config.loadSchema(path_1.join(config.dirpath, generateConfig.folders.model + '/**/*.graphql'), 'DocumentNode');
201 const schemaString = graphql_1.print(schemaDocument);
202 await exports.runGeneration(cliFlags, config.dirpath, generateConfig, schemaString);
203 }
204 catch (e) {
205 reportError(e);
206 }
207 console.info('Watching for changes...');
208 }, 100);
209 if (cliFlags.watch) {
210 chokidar_1.default.watch(generateConfig.folders.model, {
211 persistent: true,
212 cwd: config.dirpath,
213 }).on('all', debouncedExec);
214 }
215 else {
216 const schemaDocument = await config.loadSchema(path_1.join(config.dirpath, generateConfig.folders.model + '/**/*.graphql'), 'DocumentNode');
217 const schemaString = graphql_1.print(schemaDocument);
218 await exports.runGeneration(cliFlags, config.dirpath, generateConfig, schemaString);
219 process.exit(0);
220 }
221 }
222 catch (e) {
223 reportError(e);
224 }
225 });
226 }
227};
228//# sourceMappingURL=index.js.map
\No newline at end of file