@platformos/platformos-graph 0.0.19 → 0.1.0
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 +516 -0
- package/bin/platformos-graph +21 -81
- package/dist/cache-probes.spec.d.ts +1 -0
- package/dist/cache-probes.spec.js +62 -0
- package/dist/cache-probes.spec.js.map +1 -0
- package/dist/cli.d.ts +46 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.spec.d.ts +1 -0
- package/dist/cli.spec.js +235 -0
- package/dist/cli.spec.js.map +1 -0
- package/dist/graph/app-index-resolution.spec.d.ts +1 -0
- package/dist/graph/app-index-resolution.spec.js +167 -0
- package/dist/graph/app-index-resolution.spec.js.map +1 -0
- package/dist/graph/asset-resolution.spec.d.ts +1 -0
- package/dist/graph/asset-resolution.spec.js +64 -0
- package/dist/graph/asset-resolution.spec.js.map +1 -0
- package/dist/graph/augment.js +3 -1
- package/dist/graph/augment.js.map +1 -1
- package/dist/graph/build.d.ts +15 -2
- package/dist/graph/build.js +54 -12
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/build.spec.d.ts +1 -0
- package/dist/graph/build.spec.js +138 -0
- package/dist/graph/build.spec.js.map +1 -0
- package/dist/graph/edge-sources.d.ts +28 -0
- package/dist/graph/edge-sources.js +43 -0
- package/dist/graph/edge-sources.js.map +1 -0
- package/dist/graph/edge-sources.spec.d.ts +1 -0
- package/dist/graph/edge-sources.spec.js +125 -0
- package/dist/graph/edge-sources.spec.js.map +1 -0
- package/dist/graph/extract.spec.d.ts +1 -0
- package/dist/graph/extract.spec.js +163 -0
- package/dist/graph/extract.spec.js.map +1 -0
- package/dist/graph/module.d.ts +70 -2
- package/dist/graph/module.js +164 -29
- package/dist/graph/module.js.map +1 -1
- package/dist/graph/module.spec.d.ts +1 -0
- package/dist/graph/module.spec.js +74 -0
- package/dist/graph/module.spec.js.map +1 -0
- package/dist/graph/query.d.ts +72 -0
- package/dist/graph/query.js +140 -0
- package/dist/graph/query.js.map +1 -0
- package/dist/graph/query.spec.d.ts +1 -0
- package/dist/graph/query.spec.js +209 -0
- package/dist/graph/query.spec.js.map +1 -0
- package/dist/graph/serialize.spec.d.ts +1 -0
- package/dist/graph/serialize.spec.js +50 -0
- package/dist/graph/serialize.spec.js.map +1 -0
- package/dist/graph/structural.spec.d.ts +1 -0
- package/dist/graph/structural.spec.js +146 -0
- package/dist/graph/structural.spec.js.map +1 -0
- package/dist/graph/test-helpers.d.ts +2 -3
- package/dist/graph/test-helpers.js +5 -9
- package/dist/graph/test-helpers.js.map +1 -1
- package/dist/graph/traverse-edges.spec.d.ts +1 -0
- package/dist/graph/traverse-edges.spec.js +337 -0
- package/dist/graph/traverse-edges.spec.js.map +1 -0
- package/dist/graph/traverse.d.ts +63 -4
- package/dist/graph/traverse.js +364 -49
- package/dist/graph/traverse.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +21 -4
- package/dist/index.js.map +1 -1
- package/dist/parsers.d.ts +35 -0
- package/dist/parsers.js +72 -0
- package/dist/parsers.js.map +1 -0
- package/dist/parsers.spec.d.ts +1 -0
- package/dist/parsers.spec.js +70 -0
- package/dist/parsers.spec.js.map +1 -0
- package/dist/toSourceCode.d.ts +14 -2
- package/dist/toSourceCode.js +23 -19
- package/dist/toSourceCode.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +114 -20
- package/dist/types.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/fixtures/asset-edges/app/assets/logo.css +1 -0
- package/fixtures/asset-edges/app/assets/site/app.js +1 -0
- package/fixtures/asset-edges/app/views/pages/index.liquid +3 -0
- package/fixtures/background-edges/app/views/pages/broken.liquid +3 -0
- package/fixtures/background-edges/app/views/pages/index.liquid +3 -0
- package/fixtures/background-edges/app/views/partials/jobs/notify.liquid +3 -0
- package/fixtures/function-edges/app/lib/queries/list.liquid +3 -0
- package/fixtures/function-edges/app/views/pages/broken.liquid +3 -0
- package/fixtures/function-edges/app/views/pages/index.liquid +3 -0
- package/fixtures/graphql-edges/app/graphql/blog_posts/find.graphql +10 -0
- package/fixtures/graphql-edges/app/views/pages/broken.liquid +3 -0
- package/fixtures/graphql-edges/app/views/pages/index.liquid +3 -0
- package/fixtures/graphql-table/app/graphql/with_table.graphql +5 -0
- package/fixtures/graphql-table/app/graphql/without_table.graphql +3 -0
- package/fixtures/graphql-table/app/views/pages/index.liquid +4 -0
- package/fixtures/include-edges/app/views/pages/index.liquid +1 -0
- package/fixtures/include-edges/app/views/partials/shared/header.liquid +1 -0
- package/fixtures/layout-edges/app/views/layouts/theme.liquid +4 -0
- package/fixtures/layout-edges/app/views/pages/broken.liquid +5 -0
- package/fixtures/layout-edges/app/views/pages/index.liquid +5 -0
- package/fixtures/module-edges/app/views/pages/index.liquid +4 -0
- package/fixtures/module-edges/modules/my_module/public/lib/queries/get.liquid +3 -0
- package/fixtures/module-edges/modules/my_module/public/views/partials/card.liquid +1 -0
- package/fixtures/schema-nodes/app/schema/blog_post.yml +6 -0
- package/fixtures/schema-nodes/app/schema/no_name.yml +3 -0
- package/fixtures/schema-nodes/app/views/pages/index.liquid +1 -0
- package/fixtures/skeleton/app/assets/app.js +1 -0
- package/fixtures/skeleton/app/views/partials/child.liquid +2 -4
- package/fixtures/skeleton/app/views/partials/parent.liquid +2 -4
- package/fixtures/structural/app/views/pages/about.liquid +1 -0
- package/fixtures/structural/app/views/pages/blog/show.liquid +4 -0
- package/fixtures/structural/app/views/pages/index.liquid +6 -0
- package/fixtures/structural/app/views/pages/rich.liquid +8 -0
- package/fixtures/structural/app/views/partials/card.liquid +1 -0
- package/fixtures/structural/app/views/partials/documented.liquid +5 -0
- package/package.json +7 -5
- package/src/cli.spec.ts +271 -0
- package/src/cli.ts +167 -0
- package/src/graph/augment.ts +4 -2
- package/src/graph/build.spec.ts +888 -9
- package/src/graph/build.ts +68 -17
- package/src/graph/edge-sources.spec.ts +125 -0
- package/src/graph/edge-sources.ts +49 -0
- package/src/graph/module.spec.ts +168 -0
- package/src/graph/module.ts +167 -33
- package/src/graph/query.spec.ts +260 -0
- package/src/graph/query.ts +154 -0
- package/src/graph/serialize.spec.ts +4 -4
- package/src/graph/test-helpers.ts +5 -12
- package/src/graph/traverse.spec.ts +278 -0
- package/src/graph/traverse.ts +423 -54
- package/src/index.ts +16 -1
- package/src/parsers.spec.ts +85 -0
- package/src/parsers.ts +75 -0
- package/src/toSourceCode.ts +26 -26
- package/src/types.ts +120 -23
- package/src/utils/index.ts +1 -1
- package/bin/jsconfig.json +0 -18
- package/dist/getWebComponentMap.d.ts +0 -10
- package/dist/getWebComponentMap.js +0 -66
- package/dist/getWebComponentMap.js.map +0 -1
- package/fixtures/skeleton/assets/app.js +0 -7
- package/src/getWebComponentMap.ts +0 -81
- /package/fixtures/skeleton/{assets → app/assets}/app.css +0 -0
|
@@ -1,34 +1,27 @@
|
|
|
1
1
|
import { memoize, path as pathUtils } from '@platformos/platformos-check-common';
|
|
2
|
-
import { AbstractFileSystem } from '@platformos/platformos-common';
|
|
2
|
+
import { AbstractFileSystem, uriFromPath } from '@platformos/platformos-common';
|
|
3
3
|
import { NodeFileSystem } from '@platformos/platformos-check-node';
|
|
4
4
|
import { vi } from 'vitest';
|
|
5
5
|
import { URI } from 'vscode-uri';
|
|
6
|
-
import { getWebComponentMap } from '../getWebComponentMap';
|
|
7
6
|
import { toSourceCode } from '../toSourceCode';
|
|
8
7
|
import { identity } from '../utils';
|
|
9
8
|
|
|
10
9
|
export function makeGetSourceCode(fs: AbstractFileSystem) {
|
|
11
10
|
return memoize(async function getSourceCode(uri: string) {
|
|
12
11
|
const source = await fs.readFile(uri);
|
|
13
|
-
return toSourceCode(
|
|
12
|
+
return toSourceCode(pathUtils.toUri(uri), source);
|
|
14
13
|
}, identity);
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
export const fixturesRoot = pathUtils.join(
|
|
16
|
+
export const fixturesRoot = pathUtils.join(uriFromPath(__dirname), ...'../../fixtures'.split('/'));
|
|
18
17
|
export const skeleton = pathUtils.join(fixturesRoot, 'skeleton');
|
|
19
18
|
|
|
20
|
-
export
|
|
19
|
+
export function getDependencies(fs: AbstractFileSystem = NodeFileSystem) {
|
|
21
20
|
const getSourceCode = makeGetSourceCode(fs);
|
|
22
|
-
|
|
21
|
+
return {
|
|
23
22
|
fs,
|
|
24
23
|
getSourceCode,
|
|
25
|
-
getWebComponentDefinitionReference: (customElementName: string) =>
|
|
26
|
-
webComponentDefs.get(customElementName),
|
|
27
24
|
};
|
|
28
|
-
|
|
29
|
-
const webComponentDefs = await getWebComponentMap(rootUri, deps);
|
|
30
|
-
|
|
31
|
-
return deps;
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
// This thing is way too hard to type.
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { path as pathUtils } from '@platformos/platformos-check-common';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { extractFileReferences, extractStructural } from '../index';
|
|
4
|
+
import { toSourceCode } from '../toSourceCode';
|
|
5
|
+
import { ModuleStructural, Reference } from '../types';
|
|
6
|
+
import { fixturesRoot, getDependencies } from './test-helpers';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `extractFileReferences` is the per-file primitive a `validate_code`-style
|
|
10
|
+
* consumer uses: parse an in-flight buffer with `toSourceCode`, then resolve its
|
|
11
|
+
* outgoing dependency edges against the on-disk project — WITHOUT building the
|
|
12
|
+
* whole app graph. The buffer is never read from disk, so these specs pass the
|
|
13
|
+
* content inline (and even use a `sourceUri` for a file that does not exist).
|
|
14
|
+
*/
|
|
15
|
+
const { fs } = getDependencies();
|
|
16
|
+
|
|
17
|
+
/** The exact source range of `snippet` within `source`. */
|
|
18
|
+
function rangeOf(source: string, snippet: string): [number, number] {
|
|
19
|
+
const start = source.indexOf(snippet);
|
|
20
|
+
if (start < 0) throw new Error(`snippet not found: ${snippet}`);
|
|
21
|
+
return [start, start + snippet.length];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function directRef(
|
|
25
|
+
sourceUri: string,
|
|
26
|
+
sourceRange: [number, number],
|
|
27
|
+
targetUri: string,
|
|
28
|
+
kind: Reference['kind'],
|
|
29
|
+
args?: string[],
|
|
30
|
+
): Reference {
|
|
31
|
+
return {
|
|
32
|
+
source: { uri: sourceUri, range: sourceRange },
|
|
33
|
+
target: { uri: targetUri },
|
|
34
|
+
type: 'direct',
|
|
35
|
+
kind,
|
|
36
|
+
...(args ? { args } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function extract(rootUri: string, sourceUri: string, content: string) {
|
|
41
|
+
return extractFileReferences(rootUri, sourceUri, await toSourceCode(sourceUri, content), { fs });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('extractFileReferences: resolves a single buffer against the project', () => {
|
|
45
|
+
const rootUri = pathUtils.join(fixturesRoot, 'function-edges');
|
|
46
|
+
const p = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
47
|
+
|
|
48
|
+
it('resolves a {% function %} edge to the canonical lib URI', async () => {
|
|
49
|
+
const sourceUri = p('app/views/pages/draft.liquid'); // not on disk — in-flight buffer
|
|
50
|
+
const content = `{% liquid
|
|
51
|
+
function items = 'queries/list'
|
|
52
|
+
%}`;
|
|
53
|
+
|
|
54
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
55
|
+
directRef(
|
|
56
|
+
sourceUri,
|
|
57
|
+
rangeOf(content, "function items = 'queries/list'"),
|
|
58
|
+
p('app/lib/queries/list.liquid'),
|
|
59
|
+
'function',
|
|
60
|
+
),
|
|
61
|
+
]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('resolves a target that does not exist on disk (path-based resolution)', async () => {
|
|
65
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
66
|
+
const content = `{% liquid
|
|
67
|
+
function ghost = 'queries/missing'
|
|
68
|
+
%}`;
|
|
69
|
+
|
|
70
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
71
|
+
directRef(
|
|
72
|
+
sourceUri,
|
|
73
|
+
rangeOf(content, "function ghost = 'queries/missing'"),
|
|
74
|
+
p('app/lib/queries/missing.liquid'),
|
|
75
|
+
'function',
|
|
76
|
+
),
|
|
77
|
+
]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('captures the named-argument names at a render call site', async () => {
|
|
81
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
82
|
+
const content = "{% render 'card', title: page.title, count: 3 %}";
|
|
83
|
+
|
|
84
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
85
|
+
directRef(
|
|
86
|
+
sourceUri,
|
|
87
|
+
rangeOf(content, "{% render 'card', title: page.title, count: 3 %}"),
|
|
88
|
+
p('app/views/partials/card.liquid'),
|
|
89
|
+
'render',
|
|
90
|
+
['title', 'count'],
|
|
91
|
+
),
|
|
92
|
+
]);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('extractFileReferences: kinds and resolution match the full graph build', () => {
|
|
97
|
+
it('tags include edges with kind "include"', async () => {
|
|
98
|
+
const rootUri = pathUtils.join(fixturesRoot, 'include-edges');
|
|
99
|
+
const p = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
100
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
101
|
+
const content = "{% include 'shared/header' %}";
|
|
102
|
+
|
|
103
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
104
|
+
directRef(
|
|
105
|
+
sourceUri,
|
|
106
|
+
rangeOf(content, "{% include 'shared/header' %}"),
|
|
107
|
+
p('app/views/partials/shared/header.liquid'),
|
|
108
|
+
'include',
|
|
109
|
+
),
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('resolves a {% graphql %} edge to the .graphql operation file', async () => {
|
|
114
|
+
const rootUri = pathUtils.join(fixturesRoot, 'graphql-edges');
|
|
115
|
+
const p = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
116
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
117
|
+
const content = `{% liquid
|
|
118
|
+
graphql posts = 'blog_posts/find', id: '1'
|
|
119
|
+
%}`;
|
|
120
|
+
|
|
121
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
122
|
+
directRef(
|
|
123
|
+
sourceUri,
|
|
124
|
+
rangeOf(content, "graphql posts = 'blog_posts/find', id: '1'"),
|
|
125
|
+
p('app/graphql/blog_posts/find.graphql'),
|
|
126
|
+
'graphql',
|
|
127
|
+
['id'],
|
|
128
|
+
),
|
|
129
|
+
]);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('resolves module-namespaced render + function targets in declaration order', async () => {
|
|
133
|
+
const rootUri = pathUtils.join(fixturesRoot, 'module-edges');
|
|
134
|
+
const p = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
135
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
136
|
+
const content = `{% liquid
|
|
137
|
+
function items = 'modules/my_module/queries/get'
|
|
138
|
+
%}
|
|
139
|
+
{% render 'modules/my_module/card' %}`;
|
|
140
|
+
|
|
141
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
142
|
+
directRef(
|
|
143
|
+
sourceUri,
|
|
144
|
+
rangeOf(content, "function items = 'modules/my_module/queries/get'"),
|
|
145
|
+
p('modules/my_module/public/lib/queries/get.liquid'),
|
|
146
|
+
'function',
|
|
147
|
+
),
|
|
148
|
+
directRef(
|
|
149
|
+
sourceUri,
|
|
150
|
+
rangeOf(content, "{% render 'modules/my_module/card' %}"),
|
|
151
|
+
p('modules/my_module/public/views/partials/card.liquid'),
|
|
152
|
+
'render',
|
|
153
|
+
),
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('extractFileReferences: only statically resolvable edges', () => {
|
|
159
|
+
const rootUri = pathUtils.join(fixturesRoot, 'function-edges');
|
|
160
|
+
const sourceUri = pathUtils.join(rootUri, 'app/views/pages/draft.liquid');
|
|
161
|
+
|
|
162
|
+
it('skips dynamic render targets', async () => {
|
|
163
|
+
expect(await extract(rootUri, sourceUri, '{% render partial_name %}')).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('returns nothing for an unparseable buffer instead of throwing', async () => {
|
|
167
|
+
expect(await extract(rootUri, sourceUri, '{% render %}{% endif %}')).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('returns nothing for a buffer with no references', async () => {
|
|
171
|
+
expect(await extract(rootUri, sourceUri, '<h1>{{ page.title }}</h1>')).toEqual([]);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('extractFileReferences: layout-association edges (frontmatter `layout:`)', () => {
|
|
176
|
+
const rootUri = pathUtils.join(fixturesRoot, 'function-edges'); // no layouts here → default path
|
|
177
|
+
const p = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
178
|
+
const sourceUri = p('app/views/pages/draft.liquid');
|
|
179
|
+
|
|
180
|
+
// The whole frontmatter block: start through the closing `---` line + newline.
|
|
181
|
+
const fmRange = (content: string): [number, number] => [
|
|
182
|
+
0,
|
|
183
|
+
content.indexOf('\n', content.indexOf('---', 3)) + 1,
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
it('emits a layout edge for an explicit frontmatter layout', async () => {
|
|
187
|
+
const content = `---
|
|
188
|
+
slug: draft
|
|
189
|
+
layout: theme
|
|
190
|
+
---
|
|
191
|
+
<h1>x</h1>`;
|
|
192
|
+
|
|
193
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
194
|
+
directRef(sourceUri, fmRange(content), p('app/views/layouts/theme.liquid'), 'layout'),
|
|
195
|
+
]);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('resolves a module-prefixed layout', async () => {
|
|
199
|
+
const content = `---
|
|
200
|
+
layout: modules/core/admin
|
|
201
|
+
---
|
|
202
|
+
<h1>x</h1>`;
|
|
203
|
+
|
|
204
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([
|
|
205
|
+
directRef(
|
|
206
|
+
sourceUri,
|
|
207
|
+
fmRange(content),
|
|
208
|
+
p('modules/core/public/views/layouts/admin.liquid'),
|
|
209
|
+
'layout',
|
|
210
|
+
),
|
|
211
|
+
]);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('emits no edge for an explicitly empty layout', async () => {
|
|
215
|
+
const content = `---
|
|
216
|
+
slug: draft
|
|
217
|
+
layout: ''
|
|
218
|
+
---
|
|
219
|
+
<h1>x</h1>`;
|
|
220
|
+
|
|
221
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('emits no edge when layout is omitted (no implicit default)', async () => {
|
|
225
|
+
const content = `---
|
|
226
|
+
slug: draft
|
|
227
|
+
---
|
|
228
|
+
<h1>x</h1>`;
|
|
229
|
+
|
|
230
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([]);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('emits no edge for a dynamic layout value', async () => {
|
|
234
|
+
const content = `---
|
|
235
|
+
layout: "{{ context.constants.LAYOUT }}"
|
|
236
|
+
---
|
|
237
|
+
<h1>x</h1>`;
|
|
238
|
+
|
|
239
|
+
expect(await extract(rootUri, sourceUri, content)).toEqual([]);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('extractStructural: the per-file primitive', () => {
|
|
244
|
+
const rootUri = pathUtils.join(fixturesRoot, 'structural');
|
|
245
|
+
// `rootUri` is already a URI, so joining is the whole conversion — `URI.file` on one
|
|
246
|
+
// yields `file:///file%3A///…`, a plausible-looking URI for nowhere.
|
|
247
|
+
const uriOf = (part: string) => pathUtils.join(rootUri, ...part.split('/'));
|
|
248
|
+
|
|
249
|
+
const run = async (part: string, content: string): Promise<ModuleStructural | undefined> => {
|
|
250
|
+
const uri = uriOf(part);
|
|
251
|
+
return extractStructural(await toSourceCode(uri, content), uri);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
it('extracts usage + routing facts from an in-flight buffer (no graph build)', async () => {
|
|
255
|
+
const content = `---
|
|
256
|
+
layout: theme
|
|
257
|
+
method: post
|
|
258
|
+
---
|
|
259
|
+
{% render 'card' %}
|
|
260
|
+
{{ 'greeting.hi' | t }}
|
|
261
|
+
{{ title | upcase }}`;
|
|
262
|
+
expect(await run('app/views/pages/contact.liquid', content)).toEqual({
|
|
263
|
+
renders_used: ['card'],
|
|
264
|
+
graphql_queries_used: [],
|
|
265
|
+
filters_used: ['t', 'upcase'],
|
|
266
|
+
tags_used: ['render'],
|
|
267
|
+
translation_keys: ['greeting.hi'],
|
|
268
|
+
doc_params: [],
|
|
269
|
+
slug: 'contact',
|
|
270
|
+
layout: 'theme',
|
|
271
|
+
method: 'post',
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('returns undefined for a non-Liquid (.graphql) buffer', async () => {
|
|
276
|
+
expect(await run('app/graphql/find.graphql', 'query find { records { id } }')).toBeUndefined();
|
|
277
|
+
});
|
|
278
|
+
});
|