@platformos/platformos-language-server-common 0.0.17 → 0.0.18
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 +10 -0
- package/dist/TypeSystem.js +3 -9
- package/dist/TypeSystem.js.map +1 -1
- package/dist/codeActions/CodeActionsProvider.d.ts +1 -1
- package/dist/completions/CompletionsProvider.d.ts +8 -3
- package/dist/completions/CompletionsProvider.js +100 -1
- package/dist/completions/CompletionsProvider.js.map +1 -1
- package/dist/completions/params/LiquidCompletionParams.js +1 -2
- package/dist/completions/params/LiquidCompletionParams.js.map +1 -1
- package/dist/completions/providers/FrontmatterKeyCompletionProvider.d.ts +14 -0
- package/dist/completions/providers/FrontmatterKeyCompletionProvider.js +149 -0
- package/dist/completions/providers/FrontmatterKeyCompletionProvider.js.map +1 -0
- package/dist/completions/providers/index.d.ts +1 -0
- package/dist/completions/providers/index.js +3 -1
- package/dist/completions/providers/index.js.map +1 -1
- package/dist/definitions/DefinitionProvider.js +2 -0
- package/dist/definitions/DefinitionProvider.js.map +1 -1
- package/dist/definitions/providers/FrontmatterDefinitionProvider.d.ts +28 -0
- package/dist/definitions/providers/FrontmatterDefinitionProvider.js +207 -0
- package/dist/definitions/providers/FrontmatterDefinitionProvider.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/TypeSystem.spec.ts +2 -2
- package/src/TypeSystem.ts +3 -11
- package/src/completions/CompletionsProvider.ts +120 -2
- package/src/completions/params/LiquidCompletionParams.ts +1 -2
- package/src/completions/providers/FrontmatterKeyCompletionProvider.spec.ts +196 -0
- package/src/completions/providers/FrontmatterKeyCompletionProvider.ts +182 -0
- package/src/completions/providers/index.ts +5 -0
- package/src/definitions/DefinitionProvider.ts +2 -0
- package/src/definitions/providers/FrontmatterDefinitionProvider.spec.ts +463 -0
- package/src/definitions/providers/FrontmatterDefinitionProvider.ts +258 -0
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { MockFileSystem } from '@platformos/platformos-check-common/src/test';
|
|
3
|
+
import { DefinitionParams, Position } from 'vscode-languageserver-protocol';
|
|
4
|
+
import { DocumentManager } from '../../documents';
|
|
5
|
+
import { FrontmatterDefinitionProvider } from './FrontmatterDefinitionProvider';
|
|
6
|
+
|
|
7
|
+
const rootUri = 'file:///project';
|
|
8
|
+
const pageUri = 'file:///project/app/views/pages/index.liquid';
|
|
9
|
+
const emailUri = 'file:///project/app/emails/welcome.liquid';
|
|
10
|
+
const formUri = 'file:///project/app/forms/signup.liquid';
|
|
11
|
+
|
|
12
|
+
function setup(files: Record<string, string>) {
|
|
13
|
+
const documentManager = new DocumentManager();
|
|
14
|
+
const mockFs = new MockFileSystem(files);
|
|
15
|
+
const provider = new FrontmatterDefinitionProvider(documentManager, mockFs, async () => rootUri);
|
|
16
|
+
return { documentManager, provider };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function makeParams(uri: string, line: number, character: number): DefinitionParams {
|
|
20
|
+
return {
|
|
21
|
+
textDocument: { uri },
|
|
22
|
+
position: Position.create(line, character),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── Layout field (Page) ──────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
describe('FrontmatterDefinitionProvider', () => {
|
|
29
|
+
describe('layout field on Page', () => {
|
|
30
|
+
it('resolves an app layout', async () => {
|
|
31
|
+
const source = `---\nlayout: application\n---\n{{ content }}`;
|
|
32
|
+
const { documentManager, provider } = setup({
|
|
33
|
+
'project/app/views/layouts/application.liquid': '{{ content }}',
|
|
34
|
+
});
|
|
35
|
+
documentManager.open(pageUri, source, 1);
|
|
36
|
+
|
|
37
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
38
|
+
|
|
39
|
+
expect(result).toHaveLength(1);
|
|
40
|
+
expect(result[0].targetUri).toBe('file:///project/app/views/layouts/application.liquid');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('resolves a module layout (public visibility)', async () => {
|
|
44
|
+
const source = `---\nlayout: modules/community/base\n---\n`;
|
|
45
|
+
const { documentManager, provider } = setup({
|
|
46
|
+
'project/modules/community/public/views/layouts/base.liquid': '{{ content }}',
|
|
47
|
+
});
|
|
48
|
+
documentManager.open(pageUri, source, 1);
|
|
49
|
+
|
|
50
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
51
|
+
|
|
52
|
+
expect(result).toHaveLength(1);
|
|
53
|
+
expect(result[0].targetUri).toBe(
|
|
54
|
+
'file:///project/modules/community/public/views/layouts/base.liquid',
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('resolves a module layout (private visibility)', async () => {
|
|
59
|
+
const source = `---\nlayout: modules/community/base\n---\n`;
|
|
60
|
+
const { documentManager, provider } = setup({
|
|
61
|
+
'project/modules/community/private/views/layouts/base.liquid': '{{ content }}',
|
|
62
|
+
});
|
|
63
|
+
documentManager.open(pageUri, source, 1);
|
|
64
|
+
|
|
65
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
66
|
+
|
|
67
|
+
expect(result).toHaveLength(1);
|
|
68
|
+
expect(result[0].targetUri).toBe(
|
|
69
|
+
'file:///project/modules/community/private/views/layouts/base.liquid',
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('prefers public over private when both module visibilities exist', async () => {
|
|
74
|
+
const source = `---\nlayout: modules/community/base\n---\n`;
|
|
75
|
+
const { documentManager, provider } = setup({
|
|
76
|
+
'project/modules/community/public/views/layouts/base.liquid': '{{ content }}',
|
|
77
|
+
'project/modules/community/private/views/layouts/base.liquid': '{{ content }}',
|
|
78
|
+
});
|
|
79
|
+
documentManager.open(pageUri, source, 1);
|
|
80
|
+
|
|
81
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
82
|
+
|
|
83
|
+
expect(result).toHaveLength(1);
|
|
84
|
+
expect(result[0].targetUri).toBe(
|
|
85
|
+
'file:///project/modules/community/public/views/layouts/base.liquid',
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('resolves app/modules overwrite over the original module layout', async () => {
|
|
90
|
+
const source = `---\nlayout: modules/community/base\n---\n`;
|
|
91
|
+
const { documentManager, provider } = setup({
|
|
92
|
+
'project/app/modules/community/public/views/layouts/base.liquid': '{{ content }}',
|
|
93
|
+
'project/modules/community/public/views/layouts/base.liquid': '{{ content }}',
|
|
94
|
+
});
|
|
95
|
+
documentManager.open(pageUri, source, 1);
|
|
96
|
+
|
|
97
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
98
|
+
|
|
99
|
+
expect(result).toHaveLength(1);
|
|
100
|
+
expect(result[0].targetUri).toBe(
|
|
101
|
+
'file:///project/app/modules/community/public/views/layouts/base.liquid',
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('resolves a nested module layout path', async () => {
|
|
106
|
+
const source = `---\nlayout: modules/community/themes/dark\n---\n`;
|
|
107
|
+
const { documentManager, provider } = setup({
|
|
108
|
+
'project/modules/community/public/views/layouts/themes/dark.liquid': '{{ content }}',
|
|
109
|
+
});
|
|
110
|
+
documentManager.open(pageUri, source, 1);
|
|
111
|
+
|
|
112
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
113
|
+
|
|
114
|
+
expect(result).toHaveLength(1);
|
|
115
|
+
expect(result[0].targetUri).toBe(
|
|
116
|
+
'file:///project/modules/community/public/views/layouts/themes/dark.liquid',
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('returns empty when layout file does not exist', async () => {
|
|
121
|
+
const source = `---\nlayout: nonexistent\n---\n{{ content }}`;
|
|
122
|
+
const { documentManager, provider } = setup({});
|
|
123
|
+
documentManager.open(pageUri, source, 1);
|
|
124
|
+
|
|
125
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
126
|
+
|
|
127
|
+
expect(result).toHaveLength(0);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('returns empty when layout value is a Liquid expression', async () => {
|
|
131
|
+
const source = `---\nlayout: {{ current_layout }}\n---\n{{ content }}`;
|
|
132
|
+
const { documentManager, provider } = setup({
|
|
133
|
+
'project/app/views/layouts/application.liquid': '{{ content }}',
|
|
134
|
+
});
|
|
135
|
+
documentManager.open(pageUri, source, 1);
|
|
136
|
+
|
|
137
|
+
const result = await provider.definitions(makeParams(pageUri, 1, 10), null as any, []);
|
|
138
|
+
|
|
139
|
+
expect(result).toHaveLength(0);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// ── Layout field (Email) ───────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
describe('layout field on Email', () => {
|
|
146
|
+
it('resolves an app layout from an email notification', async () => {
|
|
147
|
+
const source = `---\nlayout: email_base\n---\nHi`;
|
|
148
|
+
const { documentManager, provider } = setup({
|
|
149
|
+
'project/app/views/layouts/email_base.liquid': '{{ content }}',
|
|
150
|
+
});
|
|
151
|
+
documentManager.open(emailUri, source, 1);
|
|
152
|
+
|
|
153
|
+
// line 1: layout: email_base
|
|
154
|
+
const result = await provider.definitions(makeParams(emailUri, 1, 10), null as any, []);
|
|
155
|
+
|
|
156
|
+
expect(result).toHaveLength(1);
|
|
157
|
+
expect(result[0].targetUri).toBe('file:///project/app/views/layouts/email_base.liquid');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('resolves a module layout from an email notification', async () => {
|
|
161
|
+
const source = `---\nlayout: modules/community/email_base\n---\nHi`;
|
|
162
|
+
const { documentManager, provider } = setup({
|
|
163
|
+
'project/modules/community/public/views/layouts/email_base.liquid': '{{ content }}',
|
|
164
|
+
});
|
|
165
|
+
documentManager.open(emailUri, source, 1);
|
|
166
|
+
|
|
167
|
+
const result = await provider.definitions(makeParams(emailUri, 1, 10), null as any, []);
|
|
168
|
+
|
|
169
|
+
expect(result).toHaveLength(1);
|
|
170
|
+
expect(result[0].targetUri).toBe(
|
|
171
|
+
'file:///project/modules/community/public/views/layouts/email_base.liquid',
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('returns empty when email layout file does not exist', async () => {
|
|
176
|
+
const source = `---\nlayout: nonexistent\n---\nHi`;
|
|
177
|
+
const { documentManager, provider } = setup({});
|
|
178
|
+
documentManager.open(emailUri, source, 1);
|
|
179
|
+
|
|
180
|
+
const result = await provider.definitions(makeParams(emailUri, 1, 10), null as any, []);
|
|
181
|
+
|
|
182
|
+
expect(result).toHaveLength(0);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('does not resolve layout for Layout file types', async () => {
|
|
186
|
+
const layoutUri = 'file:///project/app/views/layouts/app.liquid';
|
|
187
|
+
const source = `---\nconverter: markdown\n---\n{{ content }}`;
|
|
188
|
+
const { documentManager, provider } = setup({
|
|
189
|
+
'project/app/views/layouts/application.liquid': '{{ content }}',
|
|
190
|
+
});
|
|
191
|
+
documentManager.open(layoutUri, source, 1);
|
|
192
|
+
|
|
193
|
+
const result = await provider.definitions(makeParams(layoutUri, 1, 4), null as any, []);
|
|
194
|
+
|
|
195
|
+
expect(result).toHaveLength(0);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// ── authorization_policies (Page) ─────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
describe('authorization_policies on Page', () => {
|
|
202
|
+
it('resolves an app-level authorization policy', async () => {
|
|
203
|
+
const source = `---\nauthorization_policies:\n - is_authenticated\n---\n{{ content }}`;
|
|
204
|
+
const { documentManager, provider } = setup({
|
|
205
|
+
'project/app/authorization_policies/is_authenticated.liquid': '{% return true %}',
|
|
206
|
+
});
|
|
207
|
+
documentManager.open(pageUri, source, 1);
|
|
208
|
+
|
|
209
|
+
// line 2 (0-indexed): " - is_authenticated"
|
|
210
|
+
const result = await provider.definitions(makeParams(pageUri, 2, 5), null as any, []);
|
|
211
|
+
|
|
212
|
+
expect(result).toHaveLength(1);
|
|
213
|
+
expect(result[0].targetUri).toBe(
|
|
214
|
+
'file:///project/app/authorization_policies/is_authenticated.liquid',
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('resolves a module authorization policy (public visibility)', async () => {
|
|
219
|
+
const source = `---\nauthorization_policies:\n - modules/community/is_authenticated\n---\n{{ content }}`;
|
|
220
|
+
const { documentManager, provider } = setup({
|
|
221
|
+
'project/modules/community/public/authorization_policies/is_authenticated.liquid':
|
|
222
|
+
'{% return true %}',
|
|
223
|
+
});
|
|
224
|
+
documentManager.open(pageUri, source, 1);
|
|
225
|
+
|
|
226
|
+
const result = await provider.definitions(makeParams(pageUri, 2, 10), null as any, []);
|
|
227
|
+
|
|
228
|
+
expect(result).toHaveLength(1);
|
|
229
|
+
expect(result[0].targetUri).toBe(
|
|
230
|
+
'file:///project/modules/community/public/authorization_policies/is_authenticated.liquid',
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('resolves a module authorization policy (private visibility)', async () => {
|
|
235
|
+
const source = `---\nauthorization_policies:\n - modules/community/is_authenticated\n---\n{{ content }}`;
|
|
236
|
+
const { documentManager, provider } = setup({
|
|
237
|
+
'project/modules/community/private/authorization_policies/is_authenticated.liquid':
|
|
238
|
+
'{% return true %}',
|
|
239
|
+
});
|
|
240
|
+
documentManager.open(pageUri, source, 1);
|
|
241
|
+
|
|
242
|
+
const result = await provider.definitions(makeParams(pageUri, 2, 10), null as any, []);
|
|
243
|
+
|
|
244
|
+
expect(result).toHaveLength(1);
|
|
245
|
+
expect(result[0].targetUri).toBe(
|
|
246
|
+
'file:///project/modules/community/private/authorization_policies/is_authenticated.liquid',
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('resolves app/modules overwrite over original module policy', async () => {
|
|
251
|
+
const source = `---\nauthorization_policies:\n - modules/community/is_authenticated\n---\n{{ content }}`;
|
|
252
|
+
const { documentManager, provider } = setup({
|
|
253
|
+
'project/app/modules/community/public/authorization_policies/is_authenticated.liquid':
|
|
254
|
+
'{% return true %}',
|
|
255
|
+
'project/modules/community/public/authorization_policies/is_authenticated.liquid':
|
|
256
|
+
'{% return true %}',
|
|
257
|
+
});
|
|
258
|
+
documentManager.open(pageUri, source, 1);
|
|
259
|
+
|
|
260
|
+
const result = await provider.definitions(makeParams(pageUri, 2, 10), null as any, []);
|
|
261
|
+
|
|
262
|
+
expect(result).toHaveLength(1);
|
|
263
|
+
expect(result[0].targetUri).toBe(
|
|
264
|
+
'file:///project/app/modules/community/public/authorization_policies/is_authenticated.liquid',
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('returns empty when authorization policy file does not exist', async () => {
|
|
269
|
+
const source = `---\nauthorization_policies:\n - nonexistent_policy\n---\n{{ content }}`;
|
|
270
|
+
const { documentManager, provider } = setup({});
|
|
271
|
+
documentManager.open(pageUri, source, 1);
|
|
272
|
+
|
|
273
|
+
const result = await provider.definitions(makeParams(pageUri, 2, 5), null as any, []);
|
|
274
|
+
|
|
275
|
+
expect(result).toHaveLength(0);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// ── email_notifications (FormConfiguration) ───────────────────────────────
|
|
280
|
+
|
|
281
|
+
describe('email_notifications on FormConfiguration', () => {
|
|
282
|
+
it('resolves an app-level email notification', async () => {
|
|
283
|
+
const source = `---\nemail_notifications:\n - welcome\n---\n`;
|
|
284
|
+
const { documentManager, provider } = setup({
|
|
285
|
+
'project/app/emails/welcome.liquid': '---\nto: user@example.com\n---\n',
|
|
286
|
+
});
|
|
287
|
+
documentManager.open(formUri, source, 1);
|
|
288
|
+
|
|
289
|
+
// line 2: " - welcome"
|
|
290
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
291
|
+
|
|
292
|
+
expect(result).toHaveLength(1);
|
|
293
|
+
expect(result[0].targetUri).toBe('file:///project/app/emails/welcome.liquid');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('resolves a module email notification (public visibility)', async () => {
|
|
297
|
+
const source = `---\nemail_notifications:\n - modules/community/welcome\n---\n`;
|
|
298
|
+
const { documentManager, provider } = setup({
|
|
299
|
+
'project/modules/community/public/emails/welcome.liquid':
|
|
300
|
+
'---\nto: user@example.com\n---\n',
|
|
301
|
+
});
|
|
302
|
+
documentManager.open(formUri, source, 1);
|
|
303
|
+
|
|
304
|
+
const result = await provider.definitions(makeParams(formUri, 2, 10), null as any, []);
|
|
305
|
+
|
|
306
|
+
expect(result).toHaveLength(1);
|
|
307
|
+
expect(result[0].targetUri).toBe(
|
|
308
|
+
'file:///project/modules/community/public/emails/welcome.liquid',
|
|
309
|
+
);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('resolves app/modules overwrite over original module email notification', async () => {
|
|
313
|
+
const source = `---\nemail_notifications:\n - modules/community/welcome\n---\n`;
|
|
314
|
+
const { documentManager, provider } = setup({
|
|
315
|
+
'project/app/modules/community/public/emails/welcome.liquid':
|
|
316
|
+
'---\nto: user@example.com\n---\n',
|
|
317
|
+
'project/modules/community/public/emails/welcome.liquid':
|
|
318
|
+
'---\nto: user@example.com\n---\n',
|
|
319
|
+
});
|
|
320
|
+
documentManager.open(formUri, source, 1);
|
|
321
|
+
|
|
322
|
+
const result = await provider.definitions(makeParams(formUri, 2, 10), null as any, []);
|
|
323
|
+
|
|
324
|
+
expect(result).toHaveLength(1);
|
|
325
|
+
expect(result[0].targetUri).toBe(
|
|
326
|
+
'file:///project/app/modules/community/public/emails/welcome.liquid',
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('returns empty when email notification file does not exist', async () => {
|
|
331
|
+
const source = `---\nemail_notifications:\n - nonexistent\n---\n`;
|
|
332
|
+
const { documentManager, provider } = setup({});
|
|
333
|
+
documentManager.open(formUri, source, 1);
|
|
334
|
+
|
|
335
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
336
|
+
|
|
337
|
+
expect(result).toHaveLength(0);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// ── sms_notifications (FormConfiguration) ─────────────────────────────────
|
|
342
|
+
|
|
343
|
+
describe('sms_notifications on FormConfiguration', () => {
|
|
344
|
+
it('resolves an app-level SMS notification', async () => {
|
|
345
|
+
const source = `---\nsms_notifications:\n - sms_alert\n---\n`;
|
|
346
|
+
const { documentManager, provider } = setup({
|
|
347
|
+
'project/app/smses/sms_alert.liquid': '---\nto: "+15550001234"\n---\n',
|
|
348
|
+
});
|
|
349
|
+
documentManager.open(formUri, source, 1);
|
|
350
|
+
|
|
351
|
+
// line 2: " - sms_alert"
|
|
352
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
353
|
+
|
|
354
|
+
expect(result).toHaveLength(1);
|
|
355
|
+
expect(result[0].targetUri).toBe('file:///project/app/smses/sms_alert.liquid');
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('resolves a module SMS notification (public visibility)', async () => {
|
|
359
|
+
const source = `---\nsms_notifications:\n - modules/community/sms_alert\n---\n`;
|
|
360
|
+
const { documentManager, provider } = setup({
|
|
361
|
+
'project/modules/community/public/smses/sms_alert.liquid': '---\nto: "+15550001234"\n---\n',
|
|
362
|
+
});
|
|
363
|
+
documentManager.open(formUri, source, 1);
|
|
364
|
+
|
|
365
|
+
const result = await provider.definitions(makeParams(formUri, 2, 10), null as any, []);
|
|
366
|
+
|
|
367
|
+
expect(result).toHaveLength(1);
|
|
368
|
+
expect(result[0].targetUri).toBe(
|
|
369
|
+
'file:///project/modules/community/public/smses/sms_alert.liquid',
|
|
370
|
+
);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('returns empty when SMS notification file does not exist', async () => {
|
|
374
|
+
const source = `---\nsms_notifications:\n - nonexistent\n---\n`;
|
|
375
|
+
const { documentManager, provider } = setup({});
|
|
376
|
+
documentManager.open(formUri, source, 1);
|
|
377
|
+
|
|
378
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
379
|
+
|
|
380
|
+
expect(result).toHaveLength(0);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// ── api_call_notifications (FormConfiguration) ────────────────────────────
|
|
385
|
+
|
|
386
|
+
describe('api_call_notifications on FormConfiguration', () => {
|
|
387
|
+
it('resolves an app-level API call notification', async () => {
|
|
388
|
+
const source = `---\napi_call_notifications:\n - webhook\n---\n`;
|
|
389
|
+
const { documentManager, provider } = setup({
|
|
390
|
+
'project/app/api_calls/webhook.liquid':
|
|
391
|
+
'---\nto: https://example.com\nrequest_type: POST\n---\n',
|
|
392
|
+
});
|
|
393
|
+
documentManager.open(formUri, source, 1);
|
|
394
|
+
|
|
395
|
+
// line 2: " - webhook"
|
|
396
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
397
|
+
|
|
398
|
+
expect(result).toHaveLength(1);
|
|
399
|
+
expect(result[0].targetUri).toBe('file:///project/app/api_calls/webhook.liquid');
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('resolves a module API call notification (public visibility)', async () => {
|
|
403
|
+
const source = `---\napi_call_notifications:\n - modules/community/webhook\n---\n`;
|
|
404
|
+
const { documentManager, provider } = setup({
|
|
405
|
+
'project/modules/community/public/api_calls/webhook.liquid':
|
|
406
|
+
'---\nto: https://example.com\nrequest_type: POST\n---\n',
|
|
407
|
+
});
|
|
408
|
+
documentManager.open(formUri, source, 1);
|
|
409
|
+
|
|
410
|
+
const result = await provider.definitions(makeParams(formUri, 2, 10), null as any, []);
|
|
411
|
+
|
|
412
|
+
expect(result).toHaveLength(1);
|
|
413
|
+
expect(result[0].targetUri).toBe(
|
|
414
|
+
'file:///project/modules/community/public/api_calls/webhook.liquid',
|
|
415
|
+
);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('resolves app/modules overwrite over original module API call notification', async () => {
|
|
419
|
+
const source = `---\napi_call_notifications:\n - modules/community/webhook\n---\n`;
|
|
420
|
+
const { documentManager, provider } = setup({
|
|
421
|
+
'project/app/modules/community/public/api_calls/webhook.liquid':
|
|
422
|
+
'---\nto: https://example.com\nrequest_type: POST\n---\n',
|
|
423
|
+
'project/modules/community/public/api_calls/webhook.liquid':
|
|
424
|
+
'---\nto: https://example.com\nrequest_type: POST\n---\n',
|
|
425
|
+
});
|
|
426
|
+
documentManager.open(formUri, source, 1);
|
|
427
|
+
|
|
428
|
+
const result = await provider.definitions(makeParams(formUri, 2, 10), null as any, []);
|
|
429
|
+
|
|
430
|
+
expect(result).toHaveLength(1);
|
|
431
|
+
expect(result[0].targetUri).toBe(
|
|
432
|
+
'file:///project/app/modules/community/public/api_calls/webhook.liquid',
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('returns empty when API call notification file does not exist', async () => {
|
|
437
|
+
const source = `---\napi_call_notifications:\n - nonexistent\n---\n`;
|
|
438
|
+
const { documentManager, provider } = setup({});
|
|
439
|
+
documentManager.open(formUri, source, 1);
|
|
440
|
+
|
|
441
|
+
const result = await provider.definitions(makeParams(formUri, 2, 5), null as any, []);
|
|
442
|
+
|
|
443
|
+
expect(result).toHaveLength(0);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// ── Outside frontmatter ───────────────────────────────────────────────────
|
|
448
|
+
|
|
449
|
+
describe('outside frontmatter', () => {
|
|
450
|
+
it('returns empty when cursor is in the Liquid body', async () => {
|
|
451
|
+
const source = `---\nlayout: application\n---\n{{ content }}`;
|
|
452
|
+
const { documentManager, provider } = setup({
|
|
453
|
+
'project/app/views/layouts/application.liquid': '{{ content }}',
|
|
454
|
+
});
|
|
455
|
+
documentManager.open(pageUri, source, 1);
|
|
456
|
+
|
|
457
|
+
// cursor on line 3 (the {{ content }} line)
|
|
458
|
+
const result = await provider.definitions(makeParams(pageUri, 3, 5), null as any, []);
|
|
459
|
+
|
|
460
|
+
expect(result).toHaveLength(0);
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
});
|