1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const lifecycle_1 = require("@stoplight/lifecycle");
|
4 | const uuidv4 = require("uuid/v4");
|
5 | const errorReporter_1 = require("./errorReporter");
|
6 | const graph_1 = require("./graph");
|
7 | const dom_1 = require("./graph/dom");
|
8 | const nodes_1 = require("./graph/nodes");
|
9 | const notifier_1 = require("./notifier");
|
10 | const resolver_1 = require("./resolver");
|
11 | const scheduler_1 = require("./scheduler");
|
12 | const taskHandler_1 = require("./scheduler/taskHandler");
|
13 | const specProviderRegistry_1 = require("./services/specProviderRegistry");
|
14 | function createGraphite(props = {}) {
|
15 | return new Graphite(props);
|
16 | }
|
17 | exports.createGraphite = createGraphite;
|
18 | class Graphite {
|
19 | constructor(props) {
|
20 | this._disposables = new lifecycle_1.DisposableCollection();
|
21 | this.dispose = () => {
|
22 | this._disposables.dispose();
|
23 | };
|
24 | this.id = props.id || uuidv4();
|
25 | this.notifier = (props.graph && props.graph.notifier) || props.notifier || notifier_1.createNotifier();
|
26 | this.graph =
|
27 | props.graph ||
|
28 | graph_1.createGraph({
|
29 | id: this.id,
|
30 | idGenerator: props.idGenerator,
|
31 | notifier: this.notifier,
|
32 | });
|
33 | this.resolver = resolver_1.createResolver(new resolver_1.ResolveCache(), this.graph.getNodeByUri);
|
34 | this.scheduler =
|
35 | props.scheduler ||
|
36 | scheduler_1.createScheduler({
|
37 | graph: this.graph,
|
38 | resolver: this.resolver,
|
39 | });
|
40 | this._disposables.pushAll([this.graph, this.notifier]);
|
41 | this._disposables.pushAll(this.scheduleSerialize());
|
42 | this._disposables.pushAll(this.scheduleDeserialize());
|
43 | this._disposables.pushAll(this.scheduleComputeSourceMap());
|
44 | this._disposables.pushAll(this.scheduleTransformations());
|
45 | if (!props.isMirror) {
|
46 | this._disposables.pushAll(this.scheduleValidateSourceNode());
|
47 | this._disposables.pushAll(this.scheduleResolveSourceNode(props.resolveEagerly));
|
48 | }
|
49 | const sourceNodeDataHandler = (op) => {
|
50 | const node = this.graph.getNodeById(op.id);
|
51 | if (!node) {
|
52 | console.debug(`${dom_1.GraphOp[op.op]} node with id ${op.id} not found.`);
|
53 | return;
|
54 | }
|
55 | this.notifier.emit(notifier_1.GraphiteEvent.DidChangeSourceNode, {
|
56 | node: node.dehydrate(),
|
57 | change: op,
|
58 | });
|
59 | };
|
60 | this._disposables.pushAll([
|
61 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, sourceNodeDataHandler),
|
62 | this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, sourceNodeDataHandler),
|
63 | ]);
|
64 | this._disposables.push(errorReporter_1.errorReporter.onError(result => {
|
65 | this.notifier.emit(notifier_1.GraphiteEvent.DidError, result);
|
66 | }));
|
67 | }
|
68 | registerPlugins(...plugins) {
|
69 | const disposables = new lifecycle_1.DisposableCollection();
|
70 | plugins.forEach(plugin => {
|
71 | plugin.tasks.forEach(task => {
|
72 | disposables.push(this.scheduler.registerHandler(task.operation, task.handler));
|
73 | });
|
74 | if (plugin.specProvider) {
|
75 | disposables.push(specProviderRegistry_1.registry.register(plugin.specProvider));
|
76 | }
|
77 | });
|
78 | return disposables;
|
79 | }
|
80 | scheduleTransformations() {
|
81 | return [
|
82 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, ({ id, prop, trace = {}, previousValue }) => {
|
83 | if (prop === 'spec') {
|
84 | this.scheduler.queue({
|
85 | op: scheduler_1.GraphTaskOp.TransformParsed,
|
86 | nodeId: id,
|
87 | trace,
|
88 | });
|
89 | }
|
90 | else if (prop === 'data.resolved') {
|
91 | this.scheduler.queue({
|
92 | op: scheduler_1.GraphTaskOp.TransformParsed,
|
93 | nodeId: id,
|
94 | trace,
|
95 | oldValue: previousValue,
|
96 | });
|
97 | }
|
98 | }),
|
99 | this.notifier.on(notifier_1.GraphiteEvent.DidUpdateSourceMapNodeResolved, ({ id, oldValue, trace }) => {
|
100 | this.scheduler.queue({
|
101 | op: scheduler_1.GraphTaskOp.TransformParsed,
|
102 | nodeId: id,
|
103 | trace,
|
104 | oldValue,
|
105 | });
|
106 | }),
|
107 | ];
|
108 | }
|
109 | scheduleDeserialize() {
|
110 | const handler = (op) => {
|
111 | const { id, prop, trace = {} } = op;
|
112 | if (prop !== 'data.raw' && prop !== 'data.original' && prop !== 'data.parsed')
|
113 | return;
|
114 | this.scheduler
|
115 | .queue({
|
116 | op: scheduler_1.GraphTaskOp.DeserializeSourceNode,
|
117 | nodeId: id,
|
118 | trace,
|
119 | recomputeOnly: prop === 'data.parsed',
|
120 | })
|
121 | .then(() => {
|
122 | this.notifier.emit(notifier_1.GraphiteEvent.DidPatchSourceNodePropComplete, op);
|
123 | });
|
124 | };
|
125 | return [
|
126 | this.notifier.on(notifier_1.GraphiteEvent.DidAddNode, ({ node, trace = {} }) => {
|
127 | if (node.category !== nodes_1.NodeCategory.Source || !node.data || !node.data.raw)
|
128 | return;
|
129 | this.scheduler.queue({
|
130 | op: scheduler_1.GraphTaskOp.DeserializeSourceNode,
|
131 | nodeId: node.id,
|
132 | trace,
|
133 | });
|
134 | }),
|
135 | this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, handler),
|
136 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, handler),
|
137 | ];
|
138 | }
|
139 | scheduleSerialize() {
|
140 | const handler = ({ id, prop, trace = {} }) => {
|
141 | if (prop !== 'data.parsed' || trace.sourceOp === scheduler_1.GraphTaskOp.DeserializeSourceNode)
|
142 | return;
|
143 | this.scheduler.queue({
|
144 | op: scheduler_1.GraphTaskOp.SerializeSourceNode,
|
145 | nodeId: id,
|
146 | trace,
|
147 | });
|
148 | };
|
149 | return [
|
150 | this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, handler),
|
151 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, handler),
|
152 | ];
|
153 | }
|
154 | scheduleComputeSourceMap() {
|
155 | return [
|
156 | this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, ({ id, prop, trace = {}, value }) => {
|
157 | if (prop !== 'data.parsed')
|
158 | return;
|
159 | this.scheduler.queue({
|
160 | op: scheduler_1.GraphTaskOp.ComputeSourceMap,
|
161 | nodeId: id,
|
162 | patch: value,
|
163 | trace,
|
164 | });
|
165 | }),
|
166 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, ({ id, prop, trace = {}, value }) => {
|
167 | if (prop !== 'data.parsed')
|
168 | return;
|
169 | this.scheduler.queue({
|
170 | op: scheduler_1.GraphTaskOp.ComputeSourceMap,
|
171 | nodeId: id,
|
172 | trace,
|
173 | });
|
174 | }),
|
175 | this.notifier.on(notifier_1.GraphiteEvent.DidAddNode, ({ node, trace }) => {
|
176 | if (node.category !== nodes_1.NodeCategory.Source || !node.data || !node.data.parsed)
|
177 | return;
|
178 | this.scheduler.queue({
|
179 | op: scheduler_1.GraphTaskOp.ComputeSourceMap,
|
180 | nodeId: node.id,
|
181 | trace,
|
182 | });
|
183 | }),
|
184 | ];
|
185 | }
|
186 | scheduleResolveSourceNode(eager) {
|
187 | const disposables = [
|
188 | this.scheduler.registerHandler(scheduler_1.GraphTaskOp.ResolveSourceNode, taskHandler_1.createTaskHandler({
|
189 | selector: node => node.category === nodes_1.NodeCategory.Source,
|
190 | run: scheduler_1.resolveSourceNodeHandler,
|
191 | }, 'resolver-handler')),
|
192 | ];
|
193 | const isCustomized = Array.isArray(eager) && eager.length > 0;
|
194 | const shouldResolve = isCustomized
|
195 | ? (id) => {
|
196 | const node = this.graph.getNodeById(id);
|
197 | return (node !== void 0 &&
|
198 | node.category === nodes_1.NodeCategory.Source &&
|
199 | node.spec !== void 0 &&
|
200 | eager.includes(node.spec));
|
201 | }
|
202 | : null;
|
203 | if (eager !== false || isCustomized) {
|
204 | const scheduleResolving = ({ id, trace = {} }) => {
|
205 | return this.scheduler.queue({
|
206 | op: scheduler_1.GraphTaskOp.ResolveSourceNode,
|
207 | nodeId: id,
|
208 | trace,
|
209 | });
|
210 | };
|
211 | const handler = (op) => {
|
212 | if (op.prop !== 'data.parsed' || (shouldResolve !== null && !shouldResolve(op.id)))
|
213 | return;
|
214 | return scheduleResolving(op);
|
215 | };
|
216 | disposables.push(this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, handler), this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, handler));
|
217 | if (isCustomized) {
|
218 | disposables.push(this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, op => {
|
219 | if (op.prop !== 'spec')
|
220 | return;
|
221 | const node = this.graph.getNodeById(op.id);
|
222 | if (node === void 0 || node.category !== nodes_1.NodeCategory.Source) {
|
223 | throw new Error('Invalid node given');
|
224 | }
|
225 | if (node.data.resolved !== void 0) {
|
226 | return;
|
227 | }
|
228 | return scheduleResolving(op);
|
229 | }));
|
230 | }
|
231 | }
|
232 | return disposables;
|
233 | }
|
234 | scheduleValidateSourceNode() {
|
235 | const handler = ({ id, prop, trace = {} }) => {
|
236 | if (prop !== 'data.parsed')
|
237 | return;
|
238 | this.scheduler.queue({
|
239 | op: scheduler_1.GraphTaskOp.ValidateSourceNode,
|
240 | nodeId: id,
|
241 | trace,
|
242 | });
|
243 | };
|
244 | return [
|
245 | this.notifier.on(notifier_1.GraphiteEvent.DidSetSourceNodeProp, handler),
|
246 | this.notifier.on(notifier_1.GraphiteEvent.DidPatchSourceNodeProp, handler),
|
247 | ];
|
248 | }
|
249 | }
|
250 |
|
\ | No newline at end of file |