@ripple-ts/typescript-plugin 0.2.215 → 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 +38 -0
- package/package.json +5 -4
- package/src/language.js +88 -36
- package/src/utils.js +29 -0
- package/tsconfig.json +10 -1
- package/tsdown.config.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @ripple-ts/typescript-plugin
|
|
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
|
+
[[`61271cb`](https://github.com/Ripple-TS/ripple/commit/61271cb1c4777f2ab9093c6c89a5ad771ec98b7d),
|
|
21
|
+
[`21dd402`](https://github.com/Ripple-TS/ripple/commit/21dd4029d7e027a0706cb133b09530a722feb73d),
|
|
22
|
+
[`c2dbefe`](https://github.com/Ripple-TS/ripple/commit/c2dbefe5645c0c4f6e0ff4dc00d9c4de81616667),
|
|
23
|
+
[`74a10cc`](https://github.com/Ripple-TS/ripple/commit/74a10cc5701962cd7c72b144d59b35ecb76263a3)]:
|
|
24
|
+
- ripple@0.3.0
|
|
25
|
+
|
|
26
|
+
## 0.2.216
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- [#764](https://github.com/Ripple-TS/ripple/pull/764)
|
|
31
|
+
[`95ea864`](https://github.com/Ripple-TS/ripple/commit/95ea8645b2cb27e2610a4ace4c8fb238c92d441a)
|
|
32
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Fixes syntax color
|
|
33
|
+
highlighting for `pending`
|
|
34
|
+
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
[[`9fb507d`](https://github.com/Ripple-TS/ripple/commit/9fb507d76af6fd6a5c636af1976d1e03d3e869ac),
|
|
37
|
+
[`e1de4bb`](https://github.com/Ripple-TS/ripple/commit/e1de4bb9df75342a693cda24d0999a423db05ec4),
|
|
38
|
+
[`95ea864`](https://github.com/Ripple-TS/ripple/commit/95ea8645b2cb27e2610a4ace4c8fb238c92d441a)]:
|
|
39
|
+
- ripple@0.2.216
|
|
40
|
+
|
|
3
41
|
## 0.2.215
|
|
4
42
|
|
|
5
43
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "TypeScript plugin for Ripple",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.3.0",
|
|
7
7
|
"main": "src/index.js",
|
|
8
8
|
"homepage": "https://ripple-ts.com",
|
|
9
9
|
"repository": {
|
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
"@volar/typescript": "~2.4.28"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"
|
|
22
|
+
"@types/node": "^24.3.0",
|
|
23
|
+
"tsdown": "^0.20.3"
|
|
23
24
|
},
|
|
24
25
|
"peerDependencies": {
|
|
25
|
-
"typescript": "^5.9.
|
|
26
|
-
"ripple": "0.
|
|
26
|
+
"typescript": "^5.9.3",
|
|
27
|
+
"ripple": "0.3.0"
|
|
27
28
|
},
|
|
28
29
|
"publishConfig": {
|
|
29
30
|
"access": "public"
|
package/src/language.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// @ts-expect-error ESM import
|
|
2
1
|
/** @import { CodeMapping } from 'ripple/compiler' */
|
|
3
|
-
|
|
4
|
-
/** @import
|
|
2
|
+
/** @import {RippleCompileError, VolarMappingsResult} from 'ripple/compiler' */
|
|
3
|
+
/** @import * as RippleCompiler from 'ripple/compiler' */
|
|
5
4
|
|
|
6
5
|
/** @typedef {Map<string, CodeMapping>} CachedMappings */
|
|
7
6
|
/** @typedef {import('typescript').CompilerOptions} CompilerOptions */
|
|
@@ -191,7 +190,7 @@ class RippleVirtualCode {
|
|
|
191
190
|
const charBeforeDot = newEnd > 1 ? newCode[newEnd - 2] : '';
|
|
192
191
|
log(' Char before dot:', JSON.stringify(charBeforeDot));
|
|
193
192
|
|
|
194
|
-
if (/[
|
|
193
|
+
if (/[$#_\u200C\u200D\p{ID_Continue}\)\]\}]/u.test(charBeforeDot)) {
|
|
195
194
|
isDotTyped = true;
|
|
196
195
|
dotPosition = newEnd - 1; // Position of the dot
|
|
197
196
|
log('ChangeRange detected dot typed at position', dotPosition);
|
|
@@ -200,40 +199,25 @@ class RippleVirtualCode {
|
|
|
200
199
|
}
|
|
201
200
|
|
|
202
201
|
try {
|
|
203
|
-
// If user typed a ".",
|
|
202
|
+
// If user typed a ".", compile without it and then stitch it back into
|
|
203
|
+
// the generated output so completions can still resolve.
|
|
204
204
|
if (isDotTyped && dotPosition >= 0) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
newCode.substring(0, dotPosition) + charBeforeDot + newCode.substring(dotPosition + 1);
|
|
205
|
+
const codeWithoutDot =
|
|
206
|
+
newCode.substring(0, dotPosition) + newCode.substring(dotPosition + 1);
|
|
208
207
|
|
|
209
|
-
log('
|
|
210
|
-
transpiled = this.ripple.compile_to_volar_mappings(
|
|
211
|
-
|
|
208
|
+
log('Compiling without typed dot at position', dotPosition);
|
|
209
|
+
transpiled = this.ripple.compile_to_volar_mappings(codeWithoutDot, this.fileName, {
|
|
210
|
+
loose: true,
|
|
211
|
+
});
|
|
212
|
+
log('Compilation without dot successful');
|
|
212
213
|
|
|
213
|
-
// Find where the placeholder ended up in generated code and replace with "."
|
|
214
214
|
if (transpiled && transpiled.code && transpiled.mappings.length > 0) {
|
|
215
|
-
|
|
216
|
-
for (const mapping of transpiled.mappings) {
|
|
217
|
-
const sourceStart = mapping.sourceOffsets[0];
|
|
218
|
-
const sourceEnd = sourceStart + mapping.lengths[0];
|
|
219
|
-
|
|
220
|
-
if (dotPosition >= sourceStart && dotPosition < sourceEnd) {
|
|
221
|
-
placeholderMapping = mapping;
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
215
|
+
const insertedDotPosition = restore_typed_dot_in_transpiled_code(transpiled, dotPosition);
|
|
225
216
|
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
transpiled.code =
|
|
232
|
-
transpiled.code.substring(0, placeholderPosInGenerated) +
|
|
233
|
-
'.' +
|
|
234
|
-
transpiled.code.substring(placeholderPosInGenerated + 1);
|
|
235
|
-
|
|
236
|
-
log('Replaced placeholder at position', placeholderPosInGenerated, 'with dot');
|
|
217
|
+
if (insertedDotPosition === null) {
|
|
218
|
+
logWarning('Failed to restore typed dot into transpiled output');
|
|
219
|
+
} else {
|
|
220
|
+
log('Inserted typed dot at generated position', insertedDotPosition);
|
|
237
221
|
}
|
|
238
222
|
}
|
|
239
223
|
} else {
|
|
@@ -325,7 +309,7 @@ class RippleVirtualCode {
|
|
|
325
309
|
generatedLengths: [newCode.length],
|
|
326
310
|
data: {
|
|
327
311
|
verification: true, // disable TS since we're using source code as generated code
|
|
328
|
-
customData: {
|
|
312
|
+
customData: {},
|
|
329
313
|
},
|
|
330
314
|
},
|
|
331
315
|
];
|
|
@@ -355,7 +339,7 @@ class RippleVirtualCode {
|
|
|
355
339
|
mapping = this.mappings[i];
|
|
356
340
|
|
|
357
341
|
genStart = mapping.generatedOffsets[0];
|
|
358
|
-
genLength = mapping.
|
|
342
|
+
genLength = mapping.generatedLengths[0];
|
|
359
343
|
genEnd = genStart + genLength;
|
|
360
344
|
genKey = `${genStart}-${genEnd}`;
|
|
361
345
|
this.#mappingGenToSource.set(genKey, mapping);
|
|
@@ -427,7 +411,6 @@ function extractCssFromSource(code) {
|
|
|
427
411
|
structure: true,
|
|
428
412
|
format: false,
|
|
429
413
|
customData: {
|
|
430
|
-
generatedLengths: [cssLength],
|
|
431
414
|
content: cssContent,
|
|
432
415
|
embeddedId: `style_${index}`,
|
|
433
416
|
},
|
|
@@ -456,6 +439,75 @@ function extractCssFromSource(code) {
|
|
|
456
439
|
return embeddedCodes;
|
|
457
440
|
}
|
|
458
441
|
|
|
442
|
+
/**
|
|
443
|
+
* Insert a typed dot back into the transpiled code and update mappings so the
|
|
444
|
+
* source and generated offsets stay aligned for completion requests.
|
|
445
|
+
* @param {VolarMappingsResult} transpiled
|
|
446
|
+
* @param {number} dotPosition
|
|
447
|
+
* @returns {number | null}
|
|
448
|
+
*/
|
|
449
|
+
function restore_typed_dot_in_transpiled_code(transpiled, dotPosition) {
|
|
450
|
+
let dot_mapping = null;
|
|
451
|
+
|
|
452
|
+
for (const mapping of transpiled.mappings) {
|
|
453
|
+
const source_end = mapping.sourceOffsets[0] + mapping.lengths[0];
|
|
454
|
+
if (source_end === dotPosition) {
|
|
455
|
+
dot_mapping = mapping;
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!dot_mapping) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const generated_length = dot_mapping.generatedLengths[0];
|
|
465
|
+
const insertedDotPosition = dot_mapping.generatedOffsets[0] + generated_length;
|
|
466
|
+
|
|
467
|
+
transpiled.code =
|
|
468
|
+
transpiled.code.substring(0, insertedDotPosition) +
|
|
469
|
+
'.' +
|
|
470
|
+
transpiled.code.substring(insertedDotPosition);
|
|
471
|
+
|
|
472
|
+
// Create a separate 1:1 mapping for the dot character instead of extending
|
|
473
|
+
// the existing mapping. When source and generated lengths differ (e.g.
|
|
474
|
+
// #ripple → _$__u0023_ripple), Volar's translateOffset uses
|
|
475
|
+
// Math.min(relativePos, toLength) which would map the cursor after the dot
|
|
476
|
+
// to the middle of the generated identifier instead of after it.
|
|
477
|
+
|
|
478
|
+
/** @type {CodeMapping} */
|
|
479
|
+
const new_dot_mapping = {
|
|
480
|
+
sourceOffsets: [dotPosition],
|
|
481
|
+
generatedOffsets: [insertedDotPosition],
|
|
482
|
+
lengths: [1],
|
|
483
|
+
generatedLengths: [1],
|
|
484
|
+
data: { ...dot_mapping.data },
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// Find the index to insert after dot_mapping
|
|
488
|
+
const dot_mapping_index = transpiled.mappings.indexOf(dot_mapping);
|
|
489
|
+
transpiled.mappings.splice(dot_mapping_index + 1, 0, new_dot_mapping);
|
|
490
|
+
|
|
491
|
+
for (const mapping of transpiled.mappings) {
|
|
492
|
+
if (
|
|
493
|
+
mapping !== dot_mapping &&
|
|
494
|
+
mapping !== new_dot_mapping &&
|
|
495
|
+
mapping.generatedOffsets[0] >= insertedDotPosition
|
|
496
|
+
) {
|
|
497
|
+
mapping.generatedOffsets[0] += 1;
|
|
498
|
+
}
|
|
499
|
+
if (
|
|
500
|
+
mapping !== dot_mapping &&
|
|
501
|
+
mapping !== new_dot_mapping &&
|
|
502
|
+
mapping.sourceOffsets[0] >= dotPosition
|
|
503
|
+
) {
|
|
504
|
+
mapping.sourceOffsets[0] += 1;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return insertedDotPosition;
|
|
509
|
+
}
|
|
510
|
+
|
|
459
511
|
/**
|
|
460
512
|
* @template T
|
|
461
513
|
* @param {{ options?: CompilerOptions } & T} config
|
package/src/utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const DEBUG = process.env.RIPPLE_DEBUG === 'true';
|
|
2
|
+
// Matches valid JS/CSS identifier characters: word chars, dashes (CSS), $, and # (Ripple shorthands)
|
|
3
|
+
const charAllowedWordRegex = /[\w\-$#]/;
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Create a logging utility with a specific label
|
|
@@ -29,7 +31,34 @@ function createLogging(label) {
|
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Get the word at a specific position in the text
|
|
36
|
+
* @param {string} text
|
|
37
|
+
* @param {number} start
|
|
38
|
+
* @returns {{word: string, start: number, end: number}}
|
|
39
|
+
*/
|
|
40
|
+
function getWordFromPosition(text, start) {
|
|
41
|
+
let wordStart = start;
|
|
42
|
+
let wordEnd = start;
|
|
43
|
+
while (wordStart > 0 && charAllowedWordRegex.test(text[wordStart - 1])) {
|
|
44
|
+
wordStart--;
|
|
45
|
+
}
|
|
46
|
+
while (wordEnd < text.length && charAllowedWordRegex.test(text[wordEnd])) {
|
|
47
|
+
wordEnd++;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const word = text.substring(wordStart, wordEnd);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
word,
|
|
54
|
+
start: wordStart,
|
|
55
|
+
end: wordEnd,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
32
59
|
module.exports = {
|
|
33
60
|
createLogging,
|
|
61
|
+
getWordFromPosition,
|
|
62
|
+
charAllowedWordRegex,
|
|
34
63
|
DEBUG,
|
|
35
64
|
};
|
package/tsconfig.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
+
"module": "node20",
|
|
4
|
+
"moduleResolution": "node16",
|
|
5
|
+
"target": "es2021",
|
|
6
|
+
"lib": ["es2021"],
|
|
3
7
|
"allowJs": true,
|
|
4
|
-
"
|
|
8
|
+
"checkJs": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"types": ["node"]
|
|
5
14
|
},
|
|
6
15
|
"include": ["./src/**/*", "./tests/**/*"],
|
|
7
16
|
"exclude": ["dist", "node_modules"]
|
package/tsdown.config.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { defineConfig } from 'tsdown';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
inlineOnly: false,
|
|
4
5
|
entry: ['src/index.js'],
|
|
5
6
|
format: ['cjs'],
|
|
7
|
+
fixedExtension: false,
|
|
6
8
|
platform: 'node',
|
|
7
9
|
target: 'node20',
|
|
8
10
|
outDir: 'dist',
|