ripple 0.2.185 → 0.2.187
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 +1 -16
- package/src/compiler/phases/2-analyze/prune.js +48 -3
- package/src/compiler/phases/3-transform/client/index.js +35 -23
- package/src/compiler/phases/3-transform/segments.js +313 -62
- 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 +22 -0
- package/src/compiler/types/parse.d.ts +6 -0
- package/src/compiler/utils.js +4 -2
- package/src/runtime/internal/client/switch.js +60 -16
- package/tests/client/switch.test.ripple +138 -2
- package/tests/server/switch.test.ripple +44 -1
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.187",
|
|
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.187"
|
|
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,25 +422,11 @@ const visitors = {
|
|
|
423
422
|
context.visit(node.discriminant, context.state);
|
|
424
423
|
|
|
425
424
|
for (const switch_case of node.cases) {
|
|
426
|
-
//
|
|
425
|
+
// Skip empty cases
|
|
427
426
|
if (switch_case.consequent.length === 0) {
|
|
428
427
|
continue;
|
|
429
428
|
}
|
|
430
429
|
|
|
431
|
-
// Validate that each cases ends in a break statement, except for the last case
|
|
432
|
-
const last = switch_case.consequent?.[switch_case.consequent.length - 1];
|
|
433
|
-
|
|
434
|
-
if (
|
|
435
|
-
last.type !== 'BreakStatement' &&
|
|
436
|
-
node.cases.indexOf(switch_case) !== node.cases.length - 1
|
|
437
|
-
) {
|
|
438
|
-
error(
|
|
439
|
-
'Template switch cases must end with a break statement (with the exception of the last case).',
|
|
440
|
-
context.state.analysis.module.filename,
|
|
441
|
-
switch_case,
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
430
|
node.metadata = {
|
|
446
431
|
...node.metadata,
|
|
447
432
|
has_template: false,
|
|
@@ -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)) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
/** @import * as AST from 'estree' */
|
|
2
|
-
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
3
|
-
/** @import { SourceMapMappings } from '@jridgewell/sourcemap-codec' */
|
|
4
|
-
/** @import * as ESRap from 'esrap' */
|
|
5
1
|
/**
|
|
2
|
+
@import * as AST from 'estree';
|
|
3
|
+
@import * as ESTreeJSX from 'estree-jsx';
|
|
4
|
+
@import { SourceMapMappings } from '@jridgewell/sourcemap-codec';
|
|
6
5
|
@import {
|
|
7
6
|
AnalysisResult,
|
|
8
7
|
TransformClientContext,
|
|
@@ -14,8 +13,10 @@
|
|
|
14
13
|
} from '#compiler';
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
|
-
/**
|
|
18
|
-
|
|
16
|
+
/**
|
|
17
|
+
@typedef {Map<number, {offset: number, delta: number}>} PostProcessingChanges;
|
|
18
|
+
@typedef {number[]} LineOffsets;
|
|
19
|
+
*/
|
|
19
20
|
|
|
20
21
|
import { walk } from 'zimmerframe';
|
|
21
22
|
import path from 'node:path';
|
|
@@ -1829,31 +1830,41 @@ const visitors = {
|
|
|
1829
1830
|
const statements = [];
|
|
1830
1831
|
const cases = [];
|
|
1831
1832
|
|
|
1832
|
-
let
|
|
1833
|
-
|
|
1833
|
+
let id_gen = 0;
|
|
1834
|
+
let counter = 0;
|
|
1834
1835
|
for (const switch_case of node.cases) {
|
|
1835
1836
|
const case_body = [];
|
|
1837
|
+
const consequent = switch_case.consequent;
|
|
1838
|
+
|
|
1839
|
+
if (consequent.length !== 0) {
|
|
1840
|
+
const consequent_scope = context.state.scopes.get(consequent) || context.state.scope;
|
|
1836
1841
|
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1842
|
+
const block = transform_body(consequent, {
|
|
1843
|
+
...context,
|
|
1844
|
+
state: { ...context.state, scope: consequent_scope },
|
|
1845
|
+
});
|
|
1846
|
+
const has_break = consequent.some((stmt) => stmt.type === 'BreakStatement');
|
|
1847
|
+
const is_last = counter === node.cases.length - 1;
|
|
1848
|
+
const is_default = switch_case.test == null;
|
|
1840
1849
|
const consequent_id = context.state.scope.generate(
|
|
1841
|
-
'switch_case_' + (
|
|
1842
|
-
);
|
|
1843
|
-
const consequent = b.block(
|
|
1844
|
-
transform_body(switch_case.consequent, {
|
|
1845
|
-
...context,
|
|
1846
|
-
state: { ...context.state, scope: consequent_scope },
|
|
1847
|
-
}),
|
|
1850
|
+
'switch_case_' + (is_default ? 'default' : id_gen),
|
|
1848
1851
|
);
|
|
1849
1852
|
|
|
1850
|
-
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('__anchor')],
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
+
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('__anchor')], b.block(block))));
|
|
1854
|
+
case_body.push(
|
|
1855
|
+
b.stmt(b.call(b.member(b.id('result'), b.id('push'), false), b.id(consequent_id))),
|
|
1856
|
+
);
|
|
1853
1857
|
|
|
1854
|
-
|
|
1858
|
+
// in js, `default:` can be in the middle without a break
|
|
1859
|
+
// so we only add return for the last case or cases with a break
|
|
1860
|
+
if (has_break || is_last) {
|
|
1861
|
+
case_body.push(b.return(b.id('result')));
|
|
1862
|
+
}
|
|
1863
|
+
id_gen++;
|
|
1855
1864
|
}
|
|
1856
1865
|
|
|
1866
|
+
counter++;
|
|
1867
|
+
|
|
1857
1868
|
cases.push(
|
|
1858
1869
|
b.switch_case(
|
|
1859
1870
|
switch_case.test ? /** @type {AST.Expression} */ (context.visit(switch_case.test)) : null,
|
|
@@ -1869,6 +1880,7 @@ const visitors = {
|
|
|
1869
1880
|
id,
|
|
1870
1881
|
b.thunk(
|
|
1871
1882
|
b.block([
|
|
1883
|
+
b.var(b.id('result'), b.array([])),
|
|
1872
1884
|
b.switch(/** @type {AST.Expression} */ (context.visit(node.discriminant)), cases),
|
|
1873
1885
|
]),
|
|
1874
1886
|
),
|
|
@@ -2996,7 +3008,7 @@ function create_tsx_with_typescript_support() {
|
|
|
2996
3008
|
context.write(node.computed ? ']: ' : ': ');
|
|
2997
3009
|
context.visit(node.value);
|
|
2998
3010
|
} else {
|
|
2999
|
-
base_tsx.Property?.(node,
|
|
3011
|
+
base_tsx.Property?.(node, context);
|
|
3000
3012
|
}
|
|
3001
3013
|
} else {
|
|
3002
3014
|
// Use default handler for non-component properties
|