@hyperframes/parsers 0.7.92 → 0.7.93

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.
@@ -171,8 +171,79 @@ function containsTimelineCall(node, timelineVar) {
171
171
  function rangeOf(node) {
172
172
  return typeof node.start === "number" && typeof node.end === "number" ? [node.start, node.end] : void 0;
173
173
  }
174
+ var SAFE_DEFAULT_NODES = /* @__PURE__ */ new Set([
175
+ "ArrayExpression",
176
+ "BinaryExpression",
177
+ "ChainExpression",
178
+ "ConditionalExpression",
179
+ "Identifier",
180
+ "Literal",
181
+ "LogicalExpression",
182
+ "MemberExpression",
183
+ "ObjectExpression",
184
+ "Property",
185
+ "SpreadElement",
186
+ "TemplateElement",
187
+ "TemplateLiteral",
188
+ "UnaryExpression"
189
+ ]);
190
+ function isSafeDefaultExpression(node, earlierParams) {
191
+ let safe = true;
192
+ const visit = (current, parent, key) => {
193
+ if (!isNode(current) || !safe) return;
194
+ if (!SAFE_DEFAULT_NODES.has(current.type)) {
195
+ safe = false;
196
+ return;
197
+ }
198
+ if (current.type === "UnaryExpression" && current.operator === "delete") {
199
+ safe = false;
200
+ return;
201
+ }
202
+ if (current.type === "Identifier") {
203
+ const nonValue = parent && key ? isNonValueIdentifierSlot(parent, key) : false;
204
+ if (!nonValue && current.name !== "undefined" && !earlierParams.has(current.name)) {
205
+ safe = false;
206
+ }
207
+ return;
208
+ }
209
+ for (const childKey of Object.keys(current)) {
210
+ if (SKIP_KEYS.has(childKey)) continue;
211
+ const child = current[childKey];
212
+ if (Array.isArray(child)) {
213
+ for (const item of child) visit(item, current, childKey);
214
+ } else {
215
+ visit(child, current, childKey);
216
+ }
217
+ }
218
+ };
219
+ visit(node);
220
+ return safe;
221
+ }
222
+ var SUPPORTED_PARAMS_CACHE = /* @__PURE__ */ new WeakMap();
223
+ function supportedParam(param, earlier) {
224
+ if (param.type === "Identifier") return { name: param.name };
225
+ if (param.type !== "AssignmentPattern" || param.left?.type !== "Identifier") return null;
226
+ if (!isSafeDefaultExpression(param.right, earlier)) return null;
227
+ return { name: param.left.name, defaultExpression: param.right };
228
+ }
229
+ function supportedParams(fn) {
230
+ if (SUPPORTED_PARAMS_CACHE.has(fn)) return SUPPORTED_PARAMS_CACHE.get(fn) ?? null;
231
+ const params = [];
232
+ const earlier = /* @__PURE__ */ new Set();
233
+ for (const param of fn.params ?? []) {
234
+ const parsed = supportedParam(param, earlier);
235
+ if (!parsed) {
236
+ SUPPORTED_PARAMS_CACHE.set(fn, null);
237
+ return null;
238
+ }
239
+ params.push(parsed);
240
+ earlier.add(parsed.name);
241
+ }
242
+ SUPPORTED_PARAMS_CACHE.set(fn, params);
243
+ return params;
244
+ }
174
245
  function isShapeEligible(fn) {
175
- return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && !(fn.params ?? []).some((p) => p.type !== "Identifier");
246
+ return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && supportedParams(fn) !== null;
176
247
  }
177
248
  function callsAny(node, names) {
178
249
  let hit = false;
@@ -222,20 +293,55 @@ function timelineBuildingNames(candidates, timelineVar) {
222
293
  function bump(counts, key) {
223
294
  counts.set(key, (counts.get(key) ?? 0) + 1);
224
295
  }
296
+ function undefinedIdentifier() {
297
+ return { type: "Identifier", name: "undefined" };
298
+ }
299
+ function isExplicitUndefined(node) {
300
+ return node?.type === "Identifier" && node.name === "undefined" || node?.type === "UnaryExpression" && node.operator === "void" && node.argument?.type === "Literal" && node.argument.value === 0;
301
+ }
302
+ function resolveHelperBindings(call, params) {
303
+ if (call.arguments?.some((arg) => arg?.type === "SpreadElement")) return null;
304
+ const bindings = /* @__PURE__ */ new Map();
305
+ for (let i = 0; i < params.length; i++) {
306
+ const param = params[i];
307
+ const arg = call.arguments?.[i];
308
+ if (arg && !isExplicitUndefined(arg)) {
309
+ bindings.set(param.name, arg);
310
+ } else if (param.defaultExpression) {
311
+ bindings.set(param.name, substituteParams(cloneNode(param.defaultExpression), bindings));
312
+ } else {
313
+ bindings.set(param.name, undefinedIdentifier());
314
+ }
315
+ }
316
+ return bindings;
317
+ }
318
+ function statementHelperCall(node, names) {
319
+ if (node.type !== "ExpressionStatement") return void 0;
320
+ const expression = node.expression;
321
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier") {
322
+ return void 0;
323
+ }
324
+ return names.has(expression.callee.name) ? expression : void 0;
325
+ }
225
326
  function safelyDroppable(program, candidates) {
226
327
  const names = new Set(candidates.keys());
227
328
  const totalIds = /* @__PURE__ */ new Map();
228
329
  const stmtCalls = /* @__PURE__ */ new Map();
330
+ const unbindable = /* @__PURE__ */ new Set();
229
331
  walkNodes(program, (n) => {
230
332
  if (n.type === "Identifier" && names.has(n.name)) bump(totalIds, n.name);
231
- const e = n.type === "ExpressionStatement" ? n.expression : void 0;
232
- if (e?.type === "CallExpression" && e.callee?.type === "Identifier" && names.has(e.callee.name)) {
233
- bump(stmtCalls, e.callee.name);
234
- }
333
+ const call = statementHelperCall(n, names);
334
+ if (!call) return;
335
+ bump(stmtCalls, call.callee.name);
336
+ const fn = candidates.get(call.callee.name);
337
+ const params = fn && supportedParams(fn);
338
+ if (!params || !resolveHelperBindings(call, params)) unbindable.add(call.callee.name);
235
339
  });
236
340
  const safe = /* @__PURE__ */ new Map();
237
341
  for (const [name, fn] of candidates) {
238
- if ((totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) safe.set(name, fn);
342
+ if (!unbindable.has(name) && (totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) {
343
+ safe.set(name, fn);
344
+ }
239
345
  }
240
346
  return safe;
241
347
  }
@@ -278,11 +384,11 @@ function expandBody(bodyStmts, bindings, prov, ctx) {
278
384
  }
279
385
  function inlineHelper(call, ctx) {
280
386
  const fn = ctx.helpers.get(call.callee.name);
281
- const bindings = /* @__PURE__ */ new Map();
282
- (fn.params ?? []).forEach((p, i) => {
283
- const arg = call.arguments?.[i];
284
- if (arg) bindings.set(p.name, arg);
285
- });
387
+ if (!fn) return null;
388
+ const params = supportedParams(fn);
389
+ if (!params) return null;
390
+ const bindings = resolveHelperBindings(call, params);
391
+ if (!bindings) return null;
286
392
  const prov = {
287
393
  kind: "helper",
288
394
  fn: call.callee.name,