ripple 0.2.208 → 0.2.210

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +2 -1
  3. package/package.json +2 -6
  4. package/shims/rollup-estree-types.d.ts +1 -1
  5. package/src/compiler/index.d.ts +1 -0
  6. package/src/compiler/index.js +7 -1
  7. package/src/compiler/phases/1-parse/index.js +15 -6
  8. package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
  9. package/src/compiler/phases/2-analyze/index.js +215 -2
  10. package/src/compiler/phases/3-transform/client/index.js +388 -50
  11. package/src/compiler/phases/3-transform/segments.js +123 -39
  12. package/src/compiler/phases/3-transform/server/index.js +266 -13
  13. package/src/compiler/types/index.d.ts +16 -3
  14. package/src/compiler/utils.js +1 -15
  15. package/src/constants.js +0 -2
  16. package/src/helpers.d.ts +4 -0
  17. package/src/html-tree-validation.js +211 -0
  18. package/src/jsx-runtime.d.ts +260 -259
  19. package/src/jsx-runtime.js +12 -12
  20. package/src/runtime/array.js +17 -17
  21. package/src/runtime/create-subscriber.js +1 -1
  22. package/src/runtime/index-client.js +1 -5
  23. package/src/runtime/index-server.js +15 -0
  24. package/src/runtime/internal/client/compat.js +3 -3
  25. package/src/runtime/internal/client/composite.js +6 -1
  26. package/src/runtime/internal/client/head.js +50 -4
  27. package/src/runtime/internal/client/html.js +73 -12
  28. package/src/runtime/internal/client/hydration.js +12 -0
  29. package/src/runtime/internal/client/index.js +1 -1
  30. package/src/runtime/internal/client/portal.js +54 -29
  31. package/src/runtime/internal/client/rpc.js +3 -1
  32. package/src/runtime/internal/client/switch.js +5 -0
  33. package/src/runtime/internal/client/template.js +117 -11
  34. package/src/runtime/internal/client/try.js +1 -0
  35. package/src/runtime/internal/server/index.js +113 -1
  36. package/src/runtime/internal/server/rpc.js +4 -4
  37. package/src/runtime/map.js +2 -2
  38. package/src/runtime/object.js +6 -6
  39. package/src/runtime/proxy.js +12 -11
  40. package/src/runtime/reactive-value.js +9 -1
  41. package/src/runtime/set.js +12 -7
  42. package/src/runtime/url-search-params.js +0 -1
  43. package/src/server/index.js +4 -0
  44. package/src/utils/hashing.js +15 -0
  45. package/src/utils/normalize_css_property_name.js +1 -1
  46. package/tests/client/array/array.mutations.test.ripple +8 -8
  47. package/tests/client/basic/basic.errors.test.ripple +28 -0
  48. package/tests/client/basic/basic.events.test.ripple +6 -3
  49. package/tests/client/basic/basic.utilities.test.ripple +1 -1
  50. package/tests/client/compiler/compiler.regex.test.ripple +10 -8
  51. package/tests/client/composite/composite.generics.test.ripple +5 -2
  52. package/tests/client/dynamic-elements.test.ripple +30 -1
  53. package/tests/client/function-overload-import.ripple +6 -7
  54. package/tests/client/html.test.ripple +0 -1
  55. package/tests/client/object.test.ripple +2 -2
  56. package/tests/client/portal.test.ripple +3 -3
  57. package/tests/client/return.test.ripple +2500 -0
  58. package/tests/client/try.test.ripple +69 -0
  59. package/tests/client/typescript-generics.test.ripple +1 -1
  60. package/tests/client/url/url.derived.test.ripple +1 -1
  61. package/tests/client/url/url.parsing.test.ripple +3 -3
  62. package/tests/client/url/url.partial-removal.test.ripple +7 -7
  63. package/tests/client/url/url.reactivity.test.ripple +15 -15
  64. package/tests/client/url/url.serialization.test.ripple +2 -2
  65. package/tests/hydration/basic.test.js +23 -0
  66. package/tests/hydration/build-components.js +10 -4
  67. package/tests/hydration/compiled/client/basic.js +165 -3
  68. package/tests/hydration/compiled/client/for.js +1140 -23
  69. package/tests/hydration/compiled/client/head.js +234 -0
  70. package/tests/hydration/compiled/client/html.js +135 -0
  71. package/tests/hydration/compiled/client/portal.js +172 -0
  72. package/tests/hydration/compiled/client/reactivity.js +3 -1
  73. package/tests/hydration/compiled/client/return.js +1976 -0
  74. package/tests/hydration/compiled/client/switch.js +162 -0
  75. package/tests/hydration/compiled/server/basic.js +249 -0
  76. package/tests/hydration/compiled/server/events.js +1 -1
  77. package/tests/hydration/compiled/server/for.js +891 -1
  78. package/tests/hydration/compiled/server/head.js +291 -0
  79. package/tests/hydration/compiled/server/html.js +133 -0
  80. package/tests/hydration/compiled/server/if.js +1 -1
  81. package/tests/hydration/compiled/server/portal.js +250 -0
  82. package/tests/hydration/compiled/server/reactivity.js +1 -1
  83. package/tests/hydration/compiled/server/return.js +1969 -0
  84. package/tests/hydration/compiled/server/switch.js +130 -0
  85. package/tests/hydration/components/basic.ripple +55 -0
  86. package/tests/hydration/components/for.ripple +403 -0
  87. package/tests/hydration/components/head.ripple +111 -0
  88. package/tests/hydration/components/html.ripple +38 -0
  89. package/tests/hydration/components/portal.ripple +49 -0
  90. package/tests/hydration/components/return.ripple +564 -0
  91. package/tests/hydration/components/switch.ripple +51 -0
  92. package/tests/hydration/for.test.js +363 -0
  93. package/tests/hydration/head.test.js +105 -0
  94. package/tests/hydration/html.test.js +46 -0
  95. package/tests/hydration/portal.test.js +71 -0
  96. package/tests/hydration/return.test.js +544 -0
  97. package/tests/hydration/switch.test.js +42 -0
  98. package/tests/server/basic.attributes.test.ripple +1 -1
  99. package/tests/server/compiler.test.ripple +22 -0
  100. package/tests/server/composite.test.ripple +5 -2
  101. package/tests/server/html-nesting-validation.test.ripple +237 -0
  102. package/tests/server/return.test.ripple +1379 -0
  103. package/tests/setup-hydration.js +6 -1
  104. package/tests/utils/escaping.test.js +3 -1
  105. package/tests/utils/normalize_css_property_name.test.js +0 -1
  106. package/tests/utils/patterns.test.js +6 -2
  107. package/tests/utils/sanitize_template_string.test.js +3 -2
  108. package/types/server.d.ts +16 -0
package/src/helpers.d.ts CHANGED
@@ -3,3 +3,7 @@ export type RequireAllOrNone<T, K extends keyof T> =
3
3
  | (T & { [P in K]?: never });
4
4
 
5
5
  export type RequiredPresent<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
6
+
7
+ export type Nullable<T> = T | null;
8
+
9
+ export type Nullish<T> = T | null | undefined;
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Map of elements that have certain elements that are not allowed inside them, in the sense that they will auto-close the parent/ancestor element.
3
+ * Theoretically one could take advantage of it but most of the time it will just result in confusing behavior and break when SSR'd.
4
+ * There are more elements that are invalid inside other elements, but they're not auto-closed and so don't break SSR and are therefore not listed here.
5
+ * Based on Svelte's html-tree-validation.js (https://github.com/sveltejs/svelte/blob/main/packages/svelte/src/html-tree-validation.js)
6
+ * @type {Record<string, { direct: string[]} | { descendant: string[]; reset_by?: string[] }>}
7
+ */
8
+ const autoclosing_children = {
9
+ // based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
10
+ li: { direct: ['li'] },
11
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt#technical_summary
12
+ dt: { descendant: ['dt', 'dd'], reset_by: ['dl'] },
13
+ dd: { descendant: ['dt', 'dd'], reset_by: ['dl'] },
14
+ p: {
15
+ descendant: [
16
+ 'address',
17
+ 'article',
18
+ 'aside',
19
+ 'blockquote',
20
+ 'div',
21
+ 'dl',
22
+ 'fieldset',
23
+ 'footer',
24
+ 'form',
25
+ 'h1',
26
+ 'h2',
27
+ 'h3',
28
+ 'h4',
29
+ 'h5',
30
+ 'h6',
31
+ 'header',
32
+ 'hgroup',
33
+ 'hr',
34
+ 'main',
35
+ 'menu',
36
+ 'nav',
37
+ 'ol',
38
+ 'p',
39
+ 'pre',
40
+ 'section',
41
+ 'table',
42
+ 'ul',
43
+ ],
44
+ },
45
+ rt: { descendant: ['rt', 'rp'] },
46
+ rp: { descendant: ['rt', 'rp'] },
47
+ optgroup: { descendant: ['optgroup'] },
48
+ option: { descendant: ['option', 'optgroup'] },
49
+ thead: { direct: ['tbody', 'tfoot'] },
50
+ tbody: { direct: ['tbody', 'tfoot'] },
51
+ tfoot: { direct: ['tbody'] },
52
+ tr: { direct: ['tr', 'tbody'] },
53
+ td: { direct: ['td', 'th', 'tr'] },
54
+ th: { direct: ['td', 'th', 'tr'] },
55
+ };
56
+
57
+ /**
58
+ * Map of elements that have certain elements that are not allowed inside them, in the sense that the browser will somehow repair the HTML.
59
+ * There are more elements that are invalid inside other elements, but they're not repaired and so don't break SSR and are therefore not listed here.
60
+ * @type {Record<string, { direct: string[]} | { descendant: string[]; reset_by?: string[]; only?: string[] } | { only: string[] }>}
61
+ */
62
+ const disallowed_children = {
63
+ ...autoclosing_children,
64
+ form: { descendant: ['form'] },
65
+ a: { descendant: ['a'] },
66
+ button: { descendant: ['button'] },
67
+ h1: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
68
+ h2: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
69
+ h3: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
70
+ h4: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
71
+ h5: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
72
+ h6: { descendant: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },
73
+
74
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd
75
+ tr: { only: ['th', 'td', 'style', 'script', 'template'] },
76
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody
77
+ tbody: { only: ['tr', 'style', 'script', 'template'] },
78
+ thead: { only: ['tr', 'style', 'script', 'template'] },
79
+ tfoot: { only: ['tr', 'style', 'script', 'template'] },
80
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup
81
+ colgroup: { only: ['col', 'template'] },
82
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable
83
+ table: {
84
+ only: ['caption', 'colgroup', 'tbody', 'thead', 'tfoot', 'style', 'script', 'template'],
85
+ },
86
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead
87
+ head: {
88
+ only: [
89
+ 'base',
90
+ 'basefont',
91
+ 'bgsound',
92
+ 'link',
93
+ 'meta',
94
+ 'title',
95
+ 'noscript',
96
+ 'noframes',
97
+ 'style',
98
+ 'script',
99
+ 'template',
100
+ ],
101
+ },
102
+ // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element
103
+ html: { only: ['head', 'body', 'frameset'] },
104
+ frameset: { only: ['frame'] },
105
+ '#document': { only: ['html'] },
106
+ };
107
+
108
+ /**
109
+ * Returns an error message if the tag is not allowed inside the ancestor tag (which is grandparent and above) such that it will result
110
+ * in the browser repairing the HTML, which will likely result in an error during hydration.
111
+ * @param {string} child_tag
112
+ * @param {string[]} ancestors All nodes starting with the parent, up until the ancestor, which means two entries minimum
113
+ * @param {string} [child_loc]
114
+ * @param {string} [ancestor_loc]
115
+ * @returns {string | null}
116
+ */
117
+ export function is_tag_valid_with_ancestor(child_tag, ancestors, child_loc, ancestor_loc) {
118
+ if (child_tag.includes('-')) return null; // custom elements can be anything
119
+
120
+ const ancestor_tag = ancestors[ancestors.length - 1];
121
+ const disallowed = disallowed_children[ancestor_tag];
122
+ if (!disallowed) return null;
123
+
124
+ if ('reset_by' in disallowed && disallowed.reset_by) {
125
+ for (let i = ancestors.length - 2; i >= 0; i--) {
126
+ const ancestor = ancestors[i];
127
+ if (ancestor.includes('-')) return null; // custom elements can be anything
128
+
129
+ // A reset means that forbidden descendants are allowed again
130
+ if (disallowed.reset_by.includes(ancestors[i])) {
131
+ return null;
132
+ }
133
+ }
134
+ }
135
+
136
+ if ('descendant' in disallowed && disallowed.descendant.includes(child_tag)) {
137
+ const child = child_loc ? `\`<${child_tag}>\` (${child_loc})` : `\`<${child_tag}>\``;
138
+ const ancestor = ancestor_loc
139
+ ? `\`<${ancestor_tag}>\` (${ancestor_loc})`
140
+ : `\`<${ancestor_tag}>\``;
141
+
142
+ return `${child} cannot be a descendant of ${ancestor}`;
143
+ }
144
+
145
+ return null;
146
+ }
147
+
148
+ /**
149
+ * Returns an error message if the tag is not allowed inside the parent tag such that it will result
150
+ * in the browser repairing the HTML, which will likely result in an error during hydration.
151
+ * @param {string} child_tag
152
+ * @param {string} parent_tag
153
+ * @param {string} [child_loc]
154
+ * @param {string} [parent_loc]
155
+ * @returns {string | null}
156
+ */
157
+ export function is_tag_valid_with_parent(child_tag, parent_tag, child_loc, parent_loc) {
158
+ if (child_tag.includes('-') || parent_tag?.includes('-')) return null; // custom elements can be anything
159
+
160
+ if (parent_tag === 'template') return null; // no errors or warning should be thrown in immediate children of template tags
161
+
162
+ const disallowed = disallowed_children[parent_tag];
163
+
164
+ const child = child_loc ? `\`<${child_tag}>\` (${child_loc})` : `\`<${child_tag}>\``;
165
+ const parent = parent_loc ? `\`<${parent_tag}>\` (${parent_loc})` : `\`<${parent_tag}>\``;
166
+
167
+ if (disallowed) {
168
+ if ('direct' in disallowed && disallowed.direct.includes(child_tag)) {
169
+ return `${child} cannot be a direct child of ${parent}`;
170
+ }
171
+
172
+ if ('descendant' in disallowed && disallowed.descendant.includes(child_tag)) {
173
+ return `${child} cannot be a child of ${parent}`;
174
+ }
175
+
176
+ if ('only' in disallowed && disallowed.only) {
177
+ if (disallowed.only.includes(child_tag)) {
178
+ return null;
179
+ } else {
180
+ return `${child} cannot be a child of ${parent}. \`<${parent_tag}>\` only allows these children: ${disallowed.only.map((d) => `\`<${d}>\``).join(', ')}`;
181
+ }
182
+ }
183
+ }
184
+
185
+ // These tags are only valid with a few parents that have special child
186
+ // parsing rules - if we're down here, then none of those matched and
187
+ // so we allow it only if we don't know what the parent is, as all other
188
+ // cases are invalid (and we only get into this function if we know the parent).
189
+ switch (child_tag) {
190
+ case 'body':
191
+ case 'caption':
192
+ case 'col':
193
+ case 'colgroup':
194
+ case 'frameset':
195
+ case 'frame':
196
+ case 'head':
197
+ case 'html':
198
+ return `${child} cannot be a child of ${parent}`;
199
+ case 'thead':
200
+ case 'tbody':
201
+ case 'tfoot':
202
+ return `${child} must be the child of a \`<table>\`, not a ${parent}`;
203
+ case 'td':
204
+ case 'th':
205
+ return `${child} must be the child of a \`<tr>\`, not a ${parent}`;
206
+ case 'tr':
207
+ return `${child} must be the child of a \`<thead>\`, \`<tbody>\`, or \`<tfoot>\`, not a ${parent}`;
208
+ }
209
+
210
+ return null;
211
+ }