@ripple-ts/language-server 0.3.3 → 0.3.5
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 +14 -0
- package/package.json +3 -3
- package/src/completionPlugin.js +15 -233
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @ripple-ts/language-server
|
|
2
2
|
|
|
3
|
+
## 0.3.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies []:
|
|
8
|
+
- @ripple-ts/typescript-plugin@0.3.5
|
|
9
|
+
|
|
10
|
+
## 0.3.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies []:
|
|
15
|
+
- @ripple-ts/typescript-plugin@0.3.4
|
|
16
|
+
|
|
3
17
|
## 0.3.3
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripple-ts/language-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Language Server Protocol implementation for Ripple",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"volar-service-typescript": "0.0.70",
|
|
20
20
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
21
21
|
"vscode-uri": "^3.1.0",
|
|
22
|
-
"@ripple-ts/typescript-plugin": "0.3.
|
|
22
|
+
"@ripple-ts/typescript-plugin": "0.3.5"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"ripple": "0.3.
|
|
25
|
+
"ripple": "0.3.5"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"typescript": "^5.9.3"
|
package/src/completionPlugin.js
CHANGED
|
@@ -171,32 +171,24 @@ function generateImportEdit(documentText, importName) {
|
|
|
171
171
|
*/
|
|
172
172
|
const RIPPLE_SNIPPETS = [
|
|
173
173
|
{
|
|
174
|
-
label: '#
|
|
174
|
+
label: '#style',
|
|
175
175
|
kind: CompletionItemKind.Snippet,
|
|
176
|
-
detail: '
|
|
176
|
+
detail: 'Scoped CSS class reference',
|
|
177
177
|
documentation:
|
|
178
|
-
'
|
|
179
|
-
insertText: '#
|
|
178
|
+
'Produces a scoped CSS class string for passing to child components.\nThe class must be defined as a standalone selector in <style>.\n\nUsage: <Child cls={#style.highlight} />',
|
|
179
|
+
insertText: '#style.${1:className}',
|
|
180
180
|
insertTextFormat: InsertTextFormat.Snippet,
|
|
181
|
-
sortText: '0-#-
|
|
181
|
+
sortText: '0-#-style',
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
|
-
label: '#
|
|
184
|
+
label: '#server',
|
|
185
185
|
kind: CompletionItemKind.Snippet,
|
|
186
|
-
detail: '
|
|
187
|
-
documentation:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
sortText: '0-#-array-literal',
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
label: '#ripple{}',
|
|
194
|
-
kind: CompletionItemKind.Snippet,
|
|
195
|
-
detail: 'Ripple Reactive Object Literal, shorthand for new RippleObject',
|
|
196
|
-
documentation: 'Create a new Ripple Object Literal',
|
|
197
|
-
insertText: '#ripple{${1}}',
|
|
186
|
+
detail: 'Server-only code block (module level)',
|
|
187
|
+
documentation:
|
|
188
|
+
'Marks a block as server-only. Code inside is tree-shaken on the client.\nMust be at module top level.\n\nUsage:\n#server {\n export async function loadData() { ... }\n}',
|
|
189
|
+
insertText: '#server {\n\t$0\n}',
|
|
198
190
|
insertTextFormat: InsertTextFormat.Snippet,
|
|
199
|
-
sortText: '0-#-
|
|
191
|
+
sortText: '0-#-server',
|
|
200
192
|
},
|
|
201
193
|
{
|
|
202
194
|
label: 'component',
|
|
@@ -331,174 +323,6 @@ const RIPPLE_SNIPPETS = [
|
|
|
331
323
|
},
|
|
332
324
|
];
|
|
333
325
|
|
|
334
|
-
/**
|
|
335
|
-
* All #ripple.* namespace completions — no imports required.
|
|
336
|
-
* Shown when the cursor follows `#ripple` or `#ripple.`
|
|
337
|
-
* @type {CompletionItem[]}
|
|
338
|
-
*/
|
|
339
|
-
const RIPPLE_NAMESPACE_SNIPPETS = [
|
|
340
|
-
{
|
|
341
|
-
label: '#ripple.track',
|
|
342
|
-
kind: CompletionItemKind.Snippet,
|
|
343
|
-
detail: 'Reactive tracked value (no import needed)',
|
|
344
|
-
documentation:
|
|
345
|
-
'Creates a reactive tracked value. Equivalent to track() but requires no import.\n\nUsage: let count = #ripple.track(0);\nDerived: let double = #ripple.track(() => @count * 2);',
|
|
346
|
-
insertText: '#ripple.track(${1:initialValue})',
|
|
347
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
348
|
-
sortText: '0-ripple-track',
|
|
349
|
-
},
|
|
350
|
-
{
|
|
351
|
-
label: '#ripple.trackSplit',
|
|
352
|
-
kind: CompletionItemKind.Snippet,
|
|
353
|
-
detail: 'Reactive prop splitting (no import needed)',
|
|
354
|
-
documentation:
|
|
355
|
-
"Destructures props while preserving reactivity. Equivalent to trackSplit() but requires no import.\n\nUsage: const [children, rest] = #ripple.trackSplit(props, ['children']);",
|
|
356
|
-
insertText: "#ripple.trackSplit(${1:props}, ['${2:children}'])",
|
|
357
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
358
|
-
sortText: '0-ripple-trackSplit',
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
label: '#ripple.effect',
|
|
362
|
-
kind: CompletionItemKind.Snippet,
|
|
363
|
-
detail: 'Reactive effect (no import needed)',
|
|
364
|
-
documentation:
|
|
365
|
-
'Registers a reactive side effect. Equivalent to effect() but requires no import.\n\nUsage: #ripple.effect(() => {\n console.log(@count);\n});',
|
|
366
|
-
insertText: '#ripple.effect(() => {\n\t$0\n})',
|
|
367
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
368
|
-
sortText: '0-ripple-effect',
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
label: '#ripple.untrack',
|
|
372
|
-
kind: CompletionItemKind.Snippet,
|
|
373
|
-
detail: 'Read without dependency tracking (no import needed)',
|
|
374
|
-
documentation:
|
|
375
|
-
'Reads reactive values without creating dependencies. Equivalent to untrack() but requires no import.\n\nUsage: const snapshot = #ripple.untrack(() => @count);',
|
|
376
|
-
insertText: '#ripple.untrack(() => ${1:@value})',
|
|
377
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
378
|
-
sortText: '0-ripple-untrack',
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
label: '#ripple.validate',
|
|
382
|
-
kind: CompletionItemKind.Snippet,
|
|
383
|
-
detail: 'Validation wrapper (no import needed)',
|
|
384
|
-
documentation:
|
|
385
|
-
"Wraps a value with validation logic.\n\nUsage: let email = #ripple.validate(#ripple.track(''));",
|
|
386
|
-
insertText: '#ripple.validate(${1})',
|
|
387
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
388
|
-
sortText: '0-ripple-validate',
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
label: '#ripple.context',
|
|
392
|
-
kind: CompletionItemKind.Snippet,
|
|
393
|
-
detail: 'Create a Context (no import needed)',
|
|
394
|
-
documentation:
|
|
395
|
-
"Creates a reactive context. Equivalent to new Context() but requires no import.\n\nUsage: const ThemeCtx = #ripple.context('light');",
|
|
396
|
-
insertText: '#ripple.context(${1:defaultValue})',
|
|
397
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
398
|
-
sortText: '0-ripple-context',
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
label: '#ripple.array',
|
|
402
|
-
kind: CompletionItemKind.Snippet,
|
|
403
|
-
detail: 'RippleArray class reference (no import needed)',
|
|
404
|
-
documentation:
|
|
405
|
-
'Reference to the RippleArray class. Use for static methods or as a type annotation.\n\nUsage: const copy = #ripple.array.from(existing);',
|
|
406
|
-
insertText: '#ripple.array',
|
|
407
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
408
|
-
sortText: '0-ripple-array',
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
label: '#ripple.object',
|
|
412
|
-
kind: CompletionItemKind.Snippet,
|
|
413
|
-
detail: 'RippleObject class reference (no import needed)',
|
|
414
|
-
documentation:
|
|
415
|
-
'Reference to the RippleObject class. Use for static methods or as a type annotation.\n\nUsage: const obj = #ripple.object({ a: 1 });',
|
|
416
|
-
insertText: '#ripple.object',
|
|
417
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
418
|
-
sortText: '0-ripple-object',
|
|
419
|
-
},
|
|
420
|
-
{
|
|
421
|
-
label: '#ripple.map',
|
|
422
|
-
kind: CompletionItemKind.Snippet,
|
|
423
|
-
detail: 'RippleMap (no import needed)',
|
|
424
|
-
documentation:
|
|
425
|
-
'Creates a reactive Map. Equivalent to new RippleMap() but requires no import.\n\nUsage: const map = #ripple.map([[key, value]]);',
|
|
426
|
-
insertText: '#ripple.map(${1})',
|
|
427
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
428
|
-
sortText: '0-ripple-map',
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
label: '#ripple.set',
|
|
432
|
-
kind: CompletionItemKind.Snippet,
|
|
433
|
-
detail: 'RippleSet (no import needed)',
|
|
434
|
-
documentation:
|
|
435
|
-
'Creates a reactive Set. Equivalent to new RippleSet() but requires no import.\n\nUsage: const set = #ripple.set([1, 2, 3]);',
|
|
436
|
-
insertText: '#ripple.set(${1})',
|
|
437
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
438
|
-
sortText: '0-ripple-set',
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
label: '#ripple.date',
|
|
442
|
-
kind: CompletionItemKind.Snippet,
|
|
443
|
-
detail: 'RippleDate (no import needed)',
|
|
444
|
-
documentation:
|
|
445
|
-
'Creates a reactive Date. Equivalent to new RippleDate() but requires no import.\n\nUsage: const today = #ripple.date();',
|
|
446
|
-
insertText: '#ripple.date(${1})',
|
|
447
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
448
|
-
sortText: '0-ripple-date',
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
label: '#ripple.url',
|
|
452
|
-
kind: CompletionItemKind.Snippet,
|
|
453
|
-
detail: 'RippleURL (no import needed)',
|
|
454
|
-
documentation:
|
|
455
|
-
"Creates a reactive URL. Equivalent to new RippleURL() but requires no import.\n\nUsage: const url = #ripple.url('https://example.com');",
|
|
456
|
-
insertText: "#ripple.url('${1:https://example.com}')",
|
|
457
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
458
|
-
sortText: '0-ripple-url',
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
label: '#ripple.urlSearchParams',
|
|
462
|
-
kind: CompletionItemKind.Snippet,
|
|
463
|
-
detail: 'RippleURLSearchParams (no import needed)',
|
|
464
|
-
documentation:
|
|
465
|
-
'Creates a reactive URLSearchParams. Equivalent to new RippleURLSearchParams() but requires no import.\n\nUsage: const params = #ripple.urlSearchParams(${1});',
|
|
466
|
-
insertText: '#ripple.urlSearchParams(${1})',
|
|
467
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
468
|
-
sortText: '0-ripple-urlSearchParams',
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
label: '#ripple.mediaQuery',
|
|
472
|
-
kind: CompletionItemKind.Snippet,
|
|
473
|
-
detail: 'Reactive CSS media query (no import needed)',
|
|
474
|
-
documentation:
|
|
475
|
-
"Creates a reactive media query that tracks whether the query currently matches.\n\nUsage: const isMobile = #ripple.mediaQuery('(max-width: 768px)');",
|
|
476
|
-
insertText: "#ripple.mediaQuery('${1:(max-width: 768px)}')",
|
|
477
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
478
|
-
sortText: '0-ripple-mediaQuery',
|
|
479
|
-
},
|
|
480
|
-
{
|
|
481
|
-
label: '#ripple.style',
|
|
482
|
-
kind: CompletionItemKind.Snippet,
|
|
483
|
-
detail: 'Scoped CSS class reference (no import needed)',
|
|
484
|
-
documentation:
|
|
485
|
-
'Produces a scoped CSS class string for passing to child components.\nThe class must be defined as a standalone selector in <style>.\n\nUsage: <Child cls={#ripple.style.highlight} />',
|
|
486
|
-
insertText: '#ripple.style.${1:className}',
|
|
487
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
488
|
-
sortText: '0-ripple-style',
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
label: '#ripple.server',
|
|
492
|
-
kind: CompletionItemKind.Snippet,
|
|
493
|
-
detail: 'Server-only code block (module level)',
|
|
494
|
-
documentation:
|
|
495
|
-
'Marks a block as server-only. Code inside is tree-shaken on the client.\nMust be at module top level.\n\nUsage:\n#ripple.server {\n export async function loadData() { ... }\n}',
|
|
496
|
-
insertText: '#ripple.server {\n\t$0\n}',
|
|
497
|
-
insertTextFormat: InsertTextFormat.Snippet,
|
|
498
|
-
sortText: '0-ripple-server',
|
|
499
|
-
},
|
|
500
|
-
];
|
|
501
|
-
|
|
502
326
|
/**
|
|
503
327
|
* Import suggestions for Ripple
|
|
504
328
|
*/
|
|
@@ -545,38 +369,6 @@ const RIPPLE_IMPORTS = [
|
|
|
545
369
|
// },
|
|
546
370
|
];
|
|
547
371
|
|
|
548
|
-
/**
|
|
549
|
-
* @param {string} line
|
|
550
|
-
* @returns {RegExpMatchArray | null}
|
|
551
|
-
*/
|
|
552
|
-
function get_ripple_namespace_match(line) {
|
|
553
|
-
return line.match(/#ripple(?:\.(\w*))?$/);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* @param {RegExpMatchArray} namespace_match
|
|
558
|
-
* @param {{ line: number, character: number }} position
|
|
559
|
-
* @returns {CompletionItem[]}
|
|
560
|
-
*/
|
|
561
|
-
function create_ripple_namespace_completion_items(namespace_match, position) {
|
|
562
|
-
const start_character = position.character - namespace_match[0].length;
|
|
563
|
-
|
|
564
|
-
return RIPPLE_NAMESPACE_SNIPPETS.map((snippet) => ({
|
|
565
|
-
...snippet,
|
|
566
|
-
filterText: snippet.label,
|
|
567
|
-
textEdit: {
|
|
568
|
-
range: {
|
|
569
|
-
start: {
|
|
570
|
-
line: position.line,
|
|
571
|
-
character: start_character,
|
|
572
|
-
},
|
|
573
|
-
end: position,
|
|
574
|
-
},
|
|
575
|
-
newText: snippet.insertText ?? snippet.label,
|
|
576
|
-
},
|
|
577
|
-
}));
|
|
578
|
-
}
|
|
579
|
-
|
|
580
372
|
/**
|
|
581
373
|
* @returns {LanguageServicePlugin}
|
|
582
374
|
*/
|
|
@@ -587,9 +379,8 @@ function createCompletionPlugin() {
|
|
|
587
379
|
completionProvider: {
|
|
588
380
|
// Trigger on Ripple-specific syntax:
|
|
589
381
|
// '<' - JSX/HTML tags
|
|
590
|
-
// '#' -
|
|
591
|
-
|
|
592
|
-
triggerCharacters: ['<', '#', '.'],
|
|
382
|
+
// '#' - #style, #server keywords
|
|
383
|
+
triggerCharacters: ['<', '#'],
|
|
593
384
|
resolveProvider: false,
|
|
594
385
|
},
|
|
595
386
|
},
|
|
@@ -648,15 +439,6 @@ function createCompletionPlugin() {
|
|
|
648
439
|
return { items, isIncomplete: false };
|
|
649
440
|
}
|
|
650
441
|
|
|
651
|
-
const ripple_namespace_match = get_ripple_namespace_match(line);
|
|
652
|
-
|
|
653
|
-
if (ripple_namespace_match) {
|
|
654
|
-
items.push(
|
|
655
|
-
...create_ripple_namespace_completion_items(ripple_namespace_match, position),
|
|
656
|
-
);
|
|
657
|
-
return { items, isIncomplete: false };
|
|
658
|
-
}
|
|
659
|
-
|
|
660
442
|
// @ accessor hint when typing after @
|
|
661
443
|
if (/@\w*$/.test(line)) {
|
|
662
444
|
items.push({
|
|
@@ -667,9 +449,9 @@ function createCompletionPlugin() {
|
|
|
667
449
|
});
|
|
668
450
|
}
|
|
669
451
|
|
|
670
|
-
// RippleMap/RippleSet completions when typing
|
|
452
|
+
// RippleMap/RippleSet completions when typing R, M...
|
|
671
453
|
// Also detects if 'new' is already typed before it to avoid duplicating
|
|
672
|
-
const trackedMatch = line.match(/(new\s+)?[
|
|
454
|
+
const trackedMatch = line.match(/(new\s+)?[R,M]([\w\.]*)$/);
|
|
673
455
|
|
|
674
456
|
if (trackedMatch) {
|
|
675
457
|
const hasNew = !!trackedMatch[1];
|