ripple 0.2.184 → 0.2.186
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/package.json +2 -2
- package/src/compiler/index.d.ts +11 -2
- package/src/compiler/phases/1-parse/index.js +8 -13
- package/src/compiler/phases/2-analyze/css-analyze.js +2 -2
- package/src/compiler/phases/2-analyze/index.js +5 -1
- package/src/compiler/phases/2-analyze/prune.js +48 -3
- package/src/compiler/phases/3-transform/client/index.js +187 -136
- package/src/compiler/phases/3-transform/segments.js +313 -62
- package/src/compiler/phases/3-transform/server/index.js +135 -45
- package/src/compiler/phases/3-transform/stylesheet.js +17 -15
- package/src/compiler/source-map-utils.js +139 -65
- package/src/compiler/types/index.d.ts +111 -63
- package/src/compiler/types/parse.d.ts +36 -0
- package/src/compiler/utils.js +4 -2
- package/src/runtime/index-server.js +10 -27
- package/src/runtime/internal/client/operations.js +1 -1
- package/src/runtime/internal/client/runtime.js +8 -8
- package/src/runtime/internal/client/types.d.ts +5 -5
- package/src/runtime/internal/server/index.js +268 -17
- package/src/runtime/internal/server/types.d.ts +19 -11
- package/tests/client/switch.test.ripple +73 -23
- package/tests/server/basic.test.ripple +119 -0
- package/tests/server/composite.test.ripple +1 -1
- package/tests/server/context.test.ripple +31 -0
- package/tests/server/switch.test.ripple +21 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.186",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -86,6 +86,6 @@
|
|
|
86
86
|
"vscode-languageserver-types": "^3.17.5"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
|
-
"ripple": "0.2.
|
|
89
|
+
"ripple": "0.2.186"
|
|
90
90
|
}
|
|
91
91
|
}
|
package/src/compiler/index.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ export interface CompileResult {
|
|
|
24
24
|
css: string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export interface DefinitionLocation {
|
|
28
|
+
embeddedId: string; // e.g., 'style_0', 'style_1'
|
|
29
|
+
start: number; // start offset
|
|
30
|
+
end: number; // end offset
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
export interface PluginActionOverrides {
|
|
28
34
|
/** Whether to enable word document highlighting for this mapping */
|
|
29
35
|
wordHighlight?: {
|
|
@@ -40,13 +46,17 @@ export interface PluginActionOverrides {
|
|
|
40
46
|
/** Custom definition info for this mapping, false to disable */
|
|
41
47
|
definition?:
|
|
42
48
|
| {
|
|
43
|
-
description
|
|
49
|
+
description?: string; // just for reference
|
|
50
|
+
// Generic location for embedded content (CSS, etc.)
|
|
51
|
+
location?: DefinitionLocation;
|
|
44
52
|
}
|
|
45
53
|
| false;
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
export interface CustomMappingData extends PluginActionOverrides {
|
|
49
57
|
generatedLengths: number[];
|
|
58
|
+
embeddedId?: string; // e.g. css regions: 'style_0', 'style_1', etc.
|
|
59
|
+
content?: string; // (e.g., css code)
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
export interface MappingData extends VolarCodeInformation {
|
|
@@ -61,7 +71,6 @@ export interface VolarMappingsResult {
|
|
|
61
71
|
code: string;
|
|
62
72
|
mappings: CodeMapping[];
|
|
63
73
|
cssMappings: CodeMapping[];
|
|
64
|
-
cssSources: string[];
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
/**
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
/** @import * as AST from 'estree' */
|
|
2
|
-
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
3
|
-
/** @import { Parse } from '#parser' */
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
@import * as AST from 'estree'
|
|
3
|
+
@import * as ESTreeJSX from 'estree-jsx'
|
|
4
|
+
@import { Parse } from '#parser'
|
|
5
|
+
@import { RipplePluginConfig } from '#compiler';
|
|
6
|
+
@import { ParseOptions } from 'ripple/compiler'
|
|
7
|
+
*/
|
|
11
8
|
|
|
12
9
|
import * as acorn from 'acorn';
|
|
13
10
|
import { tsPlugin } from '@sveltejs/acorn-typescript';
|
|
@@ -1741,6 +1738,7 @@ function RipplePlugin(config) {
|
|
|
1741
1738
|
throw new Error('Components can only have one style tag');
|
|
1742
1739
|
}
|
|
1743
1740
|
component.css = parsed_css;
|
|
1741
|
+
/** @type {AST.Element} */ (element).metadata.styleScopeHash = parsed_css.hash;
|
|
1744
1742
|
}
|
|
1745
1743
|
|
|
1746
1744
|
const newLines = content.match(regex_newline_characters)?.length;
|
|
@@ -2167,6 +2165,7 @@ function RipplePlugin(config) {
|
|
|
2167
2165
|
* @param {string} source
|
|
2168
2166
|
* @param {AST.CommentWithLocation[]} comments
|
|
2169
2167
|
* @param {number} [index=0] - Starting index
|
|
2168
|
+
* @returns {{onComment: Parse.Options['onComment'], add_comments: (ast: AST.Node) => void}}
|
|
2170
2169
|
*/
|
|
2171
2170
|
function get_comment_handlers(source, comments, index = 0) {
|
|
2172
2171
|
/**
|
|
@@ -2230,11 +2229,7 @@ function get_comment_handlers(source, comments, index = 0) {
|
|
|
2230
2229
|
context,
|
|
2231
2230
|
}));
|
|
2232
2231
|
|
|
2233
|
-
/**
|
|
2234
|
-
* @param {AST.Node} ast
|
|
2235
|
-
*/
|
|
2236
2232
|
walk(ast, null, {
|
|
2237
|
-
/** @param {AST.Node} node */
|
|
2238
2233
|
_(node, { next, path }) {
|
|
2239
2234
|
const metadata = node?.metadata;
|
|
2240
2235
|
|
|
@@ -41,7 +41,7 @@ function is_global(relative_selector) {
|
|
|
41
41
|
export function analyze_css(css) {
|
|
42
42
|
walk(
|
|
43
43
|
css,
|
|
44
|
-
|
|
44
|
+
/** @type {{ rule: AST.CSS.Rule | null }} */ ({ rule: null }),
|
|
45
45
|
{
|
|
46
46
|
Rule(node, context) {
|
|
47
47
|
node.metadata.parent_rule = context.state.rule;
|
|
@@ -90,7 +90,7 @@ export function analyze_css(css) {
|
|
|
90
90
|
// Set the rule metadata before analyzing children
|
|
91
91
|
node.metadata.rule = context.state.rule;
|
|
92
92
|
|
|
93
|
-
context.next(); //
|
|
93
|
+
context.next(); // analyze relevant selectors first
|
|
94
94
|
|
|
95
95
|
{
|
|
96
96
|
const global = node.children.find(is_global);
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
AnalysisContext,
|
|
7
7
|
ScopeInterface,
|
|
8
8
|
Visitors,
|
|
9
|
-
Visitor,
|
|
10
9
|
} from '#compiler';
|
|
11
10
|
*/
|
|
12
11
|
/** @import * as AST from 'estree' */
|
|
@@ -423,6 +422,11 @@ const visitors = {
|
|
|
423
422
|
context.visit(node.discriminant, context.state);
|
|
424
423
|
|
|
425
424
|
for (const switch_case of node.cases) {
|
|
425
|
+
// Fallthrough
|
|
426
|
+
if (switch_case.consequent.length === 0) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
|
|
426
430
|
// Validate that each cases ends in a break statement, except for the last case
|
|
427
431
|
const last = switch_case.consequent?.[switch_case.consequent.length - 1];
|
|
428
432
|
|
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
import { walk } from 'zimmerframe';
|
|
6
6
|
import { is_element_dom_element } from '../../utils.js';
|
|
7
7
|
|
|
8
|
-
const seen = new Set();
|
|
9
8
|
const regex_backslash_and_following_character = /\\(.)/g;
|
|
10
9
|
/** @type {Direction} */
|
|
11
10
|
const FORWARD = 0;
|
|
12
11
|
/** @type {Direction} */
|
|
13
12
|
const BACKWARD = 1;
|
|
14
13
|
|
|
14
|
+
// this will be set for every prune_css call
|
|
15
|
+
// since the code is synchronous, this is safe
|
|
16
|
+
/** @type {string} */
|
|
17
|
+
let css_hash;
|
|
18
|
+
|
|
15
19
|
// CSS selector constants
|
|
16
20
|
/**
|
|
17
21
|
* @param {number} start
|
|
@@ -196,6 +200,47 @@ function apply_selector(relative_selectors, rule, element, direction) {
|
|
|
196
200
|
if (matched) {
|
|
197
201
|
if (!is_outer_global(relative_selector)) {
|
|
198
202
|
relative_selector.metadata.scoped = true;
|
|
203
|
+
|
|
204
|
+
// Store scoped class information on element for language server features
|
|
205
|
+
if (!relative_selector.metadata.is_global && !relative_selector.metadata.is_global_like) {
|
|
206
|
+
// Extract class selectors from the relative selector
|
|
207
|
+
for (const selector of relative_selector.selectors) {
|
|
208
|
+
if (selector.type === 'ClassSelector') {
|
|
209
|
+
const name = selector.name.replace(regex_backslash_and_following_character, '$1');
|
|
210
|
+
|
|
211
|
+
if (!element.metadata.css) {
|
|
212
|
+
element.metadata.css = {
|
|
213
|
+
scopedClasses: new Map(),
|
|
214
|
+
topScopedClasses: new Map(),
|
|
215
|
+
hash: css_hash,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Store class name → CSS location in scopedClasses
|
|
220
|
+
if (!element.metadata.css.scopedClasses.has(name)) {
|
|
221
|
+
element.metadata.css.scopedClasses.set(name, {
|
|
222
|
+
start: selector.start,
|
|
223
|
+
end: selector.end,
|
|
224
|
+
selector: selector,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Also store in topScopedClasses if standalone
|
|
229
|
+
// Standalone = only this ClassSelector in the RelativeSelector, no pseudo-classes/elements
|
|
230
|
+
const isStandalone =
|
|
231
|
+
relative_selector.selectors.length === 1 &&
|
|
232
|
+
relative_selector.selectors[0] === selector;
|
|
233
|
+
|
|
234
|
+
if (isStandalone && !element.metadata.css.topScopedClasses.has(name)) {
|
|
235
|
+
element.metadata.css.topScopedClasses.set(name, {
|
|
236
|
+
start: selector.start,
|
|
237
|
+
end: selector.end,
|
|
238
|
+
selector: selector,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
199
244
|
}
|
|
200
245
|
|
|
201
246
|
element.metadata.scoped = true;
|
|
@@ -1005,6 +1050,8 @@ function rule_has_animation(rule) {
|
|
|
1005
1050
|
* @return {void}
|
|
1006
1051
|
*/
|
|
1007
1052
|
export function prune_css(css, element) {
|
|
1053
|
+
css_hash = css.hash;
|
|
1054
|
+
|
|
1008
1055
|
/** @type {Visitors<AST.CSS.Node, null>} */
|
|
1009
1056
|
const visitors = {
|
|
1010
1057
|
Rule(node, context) {
|
|
@@ -1017,8 +1064,6 @@ export function prune_css(css, element) {
|
|
|
1017
1064
|
ComplexSelector(node, context) {
|
|
1018
1065
|
const selectors = get_relative_selectors(node);
|
|
1019
1066
|
|
|
1020
|
-
seen.clear();
|
|
1021
|
-
|
|
1022
1067
|
const rule = /** @type {AST.CSS.Rule} */ (node.metadata.rule);
|
|
1023
1068
|
|
|
1024
1069
|
if (apply_selector(selectors, rule, element, BACKWARD) || rule_has_animation(rule)) {
|