@platformos/platformos-graph 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/getWebComponentMap.js +1 -1
- package/dist/getWebComponentMap.js.map +1 -1
- package/dist/graph/augment.js +0 -3
- package/dist/graph/augment.js.map +1 -1
- package/dist/graph/build.d.ts +2 -2
- package/dist/graph/build.js +11 -8
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/module.d.ts +6 -9
- package/dist/graph/module.js +53 -117
- package/dist/graph/module.js.map +1 -1
- package/dist/graph/serialize.d.ts +2 -2
- package/dist/graph/serialize.js +2 -2
- package/dist/graph/serialize.js.map +1 -1
- package/dist/graph/test-helpers.d.ts +0 -13
- package/dist/graph/test-helpers.js +0 -10
- package/dist/graph/test-helpers.js.map +1 -1
- package/dist/graph/traverse.d.ts +3 -3
- package/dist/graph/traverse.js +19 -349
- package/dist/graph/traverse.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/toSourceCode.d.ts +1 -4
- package/dist/toSourceCode.js +8 -52
- package/dist/toSourceCode.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +21 -78
- package/dist/types.js.map +1 -1
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.js +0 -18
- package/dist/utils/index.js.map +1 -1
- package/fixtures/skeleton/{layout/theme.liquid → app/views/layouts/application.liquid} +3 -4
- package/fixtures/skeleton/app/views/pages/index.liquid +5 -0
- package/fixtures/skeleton/app/views/partials/header.liquid +3 -0
- package/package.json +7 -7
- package/src/getWebComponentMap.ts +1 -1
- package/src/graph/augment.ts +1 -13
- package/src/graph/build.spec.ts +31 -171
- package/src/graph/build.ts +18 -14
- package/src/graph/module.ts +59 -135
- package/src/graph/serialize.spec.ts +22 -29
- package/src/graph/serialize.ts +2 -2
- package/src/graph/test-helpers.ts +1 -18
- package/src/graph/traverse.ts +28 -501
- package/src/index.ts +3 -3
- package/src/toSourceCode.ts +14 -55
- package/src/types.ts +23 -100
- package/src/utils/index.ts +0 -24
- package/fixtures/skeleton/blocks/_private.liquid +0 -1
- package/fixtures/skeleton/blocks/_static.liquid +0 -10
- package/fixtures/skeleton/blocks/group.liquid +0 -27
- package/fixtures/skeleton/blocks/render-static.liquid +0 -22
- package/fixtures/skeleton/blocks/text.liquid +0 -14
- package/fixtures/skeleton/jsconfig.json +0 -9
- package/fixtures/skeleton/sections/custom-section.liquid +0 -6
- package/fixtures/skeleton/sections/header-group.json +0 -36
- package/fixtures/skeleton/sections/header.liquid +0 -1
- package/fixtures/skeleton/templates/index.json +0 -20
package/src/graph/traverse.ts
CHANGED
|
@@ -1,56 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
JSONNode,
|
|
4
|
-
nodeAtPath,
|
|
5
|
-
ObjectNode,
|
|
6
|
-
parseJSON,
|
|
7
|
-
path,
|
|
8
|
-
Preset,
|
|
9
|
-
Section,
|
|
10
|
-
SectionSchema,
|
|
11
|
-
SourceCodeType,
|
|
12
|
-
Template,
|
|
13
|
-
ThemeBlock,
|
|
14
|
-
ThemeBlockSchema,
|
|
15
|
-
visit,
|
|
16
|
-
Visitor,
|
|
17
|
-
} from '@platformos/platformos-check-common';
|
|
1
|
+
import { NodeTypes } from '@platformos/liquid-html-parser';
|
|
2
|
+
import { SourceCodeType, visit, Visitor } from '@platformos/platformos-check-common';
|
|
18
3
|
import {
|
|
19
4
|
AugmentedDependencies,
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
AppGraph,
|
|
6
|
+
AppModule,
|
|
22
7
|
LiquidModule,
|
|
23
|
-
LiquidModuleKind,
|
|
24
8
|
ModuleType,
|
|
25
9
|
Range,
|
|
26
10
|
Reference,
|
|
27
|
-
ThemeGraph,
|
|
28
|
-
ThemeModule,
|
|
29
11
|
Void,
|
|
30
12
|
} from '../types';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
getAssetModule,
|
|
34
|
-
getLayoutModule,
|
|
35
|
-
getSectionGroupModule,
|
|
36
|
-
getSectionModule,
|
|
37
|
-
getPartialModule,
|
|
38
|
-
getThemeBlockModule,
|
|
39
|
-
} from './module';
|
|
13
|
+
import { assertNever, exists, isString } from '../utils';
|
|
14
|
+
import { getAssetModule, getLayoutModule, getPartialModule } from './module';
|
|
40
15
|
|
|
41
16
|
export async function traverseModule(
|
|
42
|
-
module:
|
|
43
|
-
|
|
17
|
+
module: AppModule,
|
|
18
|
+
appGraph: AppGraph,
|
|
44
19
|
deps: AugmentedDependencies,
|
|
45
20
|
): Promise<Void> {
|
|
46
21
|
// If the module is already traversed, skip it
|
|
47
|
-
if (
|
|
22
|
+
if (appGraph.modules[module.uri]) {
|
|
48
23
|
return;
|
|
49
24
|
}
|
|
50
25
|
|
|
51
26
|
// Signal to all users that the file is being traversed
|
|
52
27
|
// This will prevent multiple traversals of the same file
|
|
53
|
-
|
|
28
|
+
appGraph.modules[module.uri] = module;
|
|
54
29
|
|
|
55
30
|
// Check if the module exists on disk
|
|
56
31
|
module.exists = await exists(deps.fs, module.uri);
|
|
@@ -62,21 +37,11 @@ export async function traverseModule(
|
|
|
62
37
|
|
|
63
38
|
switch (module.type) {
|
|
64
39
|
case ModuleType.Liquid: {
|
|
65
|
-
return traverseLiquidModule(module,
|
|
40
|
+
return traverseLiquidModule(module, appGraph, deps);
|
|
66
41
|
}
|
|
67
42
|
|
|
68
|
-
case ModuleType.
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
case ModuleType.JavaScript: {
|
|
73
|
-
return; // TODO graph import/exports ?
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
case ModuleType.Css:
|
|
77
|
-
case ModuleType.Svg:
|
|
78
|
-
case ModuleType.Image: {
|
|
79
|
-
return; // Nothing to do??
|
|
43
|
+
case ModuleType.Asset: {
|
|
44
|
+
return; // Nothing to traverse in assets
|
|
80
45
|
}
|
|
81
46
|
|
|
82
47
|
default: {
|
|
@@ -87,7 +52,7 @@ export async function traverseModule(
|
|
|
87
52
|
|
|
88
53
|
async function traverseLiquidModule(
|
|
89
54
|
module: LiquidModule,
|
|
90
|
-
|
|
55
|
+
appGraph: AppGraph,
|
|
91
56
|
deps: AugmentedDependencies,
|
|
92
57
|
) {
|
|
93
58
|
const sourceCode = await deps.getSourceCode(module.uri);
|
|
@@ -96,7 +61,7 @@ async function traverseLiquidModule(
|
|
|
96
61
|
|
|
97
62
|
const visitor: Visitor<
|
|
98
63
|
SourceCodeType.LiquidHtml,
|
|
99
|
-
{ target:
|
|
64
|
+
{ target: AppModule; sourceRange: Range; targetRange?: Range }
|
|
100
65
|
> = {
|
|
101
66
|
// {{ 'theme.js' | asset_url }}
|
|
102
67
|
// {{ 'image.png' | asset_img_url }}
|
|
@@ -108,33 +73,15 @@ async function traverseLiquidModule(
|
|
|
108
73
|
if (parentNode.expression.type !== NodeTypes.String) return;
|
|
109
74
|
if (parentNode.filters[0] !== node) return;
|
|
110
75
|
const asset = parentNode.expression.value;
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
76
|
+
const assetModule = getAssetModule(appGraph, asset);
|
|
77
|
+
if (!assetModule) return;
|
|
113
78
|
return {
|
|
114
|
-
target:
|
|
79
|
+
target: assetModule,
|
|
115
80
|
sourceRange: [parentNode.position.start, parentNode.position.end],
|
|
116
81
|
};
|
|
117
82
|
}
|
|
118
83
|
},
|
|
119
84
|
|
|
120
|
-
// {% content_for 'block', type: 'staticBlockName', id: 'id' %}
|
|
121
|
-
ContentForMarkup: async (node, ancestors) => {
|
|
122
|
-
const parentNode = ancestors.at(-1)!;
|
|
123
|
-
if (node.contentForType.value !== 'block') return;
|
|
124
|
-
const blockTypeArg = node.args.find((arg) => arg.name === 'type');
|
|
125
|
-
if (!blockTypeArg) return;
|
|
126
|
-
|
|
127
|
-
const blockTypeValue = blockTypeArg.value;
|
|
128
|
-
if (blockTypeValue.type !== NodeTypes.String) return;
|
|
129
|
-
|
|
130
|
-
const blockType = blockTypeValue.value;
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
target: getThemeBlockModule(themeGraph, blockType),
|
|
134
|
-
sourceRange: [parentNode.position.start, node.position.end],
|
|
135
|
-
};
|
|
136
|
-
},
|
|
137
|
-
|
|
138
85
|
// <custom-element></custom-element>
|
|
139
86
|
HtmlElement: async (node) => {
|
|
140
87
|
if (node.name.length !== 1) return;
|
|
@@ -146,11 +93,11 @@ async function traverseLiquidModule(
|
|
|
146
93
|
const result = deps.getWebComponentDefinitionReference(nodeName);
|
|
147
94
|
if (!result) return;
|
|
148
95
|
const { assetName, range } = result;
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
96
|
+
const assetModule = getAssetModule(appGraph, assetName);
|
|
97
|
+
if (!assetModule) return;
|
|
151
98
|
|
|
152
99
|
return {
|
|
153
|
-
target:
|
|
100
|
+
target: assetModule,
|
|
154
101
|
sourceRange: [node.blockStartPosition.start, nodeNameNode.position.end],
|
|
155
102
|
targetRange: range,
|
|
156
103
|
};
|
|
@@ -162,37 +109,11 @@ async function traverseLiquidModule(
|
|
|
162
109
|
const tag = ancestors.at(-1)!;
|
|
163
110
|
if (!isString(snippet) && snippet.type === NodeTypes.String) {
|
|
164
111
|
return {
|
|
165
|
-
target: getPartialModule(
|
|
112
|
+
target: getPartialModule(appGraph, snippet.value),
|
|
166
113
|
sourceRange: [tag.position.start, tag.position.end],
|
|
167
114
|
};
|
|
168
115
|
}
|
|
169
116
|
},
|
|
170
|
-
|
|
171
|
-
LiquidTag: async (node) => {
|
|
172
|
-
switch (node.name) {
|
|
173
|
-
// {% sections 'section-group' %}
|
|
174
|
-
case NamedTags.sections: {
|
|
175
|
-
if (!isString(node.markup)) {
|
|
176
|
-
const sectionGroupType = node.markup.value;
|
|
177
|
-
return {
|
|
178
|
-
target: getSectionGroupModule(themeGraph, sectionGroupType),
|
|
179
|
-
sourceRange: [node.position.start, node.position.end],
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// {% section 'section' %}
|
|
185
|
-
case NamedTags.section: {
|
|
186
|
-
if (!isString(node.markup)) {
|
|
187
|
-
const sectionType = node.markup.value;
|
|
188
|
-
return {
|
|
189
|
-
target: getSectionModule(themeGraph, sectionType),
|
|
190
|
-
sourceRange: [node.position.start, node.position.end],
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
117
|
};
|
|
197
118
|
|
|
198
119
|
const references = await visit(sourceCode.ast, visitor);
|
|
@@ -205,407 +126,13 @@ async function traverseLiquidModule(
|
|
|
205
126
|
}
|
|
206
127
|
|
|
207
128
|
const modules = unique(references.map((ref) => ref.target));
|
|
208
|
-
const promises = modules.map((mod) => traverseModule(mod,
|
|
209
|
-
|
|
210
|
-
// Look at schema references if any
|
|
211
|
-
if (module.kind === LiquidModuleKind.Section) {
|
|
212
|
-
const sectionName = path.basename(module.uri, '.liquid');
|
|
213
|
-
const sectionSchema = await deps.getSectionSchema(sectionName);
|
|
214
|
-
promises.push(traverseLiquidSchema(sectionSchema, module, themeGraph, deps));
|
|
215
|
-
} else if (module.kind === LiquidModuleKind.Block) {
|
|
216
|
-
const blockName = path.basename(module.uri, '.liquid');
|
|
217
|
-
const blockSchema = await deps.getBlockSchema(blockName);
|
|
218
|
-
promises.push(traverseLiquidSchema(blockSchema, module, themeGraph, deps));
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return Promise.all(promises);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async function traverseLiquidSchema(
|
|
225
|
-
schema: SectionSchema | ThemeBlockSchema | undefined,
|
|
226
|
-
module: LiquidModule,
|
|
227
|
-
themeGraph: ThemeGraph,
|
|
228
|
-
deps: AugmentedDependencies,
|
|
229
|
-
): Promise<Void> {
|
|
230
|
-
if (!schema) return;
|
|
231
|
-
|
|
232
|
-
const isSection = module.kind === LiquidModuleKind.Section;
|
|
233
|
-
const hasLocalBlocks =
|
|
234
|
-
isSection && (await acceptsLocalBlocks(path.basename(module.uri, '.liquid'), deps));
|
|
235
|
-
if (hasLocalBlocks) return;
|
|
236
|
-
|
|
237
|
-
const { ast, validSchema } = schema;
|
|
238
|
-
if (validSchema instanceof Error || ast instanceof Error) return;
|
|
239
|
-
|
|
240
|
-
const promises: Promise<Void>[] = [];
|
|
241
|
-
|
|
242
|
-
// Traverse the blocks
|
|
243
|
-
if (validSchema.blocks) {
|
|
244
|
-
promises.push(traverseSchemaBlocks(schema, module, ast, validSchema.blocks, themeGraph, deps));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Traverse the presets
|
|
248
|
-
if (validSchema.presets) {
|
|
249
|
-
promises.push(
|
|
250
|
-
traverseSchemaPresets(schema, module, ast, validSchema.presets, themeGraph, deps),
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Traverse section.default if it exists
|
|
255
|
-
if ('default' in validSchema && validSchema.default) {
|
|
256
|
-
promises.push(
|
|
257
|
-
traverseSchemaDefault(
|
|
258
|
-
schema as SectionSchema,
|
|
259
|
-
module,
|
|
260
|
-
ast,
|
|
261
|
-
validSchema.default,
|
|
262
|
-
themeGraph,
|
|
263
|
-
deps,
|
|
264
|
-
),
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return Promise.all(promises);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async function traverseSchemaBlocks(
|
|
272
|
-
schema: SectionSchema | ThemeBlockSchema,
|
|
273
|
-
module: LiquidModule,
|
|
274
|
-
ast: JSONNode,
|
|
275
|
-
blocks: Section.Block[] | ThemeBlock.Block[],
|
|
276
|
-
themeGraph: ThemeGraph,
|
|
277
|
-
deps: AugmentedDependencies,
|
|
278
|
-
) {
|
|
279
|
-
const promises: Promise<Void>[] = [];
|
|
280
|
-
|
|
281
|
-
for (const [i, blockDef] of Object.entries(blocks)) {
|
|
282
|
-
const nodePath = ['blocks', i];
|
|
283
|
-
const node = nodeAtPath(ast, nodePath)! as ObjectNode;
|
|
284
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type');
|
|
285
|
-
if (!typeProperty) continue;
|
|
286
|
-
|
|
287
|
-
const sourceRange: Range = [
|
|
288
|
-
schema.offset + typeProperty.loc.start.offset,
|
|
289
|
-
schema.offset + typeProperty.loc.end.offset,
|
|
290
|
-
];
|
|
291
|
-
|
|
292
|
-
// blocks: [{ "type": "@theme" }, { "type": "custom-block" }]
|
|
293
|
-
switch (blockDef.type) {
|
|
294
|
-
case '@theme': {
|
|
295
|
-
const publicBlocks = await deps
|
|
296
|
-
.getThemeBlockNames()
|
|
297
|
-
.then((blocks) => blocks.filter((name) => !name.startsWith('_')));
|
|
298
|
-
for (const publicBlock of publicBlocks) {
|
|
299
|
-
const blockModule = getThemeBlockModule(
|
|
300
|
-
themeGraph,
|
|
301
|
-
path.basename(publicBlock, '.liquid'),
|
|
302
|
-
);
|
|
303
|
-
bind(module, blockModule, { sourceRange, type: 'indirect' });
|
|
304
|
-
promises.push(traverseModule(blockModule, themeGraph, deps));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
case '@app': {
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
default: {
|
|
315
|
-
const blockModule = getThemeBlockModule(themeGraph, blockDef.type);
|
|
316
|
-
bind(module, blockModule, { sourceRange });
|
|
317
|
-
promises.push(traverseModule(blockModule, themeGraph, deps));
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return Promise.all(promises);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
async function traverseSchemaPresets(
|
|
326
|
-
schema: SectionSchema | ThemeBlockSchema,
|
|
327
|
-
module: LiquidModule,
|
|
328
|
-
ast: JSONNode,
|
|
329
|
-
presets: Preset.Preset[],
|
|
330
|
-
themeGraph: ThemeGraph,
|
|
331
|
-
deps: AugmentedDependencies,
|
|
332
|
-
) {
|
|
333
|
-
const promises: Promise<Void>[] = [];
|
|
334
|
-
|
|
335
|
-
for (const [i, preset] of presets.entries()) {
|
|
336
|
-
if (!('blocks' in preset)) continue;
|
|
337
|
-
|
|
338
|
-
// Iterate over array entries or object entries depending on how the blocks are defined
|
|
339
|
-
const iterator = Array.isArray(preset.blocks)
|
|
340
|
-
? preset.blocks.entries()
|
|
341
|
-
: Object.entries(preset.blocks!);
|
|
342
|
-
|
|
343
|
-
for (const [keyOrIndex, block] of iterator) {
|
|
344
|
-
const nodePath = ['presets', i, 'blocks', keyOrIndex];
|
|
345
|
-
const node = nodeAtPath(ast, nodePath)! as ObjectNode;
|
|
346
|
-
|
|
347
|
-
const blockModule = getThemeBlockModule(themeGraph, block.type);
|
|
348
|
-
if (!blockModule) continue;
|
|
349
|
-
|
|
350
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type');
|
|
351
|
-
if (!typeProperty) continue;
|
|
352
|
-
|
|
353
|
-
const sourceRange: Range = [
|
|
354
|
-
schema.offset + typeProperty.loc.start.offset,
|
|
355
|
-
schema.offset + typeProperty.loc.end.offset,
|
|
356
|
-
];
|
|
357
|
-
|
|
358
|
-
bind(module, blockModule, { sourceRange, type: 'preset' });
|
|
359
|
-
promises.push(traverseModule(blockModule, themeGraph, deps));
|
|
360
|
-
if (block.blocks) {
|
|
361
|
-
promises.push(
|
|
362
|
-
traverseSchemaPresetBlock(schema, module, ast, block.blocks, nodePath, themeGraph, deps),
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
129
|
+
const promises = modules.map((mod) => traverseModule(mod, appGraph, deps));
|
|
367
130
|
|
|
368
131
|
return Promise.all(promises);
|
|
369
132
|
}
|
|
370
133
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
module: LiquidModule,
|
|
374
|
-
ast: JSONNode,
|
|
375
|
-
blocks: Preset.PresetBlockHash | Preset.PresetBlockForArray[],
|
|
376
|
-
parentPath: (string | number)[],
|
|
377
|
-
themeGraph: ThemeGraph,
|
|
378
|
-
deps: AugmentedDependencies,
|
|
379
|
-
) {
|
|
380
|
-
const promises: Promise<Void>[] = [];
|
|
381
|
-
|
|
382
|
-
// Iterate over array entries or object entries depending on how the blocks are defined
|
|
383
|
-
const iterator = Array.isArray(blocks) ? blocks.entries() : Object.entries(blocks);
|
|
384
|
-
|
|
385
|
-
for (const [keyOrIndex, block] of iterator) {
|
|
386
|
-
const nodePath = [...parentPath, 'blocks', keyOrIndex];
|
|
387
|
-
const node = nodeAtPath(ast, nodePath)! as ObjectNode;
|
|
388
|
-
|
|
389
|
-
const blockModule = getThemeBlockModule(themeGraph, block.type);
|
|
390
|
-
if (!blockModule) continue;
|
|
391
|
-
|
|
392
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type');
|
|
393
|
-
if (!typeProperty) continue;
|
|
394
|
-
|
|
395
|
-
const sourceRange: Range = [
|
|
396
|
-
schema.offset + typeProperty.loc.start.offset,
|
|
397
|
-
schema.offset + typeProperty.loc.end.offset,
|
|
398
|
-
];
|
|
399
|
-
|
|
400
|
-
bind(module, blockModule, { sourceRange, type: 'preset' });
|
|
401
|
-
promises.push(traverseModule(blockModule, themeGraph, deps));
|
|
402
|
-
if (block.blocks) {
|
|
403
|
-
promises.push(
|
|
404
|
-
traverseSchemaPresetBlock(schema, module, ast, block.blocks, nodePath, themeGraph, deps),
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return Promise.all(promises);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async function traverseSchemaDefault(
|
|
413
|
-
schema: SectionSchema,
|
|
414
|
-
module: LiquidModule,
|
|
415
|
-
ast: JSONNode,
|
|
416
|
-
preset: Section.Default,
|
|
417
|
-
themeGraph: ThemeGraph,
|
|
418
|
-
deps: AugmentedDependencies,
|
|
419
|
-
) {
|
|
420
|
-
const promises: Promise<Void>[] = [];
|
|
421
|
-
|
|
422
|
-
if (!('blocks' in preset)) return;
|
|
423
|
-
|
|
424
|
-
// Iterate over array entries or object entries depending on how the blocks are defined
|
|
425
|
-
const iterator = Array.isArray(preset.blocks)
|
|
426
|
-
? preset.blocks.entries()
|
|
427
|
-
: Object.entries(preset.blocks!);
|
|
428
|
-
|
|
429
|
-
for (const [keyOrIndex, block] of iterator) {
|
|
430
|
-
const nodePath = ['default', 'blocks', keyOrIndex];
|
|
431
|
-
const node = nodeAtPath(ast, nodePath)! as ObjectNode;
|
|
432
|
-
|
|
433
|
-
const blockModule = getThemeBlockModule(themeGraph, block.type);
|
|
434
|
-
if (!blockModule) continue;
|
|
435
|
-
|
|
436
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type');
|
|
437
|
-
if (!typeProperty) continue;
|
|
438
|
-
|
|
439
|
-
const sourceRange: Range = [
|
|
440
|
-
schema.offset + typeProperty.loc.start.offset,
|
|
441
|
-
schema.offset + typeProperty.loc.end.offset,
|
|
442
|
-
];
|
|
443
|
-
|
|
444
|
-
bind(module, blockModule, { sourceRange, type: 'preset' });
|
|
445
|
-
promises.push(traverseModule(blockModule, themeGraph, deps));
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
return Promise.all(promises);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async function traverseJsonModule(
|
|
452
|
-
module: JsonModule,
|
|
453
|
-
themeGraph: ThemeGraph,
|
|
454
|
-
deps: AugmentedDependencies,
|
|
455
|
-
): Promise<Void> {
|
|
456
|
-
const sourceCode = await deps.getSourceCode(module.uri);
|
|
457
|
-
if (sourceCode.type !== SourceCodeType.JSON) throw unexpected();
|
|
458
|
-
const ast = sourceCode.ast;
|
|
459
|
-
if (ast instanceof Error) return; // can't visit what you can't parse
|
|
460
|
-
|
|
461
|
-
switch (module.kind) {
|
|
462
|
-
case JsonModuleKind.Template: {
|
|
463
|
-
// Should only happen once per template
|
|
464
|
-
const template = parseJSON(sourceCode.source) as Template.Template;
|
|
465
|
-
const promises: Promise<Void>[] = [];
|
|
466
|
-
for (const [key, section] of Object.entries(template.sections)) {
|
|
467
|
-
const sectionType = section.type;
|
|
468
|
-
const path = ['sections', key];
|
|
469
|
-
const node = nodeAtPath(ast, path)! as ObjectNode;
|
|
470
|
-
const sectionModule = getSectionModule(themeGraph, sectionType);
|
|
471
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type')!;
|
|
472
|
-
const start = typeProperty.loc.start.offset;
|
|
473
|
-
const end = typeProperty.loc.end.offset;
|
|
474
|
-
const sourceRange: Range = [start, end];
|
|
475
|
-
// Link the template to the section
|
|
476
|
-
bind(module, sectionModule, { sourceRange });
|
|
477
|
-
promises.push(
|
|
478
|
-
// Traverse the section themeselves
|
|
479
|
-
traverseModule(sectionModule, themeGraph, deps),
|
|
480
|
-
// Link the blocks used in the section to the template
|
|
481
|
-
traverseSectionReferences(module, ast, path, section, themeGraph, deps),
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// Link the template to the layout
|
|
486
|
-
const layout = template.layout;
|
|
487
|
-
const layoutModule = getLayoutModule(themeGraph, template.layout);
|
|
488
|
-
if (layoutModule) {
|
|
489
|
-
let sourceRange: Range | undefined = undefined;
|
|
490
|
-
let indirect = true;
|
|
491
|
-
if (layout !== false && layout !== undefined) {
|
|
492
|
-
const layoutPath = ['layout'];
|
|
493
|
-
const node = nodeAtPath(ast, layoutPath)!;
|
|
494
|
-
sourceRange = [node.loc.start.offset, node.loc.end.offset];
|
|
495
|
-
indirect = false; // this is a direct reference to the layout
|
|
496
|
-
}
|
|
497
|
-
bind(module, layoutModule, { sourceRange, type: 'indirect' });
|
|
498
|
-
promises.push(traverseModule(layoutModule, themeGraph, deps));
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return Promise.all(promises);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
case JsonModuleKind.SectionGroup: {
|
|
505
|
-
const sectionGroup = parseJSON(sourceCode.source) as Template.SectionGroup;
|
|
506
|
-
const promises: Promise<Void>[] = [];
|
|
507
|
-
for (const [key, section] of Object.entries(sectionGroup.sections)) {
|
|
508
|
-
const sectionType = section.type;
|
|
509
|
-
const path = ['sections', key];
|
|
510
|
-
const node = nodeAtPath(ast, path)! as ObjectNode;
|
|
511
|
-
const sectionModule = getSectionModule(themeGraph, sectionType);
|
|
512
|
-
|
|
513
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type')!;
|
|
514
|
-
const start = typeProperty.loc.start.offset;
|
|
515
|
-
const end = typeProperty.loc.end.offset;
|
|
516
|
-
const sourceRange: Range = [start, end];
|
|
517
|
-
|
|
518
|
-
// Link the template to the section
|
|
519
|
-
bind(module, sectionModule, { sourceRange });
|
|
520
|
-
promises.push(
|
|
521
|
-
// Traverse the section themeselves
|
|
522
|
-
traverseModule(sectionModule, themeGraph, deps),
|
|
523
|
-
// Link the blocks used in the section to the template
|
|
524
|
-
traverseSectionReferences(module, ast, path, section, themeGraph, deps),
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return Promise.all(promises);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
default: {
|
|
532
|
-
return assertNever(module.kind);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Traverses the actual references contained inside Template.Template['sections'] and Template.SectionGroup['sections'].
|
|
539
|
-
*
|
|
540
|
-
* Does nothing if the mode is not `GraphMode.Production`.
|
|
541
|
-
*/
|
|
542
|
-
async function traverseSectionReferences(
|
|
543
|
-
source: ThemeModule, // template or section group
|
|
544
|
-
sourceAst: JSONNode,
|
|
545
|
-
nodePath: string[] = [],
|
|
546
|
-
section: Template.Section,
|
|
547
|
-
themeGraph: ThemeGraph,
|
|
548
|
-
deps: AugmentedDependencies,
|
|
549
|
-
): Promise<Void> {
|
|
550
|
-
if (!section.blocks) return;
|
|
551
|
-
const sectionHasLocalBlocks = await acceptsLocalBlocks(section.type, deps);
|
|
552
|
-
if (sectionHasLocalBlocks) return;
|
|
553
|
-
|
|
554
|
-
const promises: Promise<Void>[] = [];
|
|
555
|
-
|
|
556
|
-
for (const [key, block] of Object.entries(section.blocks)) {
|
|
557
|
-
const blockType = block.type;
|
|
558
|
-
const blockModule = getThemeBlockModule(themeGraph, blockType);
|
|
559
|
-
const path = [...nodePath, 'blocks', key];
|
|
560
|
-
const node = nodeAtPath(sourceAst, path)! as ObjectNode;
|
|
561
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type')!;
|
|
562
|
-
const start = typeProperty.loc.start.offset;
|
|
563
|
-
const end = typeProperty.loc.end.offset;
|
|
564
|
-
const sourceRange: Range = [start, end];
|
|
565
|
-
// Link the template to the block
|
|
566
|
-
bind(source, blockModule, { sourceRange });
|
|
567
|
-
promises.push(
|
|
568
|
-
// Traverse the block themselves
|
|
569
|
-
traverseModule(blockModule, themeGraph, deps),
|
|
570
|
-
// Traverse the block references
|
|
571
|
-
traverseBlockReferences(source, sourceAst, path, block, themeGraph, deps),
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
return Promise.all(promises);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
async function traverseBlockReferences(
|
|
579
|
-
source: ThemeModule, // template or section group
|
|
580
|
-
sourceAst: JSONNode,
|
|
581
|
-
nodePath: string[] = [],
|
|
582
|
-
block: Template.Block,
|
|
583
|
-
themeGraph: ThemeGraph,
|
|
584
|
-
deps: AugmentedDependencies,
|
|
585
|
-
): Promise<Void> {
|
|
586
|
-
if (!block.blocks) return;
|
|
587
|
-
|
|
588
|
-
const promises: Promise<Void>[] = [];
|
|
589
|
-
for (const [key, childBlock] of Object.entries(block.blocks)) {
|
|
590
|
-
const childBlockType = childBlock.type;
|
|
591
|
-
const childBlockModule = getThemeBlockModule(themeGraph, childBlockType);
|
|
592
|
-
const path = [...nodePath, 'blocks', key];
|
|
593
|
-
const node = nodeAtPath(sourceAst, path)! as ObjectNode;
|
|
594
|
-
const typeProperty = node.children.find((child) => child.key.value === 'type')!;
|
|
595
|
-
const start = typeProperty.loc.start.offset;
|
|
596
|
-
const end = typeProperty.loc.end.offset;
|
|
597
|
-
const sourceRange: Range = [start, end];
|
|
598
|
-
// Link the template/section group to the block
|
|
599
|
-
bind(source, childBlockModule, { sourceRange });
|
|
600
|
-
promises.push(
|
|
601
|
-
// Traverse the child block themselves
|
|
602
|
-
traverseModule(childBlockModule, themeGraph, deps),
|
|
603
|
-
// Traverse the child block references
|
|
604
|
-
traverseBlockReferences(source, sourceAst, path, childBlock, themeGraph, deps),
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
return Promise.all(promises);
|
|
134
|
+
function unique<T>(arr: T[]): T[] {
|
|
135
|
+
return [...new Set(arr)];
|
|
609
136
|
}
|
|
610
137
|
|
|
611
138
|
/**
|
|
@@ -616,12 +143,12 @@ async function traverseBlockReferences(
|
|
|
616
143
|
* This function mutates the source and target modules.
|
|
617
144
|
*/
|
|
618
145
|
export function bind(
|
|
619
|
-
source:
|
|
620
|
-
target:
|
|
146
|
+
source: AppModule,
|
|
147
|
+
target: AppModule,
|
|
621
148
|
{
|
|
622
149
|
sourceRange,
|
|
623
150
|
targetRange,
|
|
624
|
-
type = 'direct', // the type of dependency, can be 'direct'
|
|
151
|
+
type = 'direct', // the type of dependency, can be 'direct' or 'indirect'
|
|
625
152
|
}: {
|
|
626
153
|
sourceRange?: Range; // a range in the source module that references the child
|
|
627
154
|
targetRange?: Range; // a range in the child module that is being referenced
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { buildAppGraph } from './graph/build';
|
|
2
|
+
export { serializeAppGraph } from './graph/serialize';
|
|
3
3
|
export { getWebComponentMap, findWebComponentReferences } from './getWebComponentMap';
|
|
4
|
-
export {
|
|
4
|
+
export { parseJs, toSourceCode } from './toSourceCode';
|
|
5
5
|
export * from './types';
|