ripple 0.1.1 → 0.2.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +56 -24
  3. package/src/ai.js +292 -0
  4. package/src/compiler/errors.js +26 -0
  5. package/src/compiler/index.js +26 -0
  6. package/src/compiler/phases/1-parse/index.js +543 -0
  7. package/src/compiler/phases/1-parse/style.js +566 -0
  8. package/src/compiler/phases/2-analyze/index.js +509 -0
  9. package/src/compiler/phases/2-analyze/prune.js +572 -0
  10. package/src/compiler/phases/3-transform/index.js +1572 -0
  11. package/src/compiler/phases/3-transform/segments.js +91 -0
  12. package/src/compiler/phases/3-transform/stylesheet.js +372 -0
  13. package/src/compiler/scope.js +421 -0
  14. package/src/compiler/utils.js +552 -0
  15. package/src/constants.js +4 -0
  16. package/src/jsx-runtime.d.ts +94 -0
  17. package/src/jsx-runtime.js +46 -0
  18. package/src/runtime/array.js +215 -0
  19. package/src/runtime/index.js +39 -0
  20. package/src/runtime/internal/client/blocks.js +247 -0
  21. package/src/runtime/internal/client/constants.js +23 -0
  22. package/src/runtime/internal/client/events.js +223 -0
  23. package/src/runtime/internal/client/for.js +388 -0
  24. package/src/runtime/internal/client/if.js +35 -0
  25. package/src/runtime/internal/client/index.js +53 -0
  26. package/src/runtime/internal/client/operations.js +72 -0
  27. package/src/runtime/internal/client/portal.js +33 -0
  28. package/src/runtime/internal/client/render.js +156 -0
  29. package/src/runtime/internal/client/runtime.js +909 -0
  30. package/src/runtime/internal/client/template.js +51 -0
  31. package/src/runtime/internal/client/try.js +139 -0
  32. package/src/runtime/internal/client/utils.js +16 -0
  33. package/src/utils/ast.js +214 -0
  34. package/src/utils/builders.js +733 -0
  35. package/src/utils/patterns.js +23 -0
  36. package/src/utils/sanitize_template_string.js +7 -0
  37. package/test-mappings.js +0 -0
  38. package/types/index.d.ts +2 -0
  39. package/.npmignore +0 -2
  40. package/History.md +0 -3
  41. package/Readme.md +0 -151
  42. package/lib/exec/index.js +0 -60
  43. package/ripple.js +0 -645
@@ -0,0 +1,421 @@
1
+ import is_reference from 'is-reference';
2
+ import { extract_identifiers, object, unwrap_pattern } from '../utils/ast.js';
3
+ import { walk } from 'zimmerframe';
4
+ import { is_reserved } from './utils.js';
5
+ import * as b from '../utils/builders.js';
6
+
7
+ export function create_scopes(ast, root, parent) {
8
+ const scopes = new Map();
9
+ const scope = new Scope(root, parent, false);
10
+ scopes.set(ast, scope);
11
+
12
+ const state = { scope };
13
+ const references = [];
14
+ const updates = [];
15
+
16
+ function add_params(scope, params) {
17
+ for (const param of params) {
18
+ for (const node of extract_identifiers(param)) {
19
+ scope.declare(node, 'normal', param.type === 'RestElement' ? 'rest_param' : 'param');
20
+ }
21
+ }
22
+ }
23
+
24
+ const create_block_scope = (node, { state, next }) => {
25
+ const scope = state.scope.child(true);
26
+ scopes.set(node, scope);
27
+
28
+ next({ scope });
29
+ };
30
+
31
+ walk(ast, state, {
32
+ // references
33
+ Identifier(node, { path, state }) {
34
+ const parent = path.at(-1);
35
+ if (
36
+ parent &&
37
+ is_reference(node, /** @type {Node} */ (parent)) &&
38
+ // TSTypeAnnotation, TSInterfaceDeclaration etc - these are normally already filtered out,
39
+ // but for the migration they aren't, so we need to filter them out here
40
+ // TODO -> once migration script is gone we can remove this check
41
+ !parent.type.startsWith('TS')
42
+ ) {
43
+ references.push([state.scope, { node, path: path.slice() }]);
44
+ }
45
+ },
46
+
47
+ AssignmentExpression(node, { state, next }) {
48
+ updates.push([state.scope, node.left]);
49
+ next();
50
+ },
51
+
52
+ UpdateExpression(node, { state, next }) {
53
+ updates.push([state.scope, /** @type {Identifier | MemberExpression} */ (node.argument)]);
54
+ next();
55
+ },
56
+
57
+ ImportDeclaration(node, { state }) {
58
+ for (const specifier of node.specifiers) {
59
+ state.scope.declare(specifier.local, 'normal', 'import', node);
60
+ }
61
+ },
62
+
63
+ Component(node, { state, next }) {
64
+ const scope = state.scope.child();
65
+ scopes.set(node, scope);
66
+
67
+ if (node.id) scope.declare(node.id, 'normal', 'component');
68
+
69
+ add_params(scope, node.params);
70
+ next({ scope });
71
+ },
72
+
73
+ Fragment(node, { state, next }) {
74
+ const scope = state.scope.child();
75
+ scopes.set(node, scope);
76
+
77
+ if (node.id) scope.declare(node.id, 'normal', 'fragment');
78
+
79
+ add_params(scope, node.params);
80
+ next({ scope });
81
+ },
82
+
83
+ Element(node, { state, next }) {
84
+ const scope = state.scope.child();
85
+ scopes.set(node, scope);
86
+
87
+ scope.declare(node, 'normal', 'element');
88
+
89
+ next({ scope });
90
+ },
91
+
92
+ FunctionExpression(node, { state, next }) {
93
+ const scope = state.scope.child();
94
+ scopes.set(node, scope);
95
+
96
+ if (node.id) scope.declare(node.id, 'normal', 'function');
97
+
98
+ add_params(scope, node.params);
99
+ next({ scope });
100
+ },
101
+
102
+ FunctionDeclaration(node, { state, next }) {
103
+ if (node.id) state.scope.declare(node.id, 'normal', 'function', node);
104
+
105
+ const scope = state.scope.child();
106
+ scopes.set(node, scope);
107
+
108
+ add_params(scope, node.params);
109
+ next({ scope });
110
+ },
111
+
112
+ ArrowFunctionExpression(node, { state, next }) {
113
+ const scope = state.scope.child();
114
+ scopes.set(node, scope);
115
+
116
+ add_params(scope, node.params);
117
+ next({ scope });
118
+ },
119
+
120
+ ForStatement: create_block_scope,
121
+ ForInStatement: create_block_scope,
122
+ ForOfStatement: create_block_scope,
123
+ SwitchStatement: create_block_scope,
124
+ BlockStatement(node, context) {
125
+ const parent = context.path.at(-1);
126
+ if (
127
+ parent?.type === 'FunctionDeclaration' ||
128
+ parent?.type === 'FunctionExpression' ||
129
+ parent?.type === 'ArrowFunctionExpression'
130
+ ) {
131
+ // We already created a new scope for the function
132
+ context.next();
133
+ } else {
134
+ create_block_scope(node, context);
135
+ }
136
+ },
137
+
138
+ Eval(node, context) {
139
+ const finalizer = node.finalizer;
140
+
141
+ if (finalizer !== null) {
142
+ for (const node of finalizer.body) {
143
+ context.visit(node);
144
+ }
145
+ }
146
+ },
147
+
148
+ ClassDeclaration(node, { state, next }) {
149
+ if (node.id) state.scope.declare(node.id, 'normal', 'let', node);
150
+ next();
151
+ },
152
+
153
+ VariableDeclaration(node, { state, path, next }) {
154
+ for (const declarator of node.declarations) {
155
+ /** @type {Binding[]} */
156
+ const bindings = [];
157
+
158
+ state.scope.declarators.set(declarator, bindings);
159
+
160
+ for (const id of extract_identifiers(declarator.id)) {
161
+ const binding = state.scope.declare(id, 'normal', node.kind, declarator.init);
162
+ bindings.push(binding);
163
+ }
164
+ }
165
+
166
+ next();
167
+ },
168
+
169
+ CatchClause(node, { state, next }) {
170
+ if (node.param) {
171
+ const scope = state.scope.child(true);
172
+ scopes.set(node, scope);
173
+
174
+ for (const id of extract_identifiers(node.param)) {
175
+ scope.declare(id, 'normal', 'let');
176
+ }
177
+
178
+ next({ scope });
179
+ } else {
180
+ next();
181
+ }
182
+ }
183
+ });
184
+
185
+ for (const [scope, { node, path }] of references) {
186
+ scope.reference(node, path);
187
+ }
188
+
189
+ for (const [scope, node] of updates) {
190
+ for (const expression of unwrap_pattern(node)) {
191
+ const left = object(expression);
192
+ const binding = left && scope.get(left.name);
193
+
194
+ if (binding !== null && left !== binding.node) {
195
+ binding.updated = true;
196
+
197
+ if (left === expression) {
198
+ binding.reassigned = true;
199
+ } else {
200
+ binding.mutated = true;
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ return {
207
+ scope,
208
+ scopes
209
+ };
210
+ }
211
+
212
+ export class Scope {
213
+ /** @type {ScopeRoot} */
214
+ root;
215
+
216
+ /**
217
+ * The immediate parent scope
218
+ * @type {Scope | null}
219
+ */
220
+ parent;
221
+
222
+ /**
223
+ * Whether or not `var` declarations are contained by this scope
224
+ * @type {boolean}
225
+ */
226
+ #porous;
227
+
228
+ /**
229
+ * A map of every identifier declared by this scope, and all the
230
+ * identifiers that reference it
231
+ * @type {Map<string, Binding>}
232
+ */
233
+ declarations = new Map();
234
+
235
+ /**
236
+ * A map of declarators to the bindings they declare
237
+ * @type {Map<VariableDeclarator | AST.LetDirective, Binding[]>}
238
+ */
239
+ declarators = new Map();
240
+
241
+ /**
242
+ * A set of all the names referenced with this scope
243
+ * — useful for generating unique names
244
+ * @type {Map<string, { node: Identifier; path: AST.SvelteNode[] }[]>}
245
+ */
246
+ references = new Map();
247
+
248
+ /**
249
+ * The scope depth allows us to determine if a state variable is referenced in its own scope,
250
+ * which is usually an error. Block statements do not increase this value
251
+ */
252
+ function_depth = 0;
253
+
254
+ /**
255
+ * If tracing of reactive dependencies is enabled for this scope
256
+ * @type {null | Expression}
257
+ */
258
+ tracing = null;
259
+
260
+ /**
261
+ *
262
+ * @param {ScopeRoot} root
263
+ * @param {Scope | null} parent
264
+ * @param {boolean} porous
265
+ */
266
+ constructor(root, parent, porous) {
267
+ this.root = root;
268
+ this.parent = parent;
269
+ this.#porous = porous;
270
+ this.function_depth = parent ? parent.function_depth + (porous ? 0 : 1) : 0;
271
+ }
272
+
273
+ /**
274
+ * @param {Identifier} node
275
+ * @param {Binding['kind']} kind
276
+ * @param {DeclarationKind} declaration_kind
277
+ * @param {null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | AST.EachBlock | AST.SnippetBlock} initial
278
+ * @returns {Binding}
279
+ */
280
+ declare(node, kind, declaration_kind, initial = null) {
281
+ if (this.parent) {
282
+ if (declaration_kind === 'var' && this.#porous) {
283
+ return this.parent.declare(node, kind, declaration_kind);
284
+ }
285
+
286
+ if (declaration_kind === 'import') {
287
+ return this.parent.declare(node, kind, declaration_kind, initial);
288
+ }
289
+ }
290
+
291
+ if (this.declarations.has(node.name)) {
292
+ // This also errors on var/function types, but that's arguably a good thing
293
+ e.declaration_duplicate(node, node.name);
294
+ }
295
+
296
+ /** @type {Binding} */
297
+ const binding = {
298
+ node,
299
+ references: [],
300
+ initial,
301
+ reassigned: false,
302
+ mutated: false,
303
+ updated: false,
304
+ scope: this,
305
+ kind,
306
+ declaration_kind,
307
+ is_called: false,
308
+ prop_alias: null,
309
+ metadata: null
310
+ };
311
+
312
+ this.declarations.set(node.name, binding);
313
+ this.root.conflicts.add(node.name);
314
+ return binding;
315
+ }
316
+
317
+ child(porous = false) {
318
+ return new Scope(this.root, this, porous);
319
+ }
320
+
321
+ /**
322
+ * @param {string} preferred_name
323
+ * @returns {string}
324
+ */
325
+ generate(preferred_name) {
326
+ if (this.#porous) {
327
+ return /** @type {Scope} */ (this.parent).generate(preferred_name);
328
+ }
329
+
330
+ preferred_name = preferred_name.replace(/[^a-zA-Z0-9_$]/g, '_').replace(/^[0-9]/, '_');
331
+ let name = preferred_name;
332
+ let n = 1;
333
+
334
+ while (
335
+ this.references.has(name) ||
336
+ this.declarations.has(name) ||
337
+ this.root.conflicts.has(name) ||
338
+ is_reserved(name)
339
+ ) {
340
+ name = `${preferred_name}_${n++}`;
341
+ }
342
+
343
+ this.references.set(name, []);
344
+ this.root.conflicts.add(name);
345
+ return name;
346
+ }
347
+
348
+ /**
349
+ * @param {string} name
350
+ * @returns {Binding | null}
351
+ */
352
+ get(name) {
353
+ return this.declarations.get(name) ?? this.parent?.get(name) ?? null;
354
+ }
355
+
356
+ /**
357
+ * @param {VariableDeclarator | AST.LetDirective} node
358
+ * @returns {Binding[]}
359
+ */
360
+ get_bindings(node) {
361
+ const bindings = this.declarators.get(node);
362
+ if (!bindings) {
363
+ throw new Error('No binding found for declarator');
364
+ }
365
+ return bindings;
366
+ }
367
+
368
+ /**
369
+ * @param {string} name
370
+ * @returns {Scope | null}
371
+ */
372
+ owner(name) {
373
+ return this.declarations.has(name) ? this : this.parent && this.parent.owner(name);
374
+ }
375
+
376
+ /**
377
+ * @param {Identifier} node
378
+ * @param {AST.SvelteNode[]} path
379
+ */
380
+ reference(node, path) {
381
+ path = [...path]; // ensure that mutations to path afterwards don't affect this reference
382
+ let references = this.references.get(node.name);
383
+
384
+ if (!references) this.references.set(node.name, (references = []));
385
+
386
+ references.push({ node, path });
387
+
388
+ const binding = this.declarations.get(node.name);
389
+ if (binding) {
390
+ binding.references.push({ node, path });
391
+ } else if (this.parent) {
392
+ this.parent.reference(node, path);
393
+ } else {
394
+ // no binding was found, and this is the top level scope,
395
+ // which means this is a global
396
+ this.root.conflicts.add(node.name);
397
+ }
398
+ }
399
+ }
400
+
401
+ export class ScopeRoot {
402
+ /** @type {Set<string>} */
403
+ conflicts = new Set();
404
+
405
+ /**
406
+ * @param {string} preferred_name
407
+ */
408
+ unique(preferred_name) {
409
+ preferred_name = preferred_name.replace(/[^a-zA-Z0-9_$]/g, '_');
410
+ let final_name = preferred_name;
411
+ let n = 1;
412
+
413
+ while (this.conflicts.has(final_name)) {
414
+ final_name = `${preferred_name}_${n++}`;
415
+ }
416
+
417
+ this.conflicts.add(final_name);
418
+ const id = b.id(final_name);
419
+ return id;
420
+ }
421
+ }