ripple 0.2.67 → 0.2.69

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 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.67",
6
+ "version": "0.2.69",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index.js",
9
9
  "main": "src/runtime/index.js",
@@ -192,6 +192,135 @@ function RipplePlugin(config) {
192
192
  return super.parseExportDefaultDeclaration();
193
193
  }
194
194
 
195
+ parseForStatement(node) {
196
+ this.next()
197
+ let awaitAt = (this.options.ecmaVersion >= 9 && this.canAwait && this.eatContextual("await")) ? this.lastTokStart : -1
198
+ this.labels.push({kind: "loop"})
199
+ this.enterScope(0)
200
+ this.expect(tt.parenL)
201
+
202
+ if (this.type === tt.semi) {
203
+ if (awaitAt > -1) this.unexpected(awaitAt)
204
+ return this.parseFor(node, null)
205
+ }
206
+
207
+ let isLet = this.isLet()
208
+ if (this.type === tt._var || this.type === tt._const || isLet) {
209
+ let init = this.startNode(), kind = isLet ? "let" : this.value
210
+ this.next()
211
+ this.parseVar(init, true, kind)
212
+ this.finishNode(init, "VariableDeclaration")
213
+ return this.parseForAfterInitWithIndex(node, init, awaitAt)
214
+ }
215
+
216
+ // Handle other cases like using declarations if they exist
217
+ let startsWithLet = this.isContextual("let"), isForOf = false
218
+ let usingKind = (this.isUsing && this.isUsing(true)) ? "using" : (this.isAwaitUsing && this.isAwaitUsing(true)) ? "await using" : null
219
+ if (usingKind) {
220
+ let init = this.startNode()
221
+ this.next()
222
+ if (usingKind === "await using") {
223
+ if (!this.canAwait) {
224
+ this.raise(this.start, "Await using cannot appear outside of async function")
225
+ }
226
+ this.next()
227
+ }
228
+ this.parseVar(init, true, usingKind)
229
+ this.finishNode(init, "VariableDeclaration")
230
+ return this.parseForAfterInitWithIndex(node, init, awaitAt)
231
+ }
232
+
233
+ let containsEsc = this.containsEsc
234
+ let refDestructuringErrors = {}
235
+ let initPos = this.start
236
+ let init = awaitAt > -1
237
+ ? this.parseExprSubscripts(refDestructuringErrors, "await")
238
+ : this.parseExpression(true, refDestructuringErrors)
239
+
240
+ if (this.type === tt._in || (isForOf = this.options.ecmaVersion >= 6 && this.isContextual("of"))) {
241
+ if (awaitAt > -1) { // implies `ecmaVersion >= 9`
242
+ if (this.type === tt._in) this.unexpected(awaitAt)
243
+ node.await = true
244
+ } else if (isForOf && this.options.ecmaVersion >= 8) {
245
+ if (init.start === initPos && !containsEsc && init.type === "Identifier" && init.name === "async") this.unexpected()
246
+ else if (this.options.ecmaVersion >= 9) node.await = false
247
+ }
248
+ if (startsWithLet && isForOf) this.raise(init.start, "The left-hand side of a for-of loop may not start with 'let'.")
249
+ this.toAssignable(init, false, refDestructuringErrors)
250
+ this.checkLValPattern(init)
251
+ return this.parseForInWithIndex(node, init)
252
+ } else {
253
+ this.checkExpressionErrors(refDestructuringErrors, true)
254
+ }
255
+
256
+ if (awaitAt > -1) this.unexpected(awaitAt)
257
+ return this.parseFor(node, init)
258
+ }
259
+
260
+ parseForAfterInitWithIndex(node, init, awaitAt) {
261
+ if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1) {
262
+ if (this.options.ecmaVersion >= 9) {
263
+ if (this.type === tt._in) {
264
+ if (awaitAt > -1) this.unexpected(awaitAt)
265
+ } else node.await = awaitAt > -1
266
+ }
267
+ return this.parseForInWithIndex(node, init)
268
+ }
269
+ if (awaitAt > -1) this.unexpected(awaitAt)
270
+ return this.parseFor(node, init)
271
+ }
272
+
273
+ parseForInWithIndex(node, init) {
274
+ const isForIn = this.type === tt._in
275
+ this.next()
276
+
277
+ if (
278
+ init.type === "VariableDeclaration" &&
279
+ init.declarations[0].init != null &&
280
+ (
281
+ !isForIn ||
282
+ this.options.ecmaVersion < 8 ||
283
+ this.strict ||
284
+ init.kind !== "var" ||
285
+ init.declarations[0].id.type !== "Identifier"
286
+ )
287
+ ) {
288
+ this.raise(
289
+ init.start,
290
+ `${isForIn ? "for-in" : "for-of"} loop variable declaration may not have an initializer`
291
+ )
292
+ }
293
+
294
+ node.left = init
295
+ node.right = isForIn ? this.parseExpression() : this.parseMaybeAssign()
296
+
297
+ // Check for our extended syntax: "; index varName"
298
+ if (!isForIn && this.type === tt.semi) {
299
+ this.next() // consume ';'
300
+
301
+ if (this.isContextual('index')) {
302
+ this.next() // consume 'index'
303
+
304
+ if (this.type === tt.name) {
305
+ node.index = this.parseIdent()
306
+ } else {
307
+ this.raise(this.start, 'Expected identifier after "index" keyword')
308
+ }
309
+ } else {
310
+ this.raise(this.start, 'Expected "index" keyword after semicolon in for-of loop')
311
+ }
312
+ } else if (!isForIn) {
313
+ // Set index to null for standard for-of loops
314
+ node.index = null
315
+ }
316
+
317
+ this.expect(tt.parenR)
318
+ node.body = this.parseStatement("for")
319
+ this.exitScope()
320
+ this.labels.pop()
321
+ return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement")
322
+ }
323
+
195
324
  shouldParseExportStatement() {
196
325
  if (super.shouldParseExportStatement()) {
197
326
  return true;
@@ -791,6 +920,8 @@ function RipplePlugin(config) {
791
920
  return node;
792
921
  }
793
922
 
923
+
924
+
794
925
  if (this.type.label === '@') {
795
926
  // Try to parse as an expression statement first using tryParse
796
927
  // This allows us to handle Ripple @ syntax like @count++ without
@@ -5,7 +5,7 @@ import {
5
5
  get_delegated_event,
6
6
  is_element_dom_element,
7
7
  is_inside_component,
8
- is_ripple_import,
8
+ is_ripple_track_call,
9
9
  is_void_element,
10
10
  } from '../../utils.js';
11
11
  import { extract_paths } from '../../../utils/ast.js';
@@ -87,6 +87,10 @@ const visitors = {
87
87
  next(scope !== undefined && scope !== state.scope ? { ...state, scope } : state);
88
88
  },
89
89
 
90
+ Program(_, context) {
91
+ return context.next({ ...context.state, function_depth: 0, expression: null });
92
+ },
93
+
90
94
  Identifier(node, context) {
91
95
  const binding = context.state.scope.get(node.name);
92
96
  const parent = context.path.at(-1);
@@ -133,6 +137,16 @@ const visitors = {
133
137
  },
134
138
 
135
139
  CallExpression(node, context) {
140
+ const callee = node.callee;
141
+
142
+ if (context.state.function_depth === 0 && is_ripple_track_call(callee, context)) {
143
+ error(
144
+ '`track` can only be used within a reactive context, such as a component, function or class that is used or created from a component',
145
+ context.state.analysis.module.filename,
146
+ node,
147
+ );
148
+ }
149
+
136
150
  if (context.state.metadata?.tracking === false) {
137
151
  context.state.metadata.tracking = true;
138
152
  }
@@ -145,27 +159,20 @@ const visitors = {
145
159
  },
146
160
 
147
161
  VariableDeclaration(node, context) {
148
- const { state, visit, path } = context;
162
+ const { state, visit } = context;
149
163
 
150
164
  for (const declarator of node.declarations) {
151
165
  if (is_inside_component(context) && node.kind === 'var') {
152
166
  error(
153
- 'var declarations are not allowed in components, use let or const instead',
167
+ '`var` declarations are not allowed in components, use let or const instead',
154
168
  state.analysis.module.filename,
155
169
  declarator,
156
170
  );
157
171
  }
158
172
  const metadata = { tracking: false, await: false };
159
- const parent = path.at(-1);
160
- const init_is_untracked =
161
- declarator.init !== null &&
162
- declarator.init.type === 'CallExpression' &&
163
- is_ripple_import(declarator.init.callee, context) &&
164
- declarator.init.callee.type === 'Identifier' &&
165
- (declarator.init.callee.name === 'untrack' || declarator.init.callee.name === 'deferred');
166
173
 
167
174
  if (declarator.id.type === 'Identifier') {
168
- visit(declarator, state);
175
+ visit(declarator, state);
169
176
  } else {
170
177
  const paths = extract_paths(declarator.id);
171
178
 
@@ -234,7 +241,7 @@ const visitors = {
234
241
  }
235
242
  const elements = [];
236
243
 
237
- context.next({ ...context.state, elements });
244
+ context.next({ ...context.state, elements, function_depth: context.state.function_depth + 1 });
238
245
 
239
246
  const css = node.css;
240
247
 
@@ -262,6 +269,21 @@ const visitors = {
262
269
  return context.next();
263
270
  }
264
271
 
272
+ if (node.index) {
273
+ const state = context.state;
274
+ const scope = state.scopes.get(node);
275
+ const binding = scope.get(node.index.name);
276
+ binding.kind = 'index'
277
+
278
+ if (binding !== null) {
279
+ binding.transform = {
280
+ read: (node) => {
281
+ return b.call('_$_.get', node)
282
+ },
283
+ };
284
+ }
285
+ }
286
+
265
287
  node.metadata = {
266
288
  has_template: false,
267
289
  };