UNPKG

11.6 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19 if (mod && mod.__esModule) return mod;
20 var result = {};
21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 __setModuleDefault(result, mod);
23 return result;
24};
25var __importDefault = (this && this.__importDefault) || function (mod) {
26 return (mod && mod.__esModule) ? mod : { "default": mod };
27};
28Object.defineProperty(exports, "__esModule", { value: true });
29const path_1 = __importDefault(require("path"));
30// @ts-expect-error TODO: type out if necessary
31const Index_bs_js_1 = __importDefault(require("@float-capital/float-subgraph-uncrashable/src/Index.bs.js"));
32const fs_extra_1 = __importDefault(require("fs-extra"));
33const toolbox = __importStar(require("gluegun"));
34const graphql = __importStar(require("graphql/language"));
35const immutable_1 = __importDefault(require("immutable"));
36const prettier_1 = __importDefault(require("prettier"));
37const template_1 = __importDefault(require("./codegen/template"));
38const typescript_1 = require("./codegen/typescript");
39const fs_1 = require("./command-helpers/fs");
40const spinner_1 = require("./command-helpers/spinner");
41const migrations_1 = require("./migrations");
42const schema_1 = __importDefault(require("./schema"));
43const subgraph_1 = __importDefault(require("./subgraph"));
44const watcher_1 = __importDefault(require("./watcher"));
45class TypeGenerator {
46 constructor(options) {
47 this.options = options;
48 this.sourceDir =
49 this.options.sourceDir ||
50 (this.options.subgraphManifest && path_1.default.dirname(this.options.subgraphManifest));
51 this.protocol = this.options.protocol;
52 this.protocolTypeGenerator = this.protocol?.getTypeGenerator?.({
53 sourceDir: this.sourceDir,
54 outputDir: this.options.outputDir,
55 });
56 process.on('uncaughtException', e => {
57 toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`);
58 });
59 }
60 async generateTypes() {
61 if (this.protocol.name === 'substreams') {
62 toolbox.print.success('Subgraph uses a substream datasource. Codegeneration is not required.');
63 process.exit(0);
64 return;
65 }
66 try {
67 if (!this.options.skipMigrations && this.options.subgraphManifest) {
68 await (0, migrations_1.applyMigrations)({
69 sourceDir: this.sourceDir,
70 manifestFile: this.options.subgraphManifest,
71 });
72 }
73 const subgraph = await this.loadSubgraph();
74 // Not all protocols support/have ABIs.
75 if (this.protocol.hasABIs()) {
76 const abis = await this.protocolTypeGenerator.loadABIs(subgraph);
77 await this.protocolTypeGenerator.generateTypesForABIs(abis);
78 }
79 await this.generateTypesForDataSourceTemplates(subgraph);
80 // Not all protocols support/have ABIs.
81 if (this.protocol.hasABIs()) {
82 const templateAbis = await this.protocolTypeGenerator.loadDataSourceTemplateABIs(subgraph);
83 await this.protocolTypeGenerator.generateTypesForDataSourceTemplateABIs(templateAbis);
84 }
85 const schema = await this.loadSchema(subgraph);
86 await this.generateTypesForSchema(schema);
87 toolbox.print.success('\nTypes generated successfully\n');
88 if (this.options.uncrashable && this.options.uncrashableConfig) {
89 await this.generateUncrashableEntities(schema);
90 toolbox.print.success('\nUncrashable Helpers generated successfully\n');
91 }
92 return true;
93 }
94 catch (e) {
95 return false;
96 }
97 }
98 async generateUncrashableEntities(graphSchema) {
99 const ast = graphql.parse(graphSchema.document);
100 const entityDefinitions = ast['definitions'];
101 return await (0, spinner_1.withSpinner)(`Generate Uncrashable Entity Helpers`, `Failed to generate Uncrashable Entity Helpers`, `Warnings while generating Uncrashable Entity Helpers`, async (spinner) => {
102 Index_bs_js_1.default.run(entityDefinitions, this.options.uncrashableConfig, this.options.outputDir);
103 const outputFile = path_1.default.join(this.options.outputDir, 'UncrashableEntityHelpers.ts');
104 (0, spinner_1.step)(spinner, 'Save uncrashable entities to', (0, fs_1.displayPath)(outputFile));
105 });
106 }
107 async loadSubgraph({ quiet } = { quiet: false }) {
108 const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false };
109 if (quiet) {
110 return (this.options.subgraph ||
111 (await subgraph_1.default.load(this.options.subgraphManifest, subgraphLoadOptions)).result);
112 }
113 const manifestPath = (0, fs_1.displayPath)(this.options.subgraphManifest);
114 return await (0, spinner_1.withSpinner)(`Load subgraph from ${manifestPath}`, `Failed to load subgraph from ${manifestPath}`, `Warnings while loading subgraph from ${manifestPath}`, async (_spinner) => {
115 return (this.options.subgraph || subgraph_1.default.load(this.options.subgraphManifest, subgraphLoadOptions));
116 });
117 }
118 async loadSchema(subgraph) {
119 const maybeRelativePath = subgraph.getIn(['schema', 'file']);
120 const absolutePath = path_1.default.resolve(this.sourceDir, maybeRelativePath);
121 return await (0, spinner_1.withSpinner)(`Load GraphQL schema from ${(0, fs_1.displayPath)(absolutePath)}`, `Failed to load GraphQL schema from ${(0, fs_1.displayPath)(absolutePath)}`, `Warnings while loading GraphQL schema from ${(0, fs_1.displayPath)(absolutePath)}`, async (_spinner) => {
122 const absolutePath = path_1.default.resolve(this.sourceDir, maybeRelativePath);
123 return schema_1.default.load(absolutePath);
124 });
125 }
126 async generateTypesForSchema(schema) {
127 return await (0, spinner_1.withSpinner)(`Generate types for GraphQL schema`, `Failed to generate types for GraphQL schema`, `Warnings while generating types for GraphQL schema`, async (spinner) => {
128 // Generate TypeScript module from schema
129 const codeGenerator = schema.codeGenerator();
130 const code = prettier_1.default.format([
131 typescript_1.GENERATED_FILE_NOTE,
132 ...codeGenerator.generateModuleImports(),
133 ...codeGenerator.generateTypes(),
134 ...codeGenerator.generateDerivedLoaders(),
135 ].join('\n'), {
136 parser: 'typescript',
137 });
138 const outputFile = path_1.default.join(this.options.outputDir, 'schema.ts');
139 (0, spinner_1.step)(spinner, 'Write types to', (0, fs_1.displayPath)(outputFile));
140 await fs_extra_1.default.mkdirs(path_1.default.dirname(outputFile));
141 await fs_extra_1.default.writeFile(outputFile, code);
142 });
143 }
144 async generateTypesForDataSourceTemplates(subgraph) {
145 return await (0, spinner_1.withSpinner)(`Generate types for data source templates`, `Failed to generate types for data source templates`, `Warnings while generating types for data source templates`, async (spinner) => {
146 // Combine the generated code for all templates
147 const codeSegments = subgraph
148 .get('templates', immutable_1.default.List())
149 .reduce((codeSegments, template) => {
150 (0, spinner_1.step)(spinner, 'Generate types for data source template', String(template.get('name')));
151 const codeGenerator = new template_1.default(template, this.protocol);
152 // Only generate module imports once, because they are identical for
153 // all types generated for data source templates.
154 if (codeSegments.isEmpty()) {
155 codeSegments = codeSegments.concat(codeGenerator.generateModuleImports());
156 }
157 return codeSegments.concat(codeGenerator.generateTypes());
158 }, immutable_1.default.List());
159 if (!codeSegments.isEmpty()) {
160 const code = prettier_1.default.format([typescript_1.GENERATED_FILE_NOTE, ...codeSegments].join('\n'), {
161 parser: 'typescript',
162 });
163 const outputFile = path_1.default.join(this.options.outputDir, 'templates.ts');
164 (0, spinner_1.step)(spinner, `Write types for templates to`, (0, fs_1.displayPath)(outputFile));
165 await fs_extra_1.default.mkdirs(path_1.default.dirname(outputFile));
166 await fs_extra_1.default.writeFile(outputFile, code);
167 }
168 });
169 }
170 async getFilesToWatch() {
171 try {
172 const files = [];
173 const subgraph = await this.loadSubgraph({ quiet: true });
174 // Add the subgraph manifest file
175 files.push(this.options.subgraphManifest);
176 // Add the GraphQL schema to the watched files
177 files.push(subgraph.getIn(['schema', 'file']));
178 // Add all file paths specified in manifest
179 subgraph.get('dataSources').map((dataSource) => {
180 dataSource.getIn(['mapping', 'abis']).map((abi) => {
181 files.push(abi.get('file'));
182 });
183 });
184 // Make paths absolute
185 return files.map(file => path_1.default.resolve(file));
186 }
187 catch (e) {
188 throw Error(`Failed to load subgraph: ${e.message}`);
189 }
190 }
191 async watchAndGenerateTypes() {
192 const generator = this;
193 let spinner;
194 // Create watcher and generate types once and then on every change to a watched file
195 const watcher = new watcher_1.default({
196 onReady: () => (spinner = toolbox.print.spin('Watching subgraph files')),
197 onTrigger: async (changedFile) => {
198 if (changedFile !== undefined) {
199 spinner.info(`File change detected: ${(0, fs_1.displayPath)(changedFile)}\n`);
200 }
201 await generator.generateTypes();
202 spinner.start();
203 },
204 onCollectFiles: async () => await generator.getFilesToWatch(),
205 onError: error => {
206 spinner.stop();
207 toolbox.print.error(`${error}\n`);
208 spinner.start();
209 },
210 });
211 // Catch keyboard interrupt: close watcher and exit process
212 process.on('SIGINT', () => {
213 watcher.close();
214 process.exit();
215 });
216 try {
217 await watcher.watch();
218 }
219 catch (e) {
220 toolbox.print.error(String(e.message));
221 }
222 }
223}
224exports.default = TypeGenerator;