@remotion/studio-server 4.0.512 → 4.0.514

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 (68) hide show
  1. package/dist/codemods/delete-jsx-node.d.ts +2 -5
  2. package/dist/codemods/delete-jsx-node.js +23 -341
  3. package/dist/codemods/duplicate-composition.d.ts +1 -9
  4. package/dist/codemods/duplicate-composition.js +3 -49
  5. package/dist/codemods/format-inline-content.d.ts +2 -5
  6. package/dist/codemods/format-inline-content.js +20 -50
  7. package/dist/codemods/parse-ast.d.ts +1 -0
  8. package/dist/codemods/parse-ast.js +5 -1
  9. package/dist/codemods/recast-mods.js +0 -18
  10. package/dist/codemods/reorder-sequence.d.ts +2 -2
  11. package/dist/codemods/reorder-sequence.js +12 -112
  12. package/dist/codemods/split-jsx-sequence.d.ts +1 -2
  13. package/dist/codemods/split-jsx-sequence.js +11 -298
  14. package/dist/codemods/split-video-from-audio.d.ts +15 -0
  15. package/dist/codemods/split-video-from-audio.js +15 -0
  16. package/dist/codemods/update-default-props.d.ts +2 -6
  17. package/dist/codemods/update-default-props.js +12 -220
  18. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +1 -4
  19. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +5 -102
  20. package/dist/codemods/update-keyframes/update-keyframes.d.ts +8 -93
  21. package/dist/codemods/update-keyframes/update-keyframes.js +11 -1302
  22. package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +4 -1
  23. package/dist/codemods/update-sequence-props/update-sequence-props.js +47 -3
  24. package/dist/detect-outdated-remotion-skills.d.ts +7 -0
  25. package/dist/detect-outdated-remotion-skills.js +11 -5
  26. package/dist/helpers/resolve-composition-component.d.ts +3 -11
  27. package/dist/helpers/resolve-composition-component.js +38 -1495
  28. package/dist/index.d.ts +3 -2
  29. package/dist/index.js +1 -0
  30. package/dist/max-timeline-tracks.d.ts +2 -1
  31. package/dist/max-timeline-tracks.js +10 -4
  32. package/dist/preview-server/api-routes.js +4 -0
  33. package/dist/preview-server/routes/add-effect.js +1 -1
  34. package/dist/preview-server/routes/apply-codemod.js +3 -3
  35. package/dist/preview-server/routes/apply-visual-control-change.js +3 -3
  36. package/dist/preview-server/routes/can-update-effect-props.js +3 -0
  37. package/dist/preview-server/routes/can-update-sequence-props.d.ts +26 -0
  38. package/dist/preview-server/routes/can-update-sequence-props.js +437 -61
  39. package/dist/preview-server/routes/default-editor.js +4 -1
  40. package/dist/preview-server/routes/delete-effect.js +1 -1
  41. package/dist/preview-server/routes/delete-jsx-node.js +1 -1
  42. package/dist/preview-server/routes/duplicate-effect.js +1 -1
  43. package/dist/preview-server/routes/duplicate-jsx-node.js +1 -1
  44. package/dist/preview-server/routes/element-install-plan.d.ts +1 -1
  45. package/dist/preview-server/routes/insert-element.js +2 -2
  46. package/dist/preview-server/routes/insert-jsx-element.js +1 -1
  47. package/dist/preview-server/routes/log-updates/log-effect-update.js +2 -1
  48. package/dist/preview-server/routes/log-updates/log-update.js +2 -1
  49. package/dist/preview-server/routes/paste-effects.js +1 -1
  50. package/dist/preview-server/routes/remotion-skills-info.d.ts +7 -0
  51. package/dist/preview-server/routes/remotion-skills-info.js +24 -0
  52. package/dist/preview-server/routes/reorder-effect.js +1 -1
  53. package/dist/preview-server/routes/reorder-sequence.js +1 -1
  54. package/dist/preview-server/routes/save-sequence-props.js +27 -4
  55. package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -0
  56. package/dist/preview-server/routes/source-file-write-queue.js +11 -2
  57. package/dist/preview-server/routes/split-jsx-sequence.js +1 -1
  58. package/dist/preview-server/routes/split-video-from-audio.d.ts +3 -0
  59. package/dist/preview-server/routes/split-video-from-audio.js +80 -0
  60. package/dist/preview-server/routes/subscribe-to-sequence-props.d.ts +2 -2
  61. package/dist/preview-server/routes/subscribe-to-sequence-props.js +37 -3
  62. package/dist/preview-server/routes/update-default-props.js +1 -1
  63. package/dist/preview-server/sequence-props-watchers.d.ts +2 -1
  64. package/dist/preview-server/sequence-props-watchers.js +33 -2
  65. package/dist/preview-server/start-server.js +188 -140
  66. package/dist/preview-server/undo-stack.d.ts +3 -52
  67. package/dist/preview-server/update-available.js +4 -4
  68. package/package.json +8 -8
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.computeSequencePropsStatusFromFilenameByLocation = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.lineColumnToNodePath = exports.findNodePathForJsxElement = exports.getStaticJsxTextContent = exports.hasJsxChildrenAttribute = exports.getStaticJsxChildrenAttribute = exports.findJsxElementNodeAtNodePath = exports.findJsxElementAtNodePath = exports.findJsxElementPathAtNodePath = exports.getNodePathForRecastPath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = void 0;
36
+ exports.computeSequencePropsStatusFromFilenameByLocation = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsStatusFromAst = exports.resolveSequencePropsNodePathsFromFilename = exports.lineColumnsToNodePaths = exports.lineColumnToNodePath = exports.findNodePathForJsxElement = exports.getStaticJsxTextContent = exports.hasJsxChildrenAttribute = exports.getStaticJsxChildrenAttribute = exports.findJsxElementNodeAtNodePath = exports.findJsxElementAtNodePath = exports.findJsxElementPathAtNodePath = exports.getNodePathForRecastPath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = exports.takeCachedSequencePropsStatusAst = void 0;
37
37
  const node_fs_1 = require("node:fs");
38
38
  const renderer_1 = require("@remotion/renderer");
39
39
  const studio_shared_1 = require("@remotion/studio-shared");
@@ -55,8 +55,41 @@ const can_update_effect_props_1 = require("./can-update-effect-props");
55
55
  // computation is read-only, so all subscribers can share one parsed snapshot
56
56
  // until the notification burst has finished.
57
57
  let cachedSequencePropsStatusAst = null;
58
+ // A subsequent save can consume the last read-only snapshot if the file has
59
+ // not changed. The save mutates the AST, so it must only be reused once.
60
+ let reusableSequencePropsStatusAst = null;
61
+ const getCachedSequencePropsStatusAst = (fileContents) => {
62
+ if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.fileContents) !== fileContents) {
63
+ const snapshot = {
64
+ fileContents,
65
+ ast: (0, parse_ast_1.parseAst)(fileContents),
66
+ videoConfigIdentifierValues: new Map(),
67
+ };
68
+ cachedSequencePropsStatusAst = snapshot;
69
+ reusableSequencePropsStatusAst = snapshot;
70
+ queueMicrotask(() => {
71
+ if (cachedSequencePropsStatusAst === snapshot) {
72
+ cachedSequencePropsStatusAst = null;
73
+ }
74
+ });
75
+ }
76
+ return cachedSequencePropsStatusAst;
77
+ };
78
+ const takeCachedSequencePropsStatusAst = (fileContents) => {
79
+ if ((reusableSequencePropsStatusAst === null || reusableSequencePropsStatusAst === void 0 ? void 0 : reusableSequencePropsStatusAst.fileContents) !== fileContents) {
80
+ return null;
81
+ }
82
+ const { ast } = reusableSequencePropsStatusAst;
83
+ reusableSequencePropsStatusAst = null;
84
+ if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.ast) === ast) {
85
+ cachedSequencePropsStatusAst = null;
86
+ }
87
+ return ast;
88
+ };
89
+ exports.takeCachedSequencePropsStatusAst = takeCachedSequencePropsStatusAst;
58
90
  const staticStatus = (codeValue, numericExpression) => ({
59
91
  status: 'static',
92
+ keyframeDisplayOffsetAdjustment: null,
60
93
  codeValue,
61
94
  ...(numericExpression === null || numericExpression.type === 'literal'
62
95
  ? {}
@@ -389,13 +422,20 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
389
422
  const outputArg = callExpression.arguments[2];
390
423
  if (!frameArg ||
391
424
  frameArg.type === 'SpreadElement' ||
392
- !isCurrentFrameIdentifier(frameArg, ast) ||
393
425
  !inputArg ||
394
426
  !outputArg ||
395
427
  inputArg.type !== 'ArrayExpression' ||
396
428
  outputArg.type !== 'ArrayExpression') {
397
429
  return undefined;
398
430
  }
431
+ const frameDisplayOffset = getCurrentFrameDisplayOffsetAdjustment({
432
+ node: frameArg,
433
+ ast,
434
+ videoConfigValues,
435
+ });
436
+ if (frameDisplayOffset === null) {
437
+ return undefined;
438
+ }
399
439
  if (inputArg.elements.length !== outputArg.elements.length) {
400
440
  return undefined;
401
441
  }
@@ -436,39 +476,283 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
436
476
  clamping: metadata.clamping,
437
477
  posterize: metadata.posterize,
438
478
  output: metadata.output,
479
+ keyframeDisplayOffsetAdjustment: frameDisplayOffset.hasEnclosingElement
480
+ ? frameDisplayOffset.adjustment
481
+ : null,
439
482
  };
440
483
  };
441
- const isUseCurrentFrameCall = (node) => {
442
- return (node.type === 'CallExpression' &&
443
- node.callee.type === 'Identifier' &&
444
- node.callee.name === 'useCurrentFrame' &&
445
- node.arguments.length === 0);
484
+ const getRemotionImportNames = ({ ast, importedName, }) => {
485
+ var _a;
486
+ var _b, _c;
487
+ const direct = new Set();
488
+ const namespaces = new Set();
489
+ for (const statement of ast.program.body) {
490
+ if (statement.type !== 'ImportDeclaration' ||
491
+ statement.source.value !== 'remotion') {
492
+ continue;
493
+ }
494
+ for (const specifier of (_b = statement.specifiers) !== null && _b !== void 0 ? _b : []) {
495
+ if (specifier.type === 'ImportSpecifier' &&
496
+ ((specifier.imported.type === 'Identifier' &&
497
+ specifier.imported.name === importedName) ||
498
+ (specifier.imported.type === 'StringLiteral' &&
499
+ specifier.imported.value === importedName))) {
500
+ direct.add((_c = (_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _c !== void 0 ? _c : importedName);
501
+ }
502
+ if (specifier.type === 'ImportNamespaceSpecifier') {
503
+ namespaces.add(specifier.local.name);
504
+ }
505
+ }
506
+ }
507
+ return { direct, namespaces };
508
+ };
509
+ const isUseCurrentFrameCall = (node, ast) => {
510
+ if (node.type !== 'CallExpression' || node.arguments.length !== 0) {
511
+ return false;
512
+ }
513
+ const imports = getRemotionImportNames({
514
+ ast,
515
+ importedName: 'useCurrentFrame',
516
+ });
517
+ if (node.callee.type === 'Identifier') {
518
+ return imports.direct.has(node.callee.name);
519
+ }
520
+ return (node.callee.type === 'MemberExpression' &&
521
+ !node.callee.computed &&
522
+ node.callee.object.type === 'Identifier' &&
523
+ node.callee.property.type === 'Identifier' &&
524
+ imports.namespaces.has(node.callee.object.name) &&
525
+ node.callee.property.name === 'useCurrentFrame');
526
+ };
527
+ const findNodePath = (ast, target) => {
528
+ let found = null;
529
+ recast.types.visit(ast, {
530
+ visitNode(p) {
531
+ if (p.node === target) {
532
+ found = p;
533
+ return false;
534
+ }
535
+ return this.traverse(p);
536
+ },
537
+ });
538
+ return found;
539
+ };
540
+ const getJsxNumericAttribute = ({ openingElement, name, defaultValue, videoConfigValues, }) => {
541
+ var _a, _b;
542
+ var _c;
543
+ if (openingElement.attributes.some((attribute) => attribute.type === 'JSXSpreadAttribute')) {
544
+ return null;
545
+ }
546
+ for (let index = openingElement.attributes.length - 1; index >= 0; index--) {
547
+ const attribute = openingElement.attributes[index];
548
+ if (attribute.type !== 'JSXAttribute' ||
549
+ attribute.name.type !== 'JSXIdentifier' ||
550
+ attribute.name.name !== name) {
551
+ continue;
552
+ }
553
+ if (((_a = attribute.value) === null || _a === void 0 ? void 0 : _a.type) !== 'JSXExpressionContainer' ||
554
+ attribute.value.expression.type === 'JSXEmptyExpression') {
555
+ return null;
556
+ }
557
+ return ((_c = (_b = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
558
+ node: attribute.value.expression,
559
+ videoConfigValues,
560
+ })) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : null);
561
+ }
562
+ return defaultValue;
563
+ };
564
+ const getFrameDisplayOffsetAdjustmentBetweenPaths = ({ startPath, endPath, videoConfigValues, }) => {
565
+ let current = startPath;
566
+ let hasSeenControlledElement = false;
567
+ let hasEnclosingElement = false;
568
+ let adjustment = 0;
569
+ while (current && current.value !== endPath.value) {
570
+ const currentNode = current.value;
571
+ if (currentNode.type === 'FunctionDeclaration' ||
572
+ currentNode.type === 'FunctionExpression' ||
573
+ currentNode.type === 'ArrowFunctionExpression') {
574
+ return null;
575
+ }
576
+ if (currentNode.type === 'JSXElement') {
577
+ if (!hasSeenControlledElement) {
578
+ hasSeenControlledElement = true;
579
+ }
580
+ else {
581
+ hasEnclosingElement = true;
582
+ // Sequence-backed built-ins and userland components can both shift
583
+ // their children, so the prop names are the semantic boundary.
584
+ const from = getJsxNumericAttribute({
585
+ openingElement: currentNode.openingElement,
586
+ name: 'from',
587
+ defaultValue: 0,
588
+ videoConfigValues,
589
+ });
590
+ const trimBefore = getJsxNumericAttribute({
591
+ openingElement: currentNode.openingElement,
592
+ name: 'trimBefore',
593
+ defaultValue: 0,
594
+ videoConfigValues,
595
+ });
596
+ if (from === null || trimBefore === null) {
597
+ return null;
598
+ }
599
+ adjustment -= from - trimBefore;
600
+ }
601
+ }
602
+ current = current.parentPath;
603
+ }
604
+ return current ? { adjustment, hasEnclosingElement } : null;
446
605
  };
447
- const isCurrentFrameIdentifier = (node, ast) => {
606
+ const getDefaultFrameDisplayOffsetAdjustment = ({ jsxPath, videoConfigValues, }) => {
607
+ var _a;
608
+ let functionPath = jsxPath.parentPath;
609
+ while (functionPath) {
610
+ const node = functionPath.value;
611
+ if (node.type === 'FunctionDeclaration' ||
612
+ node.type === 'FunctionExpression' ||
613
+ node.type === 'ArrowFunctionExpression') {
614
+ break;
615
+ }
616
+ functionPath = functionPath.parentPath;
617
+ }
618
+ if (!functionPath) {
619
+ return null;
620
+ }
621
+ const result = getFrameDisplayOffsetAdjustmentBetweenPaths({
622
+ startPath: jsxPath,
623
+ endPath: functionPath,
624
+ videoConfigValues,
625
+ });
626
+ return (_a = result === null || result === void 0 ? void 0 : result.adjustment) !== null && _a !== void 0 ? _a : null;
627
+ };
628
+ const resolveCurrentFrameExpression = ({ node, ast, seenDeclarations, }) => {
629
+ var _a;
448
630
  if (node.type === 'TSAsExpression') {
449
- return isCurrentFrameIdentifier(node.expression, ast);
631
+ return resolveCurrentFrameExpression({
632
+ node: node.expression,
633
+ ast,
634
+ seenDeclarations,
635
+ });
636
+ }
637
+ if (node.type === 'BinaryExpression' &&
638
+ (node.operator === '+' || node.operator === '-')) {
639
+ const rightValue = getNumericValue(node.right);
640
+ if (rightValue !== null && Number.isFinite(rightValue)) {
641
+ const resolvedLeft = resolveCurrentFrameExpression({
642
+ node: node.left,
643
+ ast,
644
+ seenDeclarations,
645
+ });
646
+ if (resolvedLeft !== null) {
647
+ return {
648
+ ...resolvedLeft,
649
+ offset: resolvedLeft.offset +
650
+ (node.operator === '+' ? rightValue : -rightValue),
651
+ };
652
+ }
653
+ }
654
+ if (node.operator === '+') {
655
+ const leftValue = getNumericValue(node.left);
656
+ if (leftValue !== null && Number.isFinite(leftValue)) {
657
+ const resolvedRight = resolveCurrentFrameExpression({
658
+ node: node.right,
659
+ ast,
660
+ seenDeclarations,
661
+ });
662
+ if (resolvedRight !== null) {
663
+ return {
664
+ ...resolvedRight,
665
+ offset: resolvedRight.offset + leftValue,
666
+ };
667
+ }
668
+ }
669
+ }
670
+ return null;
450
671
  }
451
672
  if (node.type !== 'Identifier') {
452
- return false;
673
+ return null;
453
674
  }
454
- let hasUseCurrentFrameDeclaration = false;
455
- let hasOtherDeclaration = false;
456
- recast.types.visit(ast, {
675
+ const nodePath = findNodePath(ast, node);
676
+ const bindingScope = (_a = nodePath === null || nodePath === void 0 ? void 0 : nodePath.scope) === null || _a === void 0 ? void 0 : _a.lookup(node.name);
677
+ if (!nodePath || !bindingScope) {
678
+ return null;
679
+ }
680
+ let matchingDeclarations = 0;
681
+ let matchingDeclaration = null;
682
+ let initializer = null;
683
+ let isConstDeclaration = false;
684
+ recast.types.visit(bindingScope.path, {
457
685
  visitVariableDeclarator(p) {
686
+ var _a;
458
687
  const { id, init } = p.node;
459
- if (id.type !== 'Identifier' || id.name !== node.name) {
688
+ if (id.type !== 'Identifier' ||
689
+ id.name !== node.name ||
690
+ ((_a = p.scope.lookup(node.name)) === null || _a === void 0 ? void 0 : _a.path.node) !== bindingScope.path.node) {
460
691
  return this.traverse(p);
461
692
  }
462
- if (init && isUseCurrentFrameCall(init)) {
463
- hasUseCurrentFrameDeclaration = true;
464
- }
465
- else {
466
- hasOtherDeclaration = true;
693
+ matchingDeclarations++;
694
+ const declaration = p.parentPath.node;
695
+ if (init) {
696
+ matchingDeclaration = p.node;
697
+ initializer = init;
698
+ isConstDeclaration =
699
+ declaration.type === 'VariableDeclaration' &&
700
+ declaration.kind === 'const';
467
701
  }
468
702
  return false;
469
703
  },
470
704
  });
471
- return hasUseCurrentFrameDeclaration && !hasOtherDeclaration;
705
+ if (matchingDeclarations !== 1 ||
706
+ matchingDeclaration === null ||
707
+ initializer === null ||
708
+ seenDeclarations.has(matchingDeclaration)) {
709
+ return null;
710
+ }
711
+ if (isUseCurrentFrameCall(initializer, ast)) {
712
+ return { bindingScopePath: bindingScope.path, offset: 0 };
713
+ }
714
+ if (!isConstDeclaration) {
715
+ return null;
716
+ }
717
+ const nextSeenDeclarations = new Set(seenDeclarations);
718
+ nextSeenDeclarations.add(matchingDeclaration);
719
+ return resolveCurrentFrameExpression({
720
+ node: initializer,
721
+ ast,
722
+ seenDeclarations: nextSeenDeclarations,
723
+ });
724
+ };
725
+ const getCurrentFrameDisplayOffsetAdjustment = ({ node, ast, videoConfigValues, }) => {
726
+ if (node.type === 'TSAsExpression') {
727
+ return getCurrentFrameDisplayOffsetAdjustment({
728
+ node: node.expression,
729
+ ast,
730
+ videoConfigValues,
731
+ });
732
+ }
733
+ const nodePath = findNodePath(ast, node);
734
+ const resolved = resolveCurrentFrameExpression({
735
+ node,
736
+ ast,
737
+ seenDeclarations: new Set(),
738
+ });
739
+ if (!nodePath || resolved === null) {
740
+ return null;
741
+ }
742
+ const frameDisplayOffset = getFrameDisplayOffsetAdjustmentBetweenPaths({
743
+ startPath: nodePath,
744
+ endPath: resolved.bindingScopePath,
745
+ videoConfigValues,
746
+ });
747
+ if (frameDisplayOffset === null) {
748
+ return null;
749
+ }
750
+ return {
751
+ ...frameDisplayOffset,
752
+ // interpolate(frame + offset, [keyframe], ...) reaches the keyframe at
753
+ // composition frame `keyframe - offset`.
754
+ adjustment: frameDisplayOffset.adjustment - resolved.offset,
755
+ };
472
756
  };
473
757
  const getComputedStatus = (node, ast, videoConfigValues) => {
474
758
  const interpolation = getInterpolationKeyframes(node, ast, videoConfigValues);
@@ -478,6 +762,7 @@ const getComputedStatus = (node, ast, videoConfigValues) => {
478
762
  return {
479
763
  status: 'keyframed',
480
764
  interpolationFunction: interpolation.interpolationFunction,
765
+ keyframeDisplayOffsetAdjustment: interpolation.keyframeDisplayOffsetAdjustment,
481
766
  keyframes: interpolation.keyframes,
482
767
  easing: interpolation.easing,
483
768
  clamping: interpolation.clamping,
@@ -567,17 +852,17 @@ const findJsxElementAtNodePath = (ast, nodePath) => {
567
852
  return current ? current.value : null;
568
853
  };
569
854
  exports.findJsxElementAtNodePath = findJsxElementAtNodePath;
570
- const findJsxElementNodeAtNodePath = (ast, nodePath) => {
855
+ const getJsxElementNodeFromJsxPath = (jsxPath) => {
571
856
  var _a;
572
- const current = (0, exports.findJsxElementPathAtNodePath)(ast, nodePath);
573
- if (!current) {
574
- return null;
575
- }
576
- if (recast.types.namedTypes.JSXElement.check((_a = current.parentPath) === null || _a === void 0 ? void 0 : _a.value)) {
577
- return current.parentPath.value;
857
+ if (recast.types.namedTypes.JSXElement.check((_a = jsxPath.parentPath) === null || _a === void 0 ? void 0 : _a.value)) {
858
+ return jsxPath.parentPath.value;
578
859
  }
579
860
  return null;
580
861
  };
862
+ const findJsxElementNodeAtNodePath = (ast, nodePath) => {
863
+ const current = (0, exports.findJsxElementPathAtNodePath)(ast, nodePath);
864
+ return current ? getJsxElementNodeFromJsxPath(current) : null;
865
+ };
581
866
  exports.findJsxElementNodeAtNodePath = findJsxElementNodeAtNodePath;
582
867
  const findJsxChildrenAttribute = (jsxElement) => {
583
868
  const childrenAttr = jsxElement.attributes.find((attr) => {
@@ -648,8 +933,7 @@ const findNodePathForJsxElement = (ast, target) => {
648
933
  };
649
934
  exports.findNodePathForJsxElement = findNodePathForJsxElement;
650
935
  const RECAST_TAB_WIDTH = 4;
651
- const sourceColumnToRecastColumn = ({ fileContents, line, column, }) => {
652
- const sourceLine = fileContents.split('\n')[line - 1];
936
+ const sourceColumnToRecastColumn = ({ sourceLine, column, }) => {
653
937
  if (sourceLine === undefined) {
654
938
  return column;
655
939
  }
@@ -671,8 +955,7 @@ const lineColumnToNodePath = (ast, targetLine, targetColumn, fileContents) => {
671
955
  const recastTargetColumn = targetColumn === undefined || fileContents === undefined
672
956
  ? targetColumn
673
957
  : sourceColumnToRecastColumn({
674
- fileContents,
675
- line: targetLine,
958
+ sourceLine: fileContents.split('\n')[targetLine - 1],
676
959
  column: targetColumn,
677
960
  });
678
961
  recast.types.visit(ast, {
@@ -694,6 +977,55 @@ const lineColumnToNodePath = (ast, targetLine, targetColumn, fileContents) => {
694
977
  return (_a = lineMatches.at(-1)) !== null && _a !== void 0 ? _a : null;
695
978
  };
696
979
  exports.lineColumnToNodePath = lineColumnToNodePath;
980
+ const lineColumnsToNodePaths = ({ ast, targets, fileContents, }) => {
981
+ const sourceLines = fileContents.split('\n');
982
+ const targetIndicesByLine = new Map();
983
+ const recastTargetColumns = targets.map(({ line, column }, index) => {
984
+ var _a;
985
+ const indices = (_a = targetIndicesByLine.get(line)) !== null && _a !== void 0 ? _a : [];
986
+ indices.push(index);
987
+ targetIndicesByLine.set(line, indices);
988
+ return sourceColumnToRecastColumn({
989
+ sourceLine: sourceLines[line - 1],
990
+ column,
991
+ });
992
+ });
993
+ const lineMatches = targets.map(() => null);
994
+ const exactMatches = targets.map(() => null);
995
+ const exactMatchCounts = targets.map(() => 0);
996
+ recast.types.visit(ast, {
997
+ visitJSXOpeningElement(p) {
998
+ var _a, _b;
999
+ const { node } = p;
1000
+ const line = (_a = node.loc) === null || _a === void 0 ? void 0 : _a.start.line;
1001
+ const targetIndices = line ? targetIndicesByLine.get(line) : undefined;
1002
+ if (targetIndices) {
1003
+ const nodePath = (0, exports.getNodePathForRecastPath)(p, ast);
1004
+ for (const index of targetIndices) {
1005
+ lineMatches[index] = nodePath;
1006
+ if (((_b = node.loc) === null || _b === void 0 ? void 0 : _b.start.column) === recastTargetColumns[index]) {
1007
+ exactMatches[index] = nodePath;
1008
+ exactMatchCounts[index]++;
1009
+ }
1010
+ }
1011
+ }
1012
+ return this.traverse(p);
1013
+ },
1014
+ });
1015
+ return targets.map((_, index) => exactMatchCounts[index] === 1 ? exactMatches[index] : lineMatches[index]);
1016
+ };
1017
+ exports.lineColumnsToNodePaths = lineColumnsToNodePaths;
1018
+ const resolveSequencePropsNodePathsFromFilename = ({ fileName, targets, remotionRoot, }) => {
1019
+ const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
1020
+ remotionRoot,
1021
+ fileName,
1022
+ action: 'read',
1023
+ });
1024
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
1025
+ const { ast } = getCachedSequencePropsStatusAst(fileContents);
1026
+ return (0, exports.lineColumnsToNodePaths)({ ast, targets, fileContents });
1027
+ };
1028
+ exports.resolveSequencePropsNodePathsFromFilename = resolveSequencePropsNodePathsFromFilename;
697
1029
  const PIXEL_VALUE_REGEX = /^-?\d+(\.\d+)?px$/;
698
1030
  const isSupportedTranslateValue = (value) => {
699
1031
  const parts = value.split(/\s+/);
@@ -924,35 +1256,12 @@ const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys,
924
1256
  }
925
1257
  return filteredProps;
926
1258
  };
927
- const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
1259
+ const computeSequencePropsStatusFromAstAndIdentifiers = ({ ast, nodePath, componentIdentity, keys, assetKeys, effects, videoConfigIdentifierValues, }) => {
928
1260
  var _a;
929
- if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.fileContents) !== fileContents) {
930
- cachedSequencePropsStatusAst = null;
931
- const snapshot = {
932
- fileContents,
933
- ast: (0, parse_ast_1.parseAst)(fileContents),
934
- videoConfigIdentifierValues: new Map(),
935
- };
936
- cachedSequencePropsStatusAst = snapshot;
937
- queueMicrotask(() => {
938
- if (cachedSequencePropsStatusAst === snapshot) {
939
- cachedSequencePropsStatusAst = null;
940
- }
941
- });
942
- }
943
- const { ast } = cachedSequencePropsStatusAst;
944
- const videoConfigCacheKey = JSON.stringify(videoConfigValues);
945
- let videoConfigIdentifierValues = cachedSequencePropsStatusAst.videoConfigIdentifierValues.get(videoConfigCacheKey);
946
- if (videoConfigIdentifierValues === undefined) {
947
- videoConfigIdentifierValues = (0, video_config_values_1.getVideoConfigIdentifierValues)({
948
- ast,
949
- videoConfigValues,
950
- });
951
- cachedSequencePropsStatusAst.videoConfigIdentifierValues.set(videoConfigCacheKey, videoConfigIdentifierValues);
952
- }
953
- const jsxElementNode = (0, exports.findJsxElementNodeAtNodePath)(ast, nodePath);
1261
+ const jsxPath = (0, exports.findJsxElementPathAtNodePath)(ast, nodePath);
1262
+ const jsxElementNode = jsxPath ? getJsxElementNodeFromJsxPath(jsxPath) : null;
954
1263
  const jsxElement = (_a = jsxElementNode === null || jsxElementNode === void 0 ? void 0 : jsxElementNode.openingElement) !== null && _a !== void 0 ? _a : null;
955
- if (!jsxElement || !jsxElementNode) {
1264
+ if (!jsxPath || !jsxElement || !jsxElementNode) {
956
1265
  throw new jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError();
957
1266
  }
958
1267
  if (!(0, jsx_component_identity_1.jsxComponentIdentitiesMatch)({
@@ -975,12 +1284,79 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, compone
975
1284
  effects,
976
1285
  videoConfigValues: videoConfigIdentifierValues,
977
1286
  });
1287
+ const defaultKeyframeDisplayOffsetAdjustment = getDefaultFrameDisplayOffsetAdjustment({
1288
+ jsxPath,
1289
+ videoConfigValues: videoConfigIdentifierValues,
1290
+ });
1291
+ const addDefaultKeyframeDisplayOffsetAdjustment = (status) => {
1292
+ if (status.status !== 'static') {
1293
+ return status;
1294
+ }
1295
+ if (defaultKeyframeDisplayOffsetAdjustment === null) {
1296
+ return computedStatus();
1297
+ }
1298
+ if (defaultKeyframeDisplayOffsetAdjustment === 0) {
1299
+ return status;
1300
+ }
1301
+ return {
1302
+ ...status,
1303
+ keyframeDisplayOffsetAdjustment: defaultKeyframeDisplayOffsetAdjustment,
1304
+ };
1305
+ };
978
1306
  return {
979
1307
  canUpdate: true,
980
- props: filteredProps,
981
- effects: effectsStatuses,
1308
+ props: Object.fromEntries(Object.entries(filteredProps).map(([key, status]) => [
1309
+ key,
1310
+ addDefaultKeyframeDisplayOffsetAdjustment(status),
1311
+ ])),
1312
+ effects: effectsStatuses.map((effectStatus) => effectStatus.canUpdate
1313
+ ? {
1314
+ ...effectStatus,
1315
+ props: Object.fromEntries(Object.entries(effectStatus.props).map(([key, status]) => [
1316
+ key,
1317
+ addDefaultKeyframeDisplayOffsetAdjustment(status),
1318
+ ])),
1319
+ }
1320
+ : effectStatus),
982
1321
  };
983
1322
  };
1323
+ const computeSequencePropsStatusFromAst = ({ ast, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
1324
+ return computeSequencePropsStatusFromAstAndIdentifiers({
1325
+ ast,
1326
+ nodePath,
1327
+ componentIdentity,
1328
+ keys,
1329
+ assetKeys,
1330
+ effects,
1331
+ videoConfigIdentifierValues: (0, video_config_values_1.getVideoConfigIdentifierValues)({
1332
+ ast,
1333
+ videoConfigValues,
1334
+ }),
1335
+ });
1336
+ };
1337
+ exports.computeSequencePropsStatusFromAst = computeSequencePropsStatusFromAst;
1338
+ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
1339
+ const cachedAst = getCachedSequencePropsStatusAst(fileContents);
1340
+ const { ast } = cachedAst;
1341
+ const videoConfigCacheKey = JSON.stringify(videoConfigValues);
1342
+ let videoConfigIdentifierValues = cachedAst.videoConfigIdentifierValues.get(videoConfigCacheKey);
1343
+ if (videoConfigIdentifierValues === undefined) {
1344
+ videoConfigIdentifierValues = (0, video_config_values_1.getVideoConfigIdentifierValues)({
1345
+ ast,
1346
+ videoConfigValues,
1347
+ });
1348
+ cachedAst.videoConfigIdentifierValues.set(videoConfigCacheKey, videoConfigIdentifierValues);
1349
+ }
1350
+ return computeSequencePropsStatusFromAstAndIdentifiers({
1351
+ ast,
1352
+ nodePath,
1353
+ componentIdentity,
1354
+ keys,
1355
+ assetKeys,
1356
+ effects,
1357
+ videoConfigIdentifierValues,
1358
+ });
1359
+ };
984
1360
  exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
985
1361
  const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, keys, assetKeys = [], effects, remotionRoot, videoConfigValues, }) => {
986
1362
  const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
@@ -1008,7 +1384,7 @@ const computeSequencePropsStatusFromFilenameByLocation = ({ fileName, line, colu
1008
1384
  action: 'read',
1009
1385
  });
1010
1386
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
1011
- const ast = (0, parse_ast_1.parseAst)(fileContents);
1387
+ const { ast } = getCachedSequencePropsStatusAst(fileContents);
1012
1388
  const resolvedNodePath = (0, exports.lineColumnToNodePath)(ast, line, column, fileContents);
1013
1389
  if (!resolvedNodePath) {
1014
1390
  return {
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDefaultEditorInfoHandler = void 0;
4
+ const custom_editor_1 = require("../../helpers/custom-editor");
4
5
  const editor_registry_1 = require("../../helpers/editor-registry");
5
6
  const getDefaultEditorInfoHandler = async ({ getDefaultEditor }) => {
6
7
  const installedEditors = await (0, editor_registry_1.getAvailableEditors)();
7
8
  const configuredEditor = getDefaultEditor();
8
- const customEditor = configuredEditor && typeof configuredEditor === 'object'
9
+ const customEditor = configuredEditor &&
10
+ typeof configuredEditor === 'object' &&
11
+ (0, custom_editor_1.resolveCustomEditorExecutable)(configuredEditor)
9
12
  ? configuredEditor
10
13
  : null;
11
14
  return {
@@ -90,7 +90,7 @@ const deleteEffectHandler = ({ input: effects, remotionRoot, logLevel }) => {
90
90
  absolutePath: update.absolutePath,
91
91
  line: update.logLine,
92
92
  });
93
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${(0, formatting_1.strikeThroughOrRemovedPrefix)(deletedEffectDescription)}`);
93
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${(0, formatting_1.strikeThroughOrRemovedPrefix)(deletedEffectDescription)}`);
94
94
  if (!update.formatted) {
95
95
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
96
96
  }
@@ -87,7 +87,7 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
87
87
  absolutePath: update.absolutePath,
88
88
  line: update.logLine,
89
89
  });
90
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Deleted ${deletedNodeDescription}`);
90
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Deleted ${deletedNodeDescription}`);
91
91
  if (!update.formatted) {
92
92
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
93
93
  }
@@ -84,7 +84,7 @@ const duplicateEffectHandler = ({ input: effects, remotionRoot, logLevel }) => {
84
84
  absolutePath: update.absolutePath,
85
85
  line: update.logLine,
86
86
  });
87
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${(0, formatting_1.attrName)(duplicatedEffectDescription)}`);
87
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${(0, formatting_1.attrName)(duplicatedEffectDescription)}`);
88
88
  if (!update.formatted) {
89
89
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
90
90
  }
@@ -56,7 +56,7 @@ const duplicateJsxNodeHandler = ({ input: { fileName, nodePath }, remotionRoot,
56
56
  absolutePath,
57
57
  line: logLine,
58
58
  });
59
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${nodeLabel}`);
59
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${nodeLabel}`);
60
60
  if (!formatted) {
61
61
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
62
62
  }