@ripple-ts/language-server 0.2.216 → 0.3.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @ripple-ts/language-server
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#779](https://github.com/Ripple-TS/ripple/pull/779)
8
+ [`74a10cc`](https://github.com/Ripple-TS/ripple/commit/74a10cc5701962cd7c72b144d59b35ecb76263a3)
9
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Introduces #ripple namespace
10
+ for creating ripple reactive entities without imports, such as array, object,
11
+ map, set, date, url, urlSearchParams, mediaQuery. Adds track, untrack,
12
+ trackSplit, effect, context, server, style to the namespace. Deprecates #[] and
13
+ #{} in favor of #ripple[] and #ripple{}. Renames types and actual reactive
14
+ imports for TrackedX entities, such as TrackedArray, TrackedObject, etc. into
15
+ RippleArray, RippleObjec, etc.
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+ [[`74a10cc`](https://github.com/Ripple-TS/ripple/commit/74a10cc5701962cd7c72b144d59b35ecb76263a3)]:
21
+ - @ripple-ts/typescript-plugin@0.3.0
22
+
3
23
  ## 0.2.216
4
24
 
5
25
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ripple-ts/language-server",
3
- "version": "0.2.216",
3
+ "version": "0.3.0",
4
4
  "description": "Language Server Protocol implementation for Ripple",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -15,17 +15,17 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@volar/language-server": "~2.4.28",
18
- "volar-service-css": "0.0.68",
19
- "volar-service-typescript": "0.0.68",
18
+ "volar-service-css": "0.0.70",
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.2.216"
22
+ "@ripple-ts/typescript-plugin": "0.3.0"
23
23
  },
24
24
  "devDependencies": {
25
- "ripple": "0.2.216"
25
+ "ripple": "0.3.0"
26
26
  },
27
27
  "peerDependencies": {
28
- "typescript": "^5.9.2"
28
+ "typescript": "^5.9.3"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public"
@@ -93,10 +93,7 @@ function parseCompilationErrorWithDocument(error, virtualCode, sourceMap, docume
93
93
 
94
94
  if (mapping) {
95
95
  start = document.positionAt(mapping.generatedOffsets[0]);
96
- end = document.positionAt(
97
- mapping.generatedOffsets[0] +
98
- (mapping.generatedLengths || mapping.data.customData.generatedLengths)[0],
99
- );
96
+ end = document.positionAt(mapping.generatedOffsets[0] + mapping.generatedLengths[0]);
100
97
  } else if (sourceMap) {
101
98
  // try to find the match even across multiple mappings
102
99
  const result = sourceMap.toGeneratedRange(start_offset, end_offset, true).next().value;
@@ -11,84 +11,68 @@ const { log } = createLogging('[Ripple Completion Plugin]');
11
11
  */
12
12
  const TRACKED_COLLECTION_SNIPPETS = [
13
13
  {
14
- label: '#Map',
15
- filterText: '#Map',
16
- detail: 'Create a Shorthand TrackedMap',
14
+ label: 'RippleMap',
15
+ filterText: 'RippleMap',
16
+ detail: 'Create a RippleMap',
17
17
  documentation: 'A reactive Map that triggers updates when modified',
18
- insertText: 'new #Map(${1})',
19
- importName: null,
18
+ insertText: 'new RippleMap(${1})',
19
+ importName: 'RippleMap',
20
20
  },
21
21
  {
22
- label: '#Set',
23
- filterText: '#Set',
24
- detail: 'Create a Shorthand TrackedSet',
22
+ label: 'RippleSet',
23
+ filterText: 'RippleSet',
24
+ detail: 'Create a RippleSet',
25
25
  documentation: 'A reactive Set that triggers updates when modified',
26
- insertText: 'new #Set(${1})',
27
- importName: null,
26
+ insertText: 'new RippleSet(${1})',
27
+ importName: 'RippleSet',
28
28
  },
29
29
  {
30
- label: 'TrackedMap',
31
- filterText: 'TrackedMap',
32
- detail: 'Create a TrackedMap',
33
- documentation: 'A reactive Map that triggers updates when modified',
34
- insertText: 'new TrackedMap(${1})',
35
- importName: 'TrackedMap',
36
- },
37
- {
38
- label: 'TrackedSet',
39
- filterText: 'TrackedSet',
40
- detail: 'Create a TrackedSet',
41
- documentation: 'A reactive Set that triggers updates when modified',
42
- insertText: 'new TrackedSet(${1})',
43
- importName: 'TrackedSet',
44
- },
45
- {
46
- label: 'TrackedArray',
47
- filterText: 'TrackedArray',
48
- detail: 'Create a TrackedArray',
30
+ label: 'RippleArray',
31
+ filterText: 'RippleArray',
32
+ detail: 'Create a RippleArray',
49
33
  documentation: 'A reactive Array that triggers updates when modified',
50
- insertText: 'new TrackedArray(${1})',
51
- importName: 'TrackedArray',
34
+ insertText: 'new RippleArray(${1})',
35
+ importName: 'RippleArray',
52
36
  },
53
37
  {
54
- label: 'TrackedArray.from',
55
- filterText: 'TrackedArray.from',
56
- detail: 'Create a TrackedArray.from',
38
+ label: 'RippleArray.from',
39
+ filterText: 'RippleArray.from',
40
+ detail: 'Create a RippleArray.from',
57
41
  documentation: 'A reactive Array that triggers when modified',
58
- insertText: 'new TrackedArray.from(${1})',
59
- importName: 'TrackedArray',
42
+ insertText: 'new RippleArray.from(${1})',
43
+ importName: 'RippleArray',
60
44
  },
61
45
  {
62
- label: 'TrackedObject',
63
- filterText: 'TrackedObject',
64
- detail: 'Create a TrackedObject',
46
+ label: 'RippleObject',
47
+ filterText: 'RippleObject',
48
+ detail: 'Create a RippleObject',
65
49
  documentation: 'A reactive Object that triggers updates when modified',
66
- insertText: 'new TrackedObject(${1})',
67
- importName: 'TrackedObject',
50
+ insertText: 'new RippleObject(${1})',
51
+ importName: 'RippleObject',
68
52
  },
69
53
  {
70
- label: 'TrackedDate',
71
- filterText: 'TrackedDate',
72
- detail: 'Create a TrackedDate',
54
+ label: 'RippleDate',
55
+ filterText: 'RippleDate',
56
+ detail: 'Create a RippleDate',
73
57
  documentation: 'A reactive Date that triggers updates when modified',
74
- insertText: 'new TrackedDate(${1})',
75
- importName: 'TrackedDate',
58
+ insertText: 'new RippleDate(${1})',
59
+ importName: 'RippleDate',
76
60
  },
77
61
  {
78
- label: 'TrackedURL',
79
- filterText: 'TrackedURL',
80
- detail: 'Create a TrackedURL',
62
+ label: 'RippleURL',
63
+ filterText: 'RippleURL',
64
+ detail: 'Create a RippleURL',
81
65
  documentation: 'A reactive URL that triggers updates when modified',
82
- insertText: 'new TrackedURL(${1})',
83
- importName: 'TrackedURL',
66
+ insertText: 'new RippleURL(${1})',
67
+ importName: 'RippleURL',
84
68
  },
85
69
  {
86
- label: 'TrackedURLSearchParams',
87
- filterText: 'TrackedURLSearchParams',
88
- detail: 'Create a TrackedURLSearchParams',
70
+ label: 'RippleURLSearchParams',
71
+ filterText: 'RippleURLSearchParams',
72
+ detail: 'Create a RippleURLSearchParams',
89
73
  documentation: 'A reactive URLSearchParams that triggers updates when modified',
90
- insertText: 'new TrackedURLSearchParams(${1})',
91
- importName: 'TrackedURLSearchParams',
74
+ insertText: 'new RippleURLSearchParams(${1})',
75
+ importName: 'RippleURLSearchParams',
92
76
  },
93
77
  {
94
78
  label: 'MediaQuery',
@@ -132,7 +116,7 @@ function findRippleImport(text) {
132
116
  /**
133
117
  * Generate additionalTextEdits to add an import
134
118
  * @param {string} documentText - Full document text
135
- * @param {string} importName - Name to import (e.g., 'TrackedMap')
119
+ * @param {string} importName - Name to import (e.g., 'RippleMap')
136
120
  * @returns {TextEdit[]}
137
121
  */
138
122
  function generateImportEdit(documentText, importName) {
@@ -187,20 +171,30 @@ function generateImportEdit(documentText, importName) {
187
171
  */
188
172
  const RIPPLE_SNIPPETS = [
189
173
  {
190
- label: '#[]',
174
+ label: '#ripple.',
191
175
  kind: CompletionItemKind.Snippet,
192
- detail: 'Ripple Reactive Array Literal, shorthand for new TrackedArray',
176
+ detail: 'Ripple namespace APIs',
177
+ documentation:
178
+ 'Type #ripple. to access all built-in Ripple namespace APIs (track, map, set, style, server, etc.).',
179
+ insertText: '#ripple.',
180
+ insertTextFormat: InsertTextFormat.Snippet,
181
+ sortText: '0-#-namespace',
182
+ },
183
+ {
184
+ label: '#ripple[]',
185
+ kind: CompletionItemKind.Snippet,
186
+ detail: 'Ripple Reactive Array Literal, shorthand for new RippleArray',
193
187
  documentation: 'Create a new Ripple Array Literal',
194
- insertText: '#[${1}]',
188
+ insertText: '#ripple[${1}]',
195
189
  insertTextFormat: InsertTextFormat.Snippet,
196
190
  sortText: '0-#-array-literal',
197
191
  },
198
192
  {
199
- label: '#{}',
193
+ label: '#ripple{}',
200
194
  kind: CompletionItemKind.Snippet,
201
- detail: 'Ripple Reactive Object Literal, shorthand for new TrackedObject',
195
+ detail: 'Ripple Reactive Object Literal, shorthand for new RippleObject',
202
196
  documentation: 'Create a new Ripple Object Literal',
203
- insertText: '#{${1}}',
197
+ insertText: '#ripple{${1}}',
204
198
  insertTextFormat: InsertTextFormat.Snippet,
205
199
  sortText: '0-#-object-literal',
206
200
  },
@@ -337,6 +331,174 @@ const RIPPLE_SNIPPETS = [
337
331
  },
338
332
  ];
339
333
 
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
+
340
502
  /**
341
503
  * Import suggestions for Ripple
342
504
  */
@@ -383,6 +545,38 @@ const RIPPLE_IMPORTS = [
383
545
  // },
384
546
  ];
385
547
 
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
+
386
580
  /**
387
581
  * @returns {LanguageServicePlugin}
388
582
  */
@@ -393,9 +587,9 @@ function createCompletionPlugin() {
393
587
  completionProvider: {
394
588
  // Trigger on Ripple-specific syntax:
395
589
  // '<' - JSX/HTML tags
396
- // '#' - TrackedMap/TrackedSet shortcuts
397
- // Avoid '.' and ' ' to reduce noise - let manual trigger (Ctrl+Space) handle those
398
- triggerCharacters: ['<', '#'],
590
+ // '#' - RippleMap/RippleSet shortcuts
591
+ // '.' - #ripple namespace member access
592
+ triggerCharacters: ['<', '#', '.'],
399
593
  resolveProvider: false,
400
594
  },
401
595
  },
@@ -412,7 +606,7 @@ function createCompletionPlugin() {
412
606
 
413
607
  const { virtualCode } = getVirtualCode(document, context);
414
608
 
415
- if (virtualCode.languageId !== 'ripple') {
609
+ if (virtualCode && virtualCode.languageId !== 'ripple') {
416
610
  // Check if we're inside an embedded code (like CSS in <style> blocks)
417
611
  // If so, don't provide Ripple snippets - let CSS completions take priority
418
612
  log(`Skipping Ripple completions in the '${virtualCode.languageId}' context`);
@@ -454,6 +648,15 @@ function createCompletionPlugin() {
454
648
  return { items, isIncomplete: false };
455
649
  }
456
650
 
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
+
457
660
  // @ accessor hint when typing after @
458
661
  if (/@\w*$/.test(line)) {
459
662
  items.push({
@@ -464,7 +667,7 @@ function createCompletionPlugin() {
464
667
  });
465
668
  }
466
669
 
467
- // TrackedMap/TrackedSet completions when typing T...
670
+ // RippleMap/RippleSet completions when typing T...
468
671
  // Also detects if 'new' is already typed before it to avoid duplicating
469
672
  const trackedMatch = line.match(/(new\s+)?[T,M,#]([\w\.]*)$/);
470
673
 
@@ -105,8 +105,7 @@ function createDefinitionPlugin() {
105
105
 
106
106
  // Create the origin selection range for #Map/#Set
107
107
  const generatedStart = customMapping.generatedOffsets[0];
108
- const generatedEnd =
109
- generatedStart + customMapping.data.customData.generatedLengths[0];
108
+ const generatedEnd = generatedStart + customMapping.generatedLengths[0];
110
109
  const originStart = document.positionAt(generatedStart);
111
110
  const originEnd = document.positionAt(generatedEnd);
112
111
 
@@ -175,8 +174,7 @@ function createDefinitionPlugin() {
175
174
  // The origin selection range should be in the virtual document
176
175
  // not in the source document!
177
176
  const generatedStart = customMapping.generatedOffsets[0];
178
- const generatedEnd =
179
- generatedStart + customMapping.data.customData.generatedLengths[0];
177
+ const generatedEnd = generatedStart + customMapping.generatedLengths[0];
180
178
  const originStart = document.positionAt(generatedStart);
181
179
  const originEnd = document.positionAt(generatedEnd);
182
180
 
package/src/utils.js CHANGED
@@ -5,9 +5,13 @@
5
5
  /** @import {is_identifier_obfuscated, deobfuscate_identifier, IDENTIFIER_OBFUSCATION_PREFIX} from 'ripple/compiler/internal/identifier/utils' */
6
6
 
7
7
  const { URI } = require('vscode-uri');
8
- const { createLogging, DEBUG } = require('@ripple-ts/typescript-plugin/src/utils.js');
9
- // Matches valid JS/CSS identifier characters: word chars, dashes (CSS), $, and # (Ripple shorthands)
10
- const charAllowedWordRegex = /[\w\-$#]/;
8
+ const {
9
+ createLogging,
10
+ getWordFromPosition,
11
+ charAllowedWordRegex,
12
+ DEBUG,
13
+ } = require('@ripple-ts/typescript-plugin/src/utils.js');
14
+
11
15
  const IMPORT_EXPORT_REGEX = {
12
16
  import: {
13
17
  findBefore: /import\s+(?:\{[^}]*|\*\s+as\s+\w*|\w*)$/s,
@@ -93,31 +97,6 @@ function getVirtualCode(document, context) {
93
97
  return { virtualCode, sourceUri, sourceScript, sourceMap };
94
98
  }
95
99
 
96
- /**
97
- * Get the word at a specific position in the text
98
- * @param {string} text
99
- * @param {number} start
100
- * @returns {{word: string, start: number, end: number}}
101
- */
102
- function getWordFromPosition(text, start) {
103
- let wordStart = start;
104
- let wordEnd = start;
105
- while (wordStart > 0 && charAllowedWordRegex.test(text[wordStart - 1])) {
106
- wordStart--;
107
- }
108
- while (wordEnd < text.length && charAllowedWordRegex.test(text[wordEnd])) {
109
- wordEnd++;
110
- }
111
-
112
- const word = text.substring(wordStart, wordEnd);
113
-
114
- return {
115
- word,
116
- start: wordStart,
117
- end: wordEnd,
118
- };
119
- }
120
-
121
100
  /**
122
101
  * @param {'import' | 'export'} type
123
102
  * @param {string} text