@hyperframes/lint 0.8.184 → 0.8.186

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/dist/browser.js CHANGED
@@ -4,6 +4,7 @@ import { Parser as Parser2 } from "htmlparser2";
4
4
  // src/utils.ts
5
5
  import { Parser } from "htmlparser2";
6
6
  import { parse } from "acorn";
7
+ import { base, recursive, simple } from "acorn-walk";
7
8
  var COMPOSITION_ID_IN_CSS_PATTERN = /\[data-composition-id=["']([^"']+)["']\]/g;
8
9
  var TIMELINE_REGISTRY_INIT_PATTERN = /window\.__timelines\s*=\s*window\.__timelines\s*\|\|\s*\{\}|window\.__timelines\s*=\s*\{\}|window\.__timelines\s*\?\?=\s*\{\}/i;
9
10
  var TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN = /window\.__timelines\s*=\s*\{\s*(?:["'][^"']+["']|[A-Za-z_$][\w$]*)\s*:/i;
@@ -366,6 +367,74 @@ function scanJsComments(source) {
366
367
  function stripJsComments(source) {
367
368
  return scanJsComments(source).out;
368
369
  }
370
+ function isGsapLibraryComment(comment) {
371
+ if (comment.type !== "Block") return false;
372
+ const { value } = comment;
373
+ const src = /^\s*inlined:\s*(\S+)\s*$/.exec(value)?.[1]?.split(/[?#]/)[0];
374
+ return value.startsWith("!") && /\bGreenSock\b/.test(value) || src !== void 0 && /(?:^|\/)gsap(?:@[^/]+)?\/dist\/[^/]+\.js$/.test(src);
375
+ }
376
+ function isUmdWrapperCall(call) {
377
+ const [scope, factory] = call.arguments;
378
+ if (call.callee.type !== "FunctionExpression" || call.arguments.length !== 2 || scope?.type !== "ThisExpression" || factory?.type !== "FunctionExpression")
379
+ return false;
380
+ let checksAmd = false;
381
+ recursive(call.callee.body, null, {
382
+ Function() {
383
+ },
384
+ MemberExpression(member, state, visit) {
385
+ if (!member.computed && member.object.type === "Identifier" && member.object.name === "define" && member.property.type === "Identifier" && member.property.name === "amd")
386
+ checksAmd = true;
387
+ base.MemberExpression?.(member, state, visit);
388
+ }
389
+ });
390
+ return checksAmd;
391
+ }
392
+ function bannerOwner(banner, source, commentAt, wrappers) {
393
+ let next = banner.end;
394
+ for (; ; ) {
395
+ while (/[\s!;(]/.test(source[next] ?? "")) next++;
396
+ const comment = commentAt.get(next);
397
+ if (!comment) break;
398
+ next = comment.end;
399
+ }
400
+ return wrappers.find((call) => call.start === next);
401
+ }
402
+ function findInlinedGsapLibrarySpans(source) {
403
+ if (!/GreenSock|inlined:/.test(source)) return [];
404
+ const comments = [];
405
+ let program;
406
+ try {
407
+ program = parse(source, {
408
+ ecmaVersion: "latest",
409
+ sourceType: "script",
410
+ allowReturnOutsideFunction: true,
411
+ onComment: comments
412
+ });
413
+ } catch {
414
+ return [];
415
+ }
416
+ const banners = comments.filter(isGsapLibraryComment);
417
+ const wrappers = [];
418
+ simple(program, {
419
+ CallExpression(call) {
420
+ if (isUmdWrapperCall(call)) wrappers.push(call);
421
+ }
422
+ });
423
+ const commentAt = new Map(comments.map((comment) => [comment.start, comment]));
424
+ const owners = /* @__PURE__ */ new Set();
425
+ for (const banner of banners) {
426
+ const owner = bannerOwner(banner, source, commentAt, wrappers);
427
+ if (owner) owners.add(owner);
428
+ }
429
+ return [...owners].map((call) => [call.start, call.end]);
430
+ }
431
+ function blankInlinedGsapLibrary(source) {
432
+ let out = source;
433
+ for (const [start, end] of findInlinedGsapLibrarySpans(source)) {
434
+ out = out.slice(0, start) + " ".repeat(end - start) + out.slice(end);
435
+ }
436
+ return out;
437
+ }
369
438
  function stripJsCode(source) {
370
439
  const { out, balanced } = scanJsComments(source);
371
440
  return balanced ? stripJsStringLiterals(out) : source;
@@ -1497,7 +1566,7 @@ var coreRules = [
1497
1566
  }
1498
1567
  ];
1499
1568
  for (const script of scripts) {
1500
- const withoutComments2 = stripJsComments(script.content);
1569
+ const withoutComments2 = stripJsComments(blankInlinedGsapLibrary(script.content));
1501
1570
  const executable = stripStringLiterals(withoutComments2);
1502
1571
  for (const { pattern, label, hint, scansStrings } of patterns) {
1503
1572
  const match = pattern.exec(scansStrings ? withoutComments2 : executable);
@@ -1699,10 +1768,10 @@ function srcKind(src) {
1699
1768
  } catch {
1700
1769
  pathname = stripped.split("?")[0]?.split("#")[0] ?? stripped;
1701
1770
  }
1702
- const base = pathname.split("/").pop() ?? "";
1703
- const dot = base.lastIndexOf(".");
1771
+ const base2 = pathname.split("/").pop() ?? "";
1772
+ const dot = base2.lastIndexOf(".");
1704
1773
  if (dot < 0) return null;
1705
- const ext = base.slice(dot + 1).toLowerCase();
1774
+ const ext = base2.slice(dot + 1).toLowerCase();
1706
1775
  if (IMAGE_SRC_EXT.has(ext)) return "image";
1707
1776
  if (VIDEO_SRC_EXT.has(ext)) return "video";
1708
1777
  if (AUDIO_SRC_EXT.has(ext)) return "audio";
@@ -2497,7 +2566,7 @@ function findAudioGroupCarveAttrFindings(ctx) {
2497
2566
 
2498
2567
  // src/scriptPositions.ts
2499
2568
  import { parse as parse2 } from "acorn";
2500
- import { simple } from "acorn-walk";
2569
+ import { simple as simple2 } from "acorn-walk";
2501
2570
  var callIndexes = /* @__PURE__ */ new WeakMap();
2502
2571
  function callsFor(script) {
2503
2572
  const cached = callIndexes.get(script);
@@ -2509,7 +2578,7 @@ function callsFor(script) {
2509
2578
  sourceType: "script",
2510
2579
  allowReturnOutsideFunction: true
2511
2580
  });
2512
- simple(ast, {
2581
+ simple2(ast, {
2513
2582
  CallExpression: (node) => {
2514
2583
  calls.push(node);
2515
2584
  }
@@ -4048,8 +4117,8 @@ function targetedSelectorTokens(selector) {
4048
4117
  const compounds = group.trim().split(/[\s>+~]+/).filter(Boolean);
4049
4118
  const last = compounds[compounds.length - 1];
4050
4119
  if (!last) continue;
4051
- const simple3 = last.match(/[#.][A-Za-z0-9_-]+/g);
4052
- if (simple3) for (const token of simple3) tokens.add(token);
4120
+ const simple4 = last.match(/[#.][A-Za-z0-9_-]+/g);
4121
+ if (simple4) for (const token of simple4) tokens.add(token);
4053
4122
  }
4054
4123
  return tokens;
4055
4124
  }
@@ -6378,7 +6447,7 @@ var structureRules = [
6378
6447
 
6379
6448
  // src/shaderDomains.ts
6380
6449
  import { parse as parse3, parseExpressionAt } from "acorn";
6381
- import { simple as simple2 } from "acorn-walk";
6450
+ import { simple as simple3 } from "acorn-walk";
6382
6451
  function withoutComments(source) {
6383
6452
  return source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\r\n]*/g, (text) => text.replace(/[^\r\n]/g, " "));
6384
6453
  }
@@ -6390,7 +6459,7 @@ function staticShaders(source) {
6390
6459
  sourceType: "module",
6391
6460
  allowReturnOutsideFunction: true
6392
6461
  });
6393
- simple2(ast, {
6462
+ simple3(ast, {
6394
6463
  Literal(node) {
6395
6464
  if (typeof node.value !== "string") return;
6396
6465
  shaders.push({
@@ -6437,8 +6506,8 @@ function zeroFlooredDot(a, b) {
6437
6506
  }
6438
6507
  function unsafeCosinePower(call) {
6439
6508
  if (call.arguments.length !== 2) return false;
6440
- const [base] = call.arguments;
6441
- return base?.type === "BinaryExpression" && base.operator === "-" && base.left.type !== "PrivateIdentifier" && isNumber(base.left, 1) && unboundedCosine(base.right);
6509
+ const [base2] = call.arguments;
6510
+ return base2?.type === "BinaryExpression" && base2.operator === "-" && base2.left.type !== "PrivateIdentifier" && isNumber(base2.left, 1) && unboundedCosine(base2.right);
6442
6511
  }
6443
6512
  function unsafePowOffsets(source) {
6444
6513
  const offsets = [];
@@ -6446,7 +6515,7 @@ function unsafePowOffsets(source) {
6446
6515
  for (const match of masked.matchAll(/\bpow\s*\(/g)) {
6447
6516
  try {
6448
6517
  const expression = parseExpressionAt(masked, match.index, { ecmaVersion: "latest" });
6449
- simple2(expression, {
6518
+ simple3(expression, {
6450
6519
  CallExpression(node) {
6451
6520
  if (node.start === match.index && unsafeCosinePower(node)) offsets.push(node.start);
6452
6521
  }
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { Parser as Parser2 } from "htmlparser2";
4
4
  // src/utils.ts
5
5
  import { Parser } from "htmlparser2";
6
6
  import { parse } from "acorn";
7
+ import { base, recursive, simple } from "acorn-walk";
7
8
  var COMPOSITION_ID_IN_CSS_PATTERN = /\[data-composition-id=["']([^"']+)["']\]/g;
8
9
  var TIMELINE_REGISTRY_INIT_PATTERN = /window\.__timelines\s*=\s*window\.__timelines\s*\|\|\s*\{\}|window\.__timelines\s*=\s*\{\}|window\.__timelines\s*\?\?=\s*\{\}/i;
9
10
  var TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN = /window\.__timelines\s*=\s*\{\s*(?:["'][^"']+["']|[A-Za-z_$][\w$]*)\s*:/i;
@@ -366,6 +367,74 @@ function scanJsComments(source) {
366
367
  function stripJsComments(source) {
367
368
  return scanJsComments(source).out;
368
369
  }
370
+ function isGsapLibraryComment(comment) {
371
+ if (comment.type !== "Block") return false;
372
+ const { value } = comment;
373
+ const src = /^\s*inlined:\s*(\S+)\s*$/.exec(value)?.[1]?.split(/[?#]/)[0];
374
+ return value.startsWith("!") && /\bGreenSock\b/.test(value) || src !== void 0 && /(?:^|\/)gsap(?:@[^/]+)?\/dist\/[^/]+\.js$/.test(src);
375
+ }
376
+ function isUmdWrapperCall(call) {
377
+ const [scope, factory] = call.arguments;
378
+ if (call.callee.type !== "FunctionExpression" || call.arguments.length !== 2 || scope?.type !== "ThisExpression" || factory?.type !== "FunctionExpression")
379
+ return false;
380
+ let checksAmd = false;
381
+ recursive(call.callee.body, null, {
382
+ Function() {
383
+ },
384
+ MemberExpression(member, state, visit) {
385
+ if (!member.computed && member.object.type === "Identifier" && member.object.name === "define" && member.property.type === "Identifier" && member.property.name === "amd")
386
+ checksAmd = true;
387
+ base.MemberExpression?.(member, state, visit);
388
+ }
389
+ });
390
+ return checksAmd;
391
+ }
392
+ function bannerOwner(banner, source, commentAt, wrappers) {
393
+ let next = banner.end;
394
+ for (; ; ) {
395
+ while (/[\s!;(]/.test(source[next] ?? "")) next++;
396
+ const comment = commentAt.get(next);
397
+ if (!comment) break;
398
+ next = comment.end;
399
+ }
400
+ return wrappers.find((call) => call.start === next);
401
+ }
402
+ function findInlinedGsapLibrarySpans(source) {
403
+ if (!/GreenSock|inlined:/.test(source)) return [];
404
+ const comments = [];
405
+ let program;
406
+ try {
407
+ program = parse(source, {
408
+ ecmaVersion: "latest",
409
+ sourceType: "script",
410
+ allowReturnOutsideFunction: true,
411
+ onComment: comments
412
+ });
413
+ } catch {
414
+ return [];
415
+ }
416
+ const banners = comments.filter(isGsapLibraryComment);
417
+ const wrappers = [];
418
+ simple(program, {
419
+ CallExpression(call) {
420
+ if (isUmdWrapperCall(call)) wrappers.push(call);
421
+ }
422
+ });
423
+ const commentAt = new Map(comments.map((comment) => [comment.start, comment]));
424
+ const owners = /* @__PURE__ */ new Set();
425
+ for (const banner of banners) {
426
+ const owner = bannerOwner(banner, source, commentAt, wrappers);
427
+ if (owner) owners.add(owner);
428
+ }
429
+ return [...owners].map((call) => [call.start, call.end]);
430
+ }
431
+ function blankInlinedGsapLibrary(source) {
432
+ let out = source;
433
+ for (const [start, end] of findInlinedGsapLibrarySpans(source)) {
434
+ out = out.slice(0, start) + " ".repeat(end - start) + out.slice(end);
435
+ }
436
+ return out;
437
+ }
369
438
  function stripJsCode(source) {
370
439
  const { out, balanced } = scanJsComments(source);
371
440
  return balanced ? stripJsStringLiterals(out) : source;
@@ -1503,7 +1572,7 @@ var coreRules = [
1503
1572
  }
1504
1573
  ];
1505
1574
  for (const script of scripts) {
1506
- const withoutComments2 = stripJsComments(script.content);
1575
+ const withoutComments2 = stripJsComments(blankInlinedGsapLibrary(script.content));
1507
1576
  const executable = stripStringLiterals(withoutComments2);
1508
1577
  for (const { pattern, label, hint, scansStrings } of patterns) {
1509
1578
  const match = pattern.exec(scansStrings ? withoutComments2 : executable);
@@ -1705,10 +1774,10 @@ function srcKind(src) {
1705
1774
  } catch {
1706
1775
  pathname = stripped.split("?")[0]?.split("#")[0] ?? stripped;
1707
1776
  }
1708
- const base = pathname.split("/").pop() ?? "";
1709
- const dot = base.lastIndexOf(".");
1777
+ const base2 = pathname.split("/").pop() ?? "";
1778
+ const dot = base2.lastIndexOf(".");
1710
1779
  if (dot < 0) return null;
1711
- const ext = base.slice(dot + 1).toLowerCase();
1780
+ const ext = base2.slice(dot + 1).toLowerCase();
1712
1781
  if (IMAGE_SRC_EXT.has(ext)) return "image";
1713
1782
  if (VIDEO_SRC_EXT.has(ext)) return "video";
1714
1783
  if (AUDIO_SRC_EXT.has(ext)) return "audio";
@@ -2503,7 +2572,7 @@ function findAudioGroupCarveAttrFindings(ctx) {
2503
2572
 
2504
2573
  // src/scriptPositions.ts
2505
2574
  import { parse as parse2 } from "acorn";
2506
- import { simple } from "acorn-walk";
2575
+ import { simple as simple2 } from "acorn-walk";
2507
2576
  var callIndexes = /* @__PURE__ */ new WeakMap();
2508
2577
  function callsFor(script) {
2509
2578
  const cached = callIndexes.get(script);
@@ -2515,7 +2584,7 @@ function callsFor(script) {
2515
2584
  sourceType: "script",
2516
2585
  allowReturnOutsideFunction: true
2517
2586
  });
2518
- simple(ast, {
2587
+ simple2(ast, {
2519
2588
  CallExpression: (node) => {
2520
2589
  calls.push(node);
2521
2590
  }
@@ -4054,8 +4123,8 @@ function targetedSelectorTokens(selector) {
4054
4123
  const compounds = group.trim().split(/[\s>+~]+/).filter(Boolean);
4055
4124
  const last = compounds[compounds.length - 1];
4056
4125
  if (!last) continue;
4057
- const simple3 = last.match(/[#.][A-Za-z0-9_-]+/g);
4058
- if (simple3) for (const token of simple3) tokens.add(token);
4126
+ const simple4 = last.match(/[#.][A-Za-z0-9_-]+/g);
4127
+ if (simple4) for (const token of simple4) tokens.add(token);
4059
4128
  }
4060
4129
  return tokens;
4061
4130
  }
@@ -6384,7 +6453,7 @@ var structureRules = [
6384
6453
 
6385
6454
  // src/shaderDomains.ts
6386
6455
  import { parse as parse3, parseExpressionAt } from "acorn";
6387
- import { simple as simple2 } from "acorn-walk";
6456
+ import { simple as simple3 } from "acorn-walk";
6388
6457
  function withoutComments(source) {
6389
6458
  return source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\r\n]*/g, (text) => text.replace(/[^\r\n]/g, " "));
6390
6459
  }
@@ -6396,7 +6465,7 @@ function staticShaders(source) {
6396
6465
  sourceType: "module",
6397
6466
  allowReturnOutsideFunction: true
6398
6467
  });
6399
- simple2(ast, {
6468
+ simple3(ast, {
6400
6469
  Literal(node) {
6401
6470
  if (typeof node.value !== "string") return;
6402
6471
  shaders.push({
@@ -6443,8 +6512,8 @@ function zeroFlooredDot(a, b) {
6443
6512
  }
6444
6513
  function unsafeCosinePower(call) {
6445
6514
  if (call.arguments.length !== 2) return false;
6446
- const [base] = call.arguments;
6447
- return base?.type === "BinaryExpression" && base.operator === "-" && base.left.type !== "PrivateIdentifier" && isNumber(base.left, 1) && unboundedCosine(base.right);
6515
+ const [base2] = call.arguments;
6516
+ return base2?.type === "BinaryExpression" && base2.operator === "-" && base2.left.type !== "PrivateIdentifier" && isNumber(base2.left, 1) && unboundedCosine(base2.right);
6448
6517
  }
6449
6518
  function unsafePowOffsets(source) {
6450
6519
  const offsets = [];
@@ -6452,7 +6521,7 @@ function unsafePowOffsets(source) {
6452
6521
  for (const match of masked.matchAll(/\bpow\s*\(/g)) {
6453
6522
  try {
6454
6523
  const expression = parseExpressionAt(masked, match.index, { ecmaVersion: "latest" });
6455
- simple2(expression, {
6524
+ simple3(expression, {
6456
6525
  CallExpression(node) {
6457
6526
  if (node.start === match.index && unsafeCosinePower(node)) offsets.push(node.start);
6458
6527
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/lint",
3
- "version": "0.8.184",
3
+ "version": "0.8.186",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -35,7 +35,7 @@
35
35
  "linkedom": "^0.18.12",
36
36
  "postcss": "^8.5.8",
37
37
  "postcss-selector-parser": "^7.1.4",
38
- "@hyperframes/parsers": "0.8.184"
38
+ "@hyperframes/parsers": "0.8.186"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^25.0.10",