@remotion/studio-server 4.0.470 → 4.0.472

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 (46) hide show
  1. package/dist/codemods/add-effect.d.ts +26 -0
  2. package/dist/codemods/add-effect.js +193 -0
  3. package/dist/codemods/format-file-content.js +1 -1
  4. package/dist/codemods/parse-ast.js +4 -1
  5. package/dist/codemods/paste-effects.d.ts +15 -0
  6. package/dist/codemods/paste-effects.js +234 -0
  7. package/dist/codemods/recast-mods.js +178 -31
  8. package/dist/codemods/reorder-effect.d.ts +13 -0
  9. package/dist/codemods/reorder-effect.js +61 -0
  10. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +1 -1
  11. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +7 -55
  12. package/dist/codemods/update-keyframes/update-keyframes.d.ts +15 -6
  13. package/dist/codemods/update-keyframes/update-keyframes.js +152 -26
  14. package/dist/helpers/get-ast-node-path.js +6 -1
  15. package/dist/helpers/import-agnostic-node-path.d.ts +10 -0
  16. package/dist/helpers/import-agnostic-node-path.js +154 -0
  17. package/dist/helpers/imports.d.ts +16 -0
  18. package/dist/helpers/imports.js +145 -0
  19. package/dist/helpers/open-in-editor.d.ts +2 -2
  20. package/dist/helpers/open-in-editor.js +35 -2
  21. package/dist/helpers/resolve-composition-component.d.ts +15 -0
  22. package/dist/helpers/resolve-composition-component.js +332 -31
  23. package/dist/preview-server/api-routes.js +10 -4
  24. package/dist/preview-server/routes/add-effect-keyframe.js +4 -2
  25. package/dist/preview-server/routes/add-effect.d.ts +3 -0
  26. package/dist/preview-server/routes/add-effect.js +68 -0
  27. package/dist/preview-server/routes/add-sequence-keyframe.js +7 -3
  28. package/dist/preview-server/routes/apply-codemod.js +18 -0
  29. package/dist/preview-server/routes/can-update-effect-props.d.ts +3 -2
  30. package/dist/preview-server/routes/can-update-effect-props.js +75 -6
  31. package/dist/preview-server/routes/can-update-sequence-props.d.ts +1 -0
  32. package/dist/preview-server/routes/can-update-sequence-props.js +47 -30
  33. package/dist/preview-server/routes/delete-keyframes.d.ts +13 -0
  34. package/dist/preview-server/routes/delete-keyframes.js +264 -0
  35. package/dist/preview-server/routes/insert-jsx-element.d.ts +3 -0
  36. package/dist/preview-server/routes/insert-jsx-element.js +102 -0
  37. package/dist/preview-server/routes/paste-effects.d.ts +3 -0
  38. package/dist/preview-server/routes/paste-effects.js +78 -0
  39. package/dist/preview-server/routes/reorder-effect.d.ts +3 -0
  40. package/dist/preview-server/routes/reorder-effect.js +67 -0
  41. package/dist/preview-server/routes/save-effect-props.js +1 -0
  42. package/dist/preview-server/routes/subscribe-to-sequence-props.js +2 -1
  43. package/dist/preview-server/sequence-props-watchers.d.ts +2 -1
  44. package/dist/preview-server/sequence-props-watchers.js +22 -2
  45. package/dist/preview-server/undo-stack.d.ts +15 -1
  46. package/package.json +6 -6
@@ -36,11 +36,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.resolveCompositionComponent = void 0;
39
+ exports.insertJsxElementIntoComposition = exports.resolveCompositionComponent = void 0;
40
40
  const node_fs_1 = __importDefault(require("node:fs"));
41
41
  const node_path_1 = __importDefault(require("node:path"));
42
42
  const recast = __importStar(require("recast"));
43
+ const format_file_content_1 = require("../codemods/format-file-content");
43
44
  const parse_ast_1 = require("../codemods/parse-ast");
45
+ const imports_1 = require("./imports");
44
46
  const allowedFileExtensions = new Set(['.tsx', '.ts', '.jsx', '.js']);
45
47
  const extensionsToProbe = ['.tsx', '.ts', '.jsx', '.js'];
46
48
  const isInRemotionRoot = ({ remotionRoot, fileName, }) => {
@@ -503,6 +505,253 @@ const getComponentRootNode = (declaration) => {
503
505
  const createSequenceElement = () => {
504
506
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier('Sequence'), []), recast.types.builders.jsxClosingElement(recast.types.builders.jsxIdentifier('Sequence')), []);
505
507
  };
508
+ const createNumberAttribute = (name, value) => {
509
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.jsxExpressionContainer(recast.types.builders.numericLiteral(value)));
510
+ };
511
+ const createPositionAbsoluteStyleAttribute = () => {
512
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('style'), recast.types.builders.jsxExpressionContainer(recast.types.builders.objectExpression([
513
+ recast.types.builders.objectProperty(recast.types.builders.identifier('position'), recast.types.builders.stringLiteral('absolute')),
514
+ ])));
515
+ };
516
+ const createStaticFileSrcAttribute = ({ staticFileLocalName, src, }) => {
517
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('src'), recast.types.builders.jsxExpressionContainer(recast.types.builders.callExpression(recast.types.builders.identifier(staticFileLocalName), [recast.types.builders.stringLiteral(src)])));
518
+ };
519
+ const createSolidElement = ({ localName, width, height, }) => {
520
+ return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
521
+ createNumberAttribute('width', width),
522
+ createNumberAttribute('height', height),
523
+ createPositionAbsoluteStyleAttribute(),
524
+ ], true), null, []);
525
+ };
526
+ const createAssetElement = ({ localName, staticFileLocalName, src, dimensions, }) => {
527
+ return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
528
+ createStaticFileSrcAttribute({ staticFileLocalName, src }),
529
+ createPositionAbsoluteStyleAttribute(),
530
+ ...(dimensions
531
+ ? [
532
+ createNumberAttribute('width', dimensions.width),
533
+ createNumberAttribute('height', dimensions.height),
534
+ ]
535
+ : []),
536
+ ], true), null, []);
537
+ };
538
+ const createFragmentWithElement = (element) => {
539
+ return recast.types.builders.jsxFragment(recast.types.builders.jsxOpeningFragment(), recast.types.builders.jsxClosingFragment(), [element]);
540
+ };
541
+ const replaceNullReturnInFunctionLike = ({ fn, element, }) => {
542
+ var _a, _b;
543
+ var _c, _d;
544
+ if (fn.type === 'ArrowFunctionExpression' && fn.body.type === 'NullLiteral') {
545
+ fn.body = createFragmentWithElement(element);
546
+ return (_c = (_a = fn.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _c !== void 0 ? _c : 1;
547
+ }
548
+ if (fn.body.type !== 'BlockStatement') {
549
+ return null;
550
+ }
551
+ const returnStatement = getTopLevelReturnStatement(fn.body.body);
552
+ if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument) ||
553
+ returnStatement.argument.type !== 'NullLiteral') {
554
+ return null;
555
+ }
556
+ returnStatement.argument = createFragmentWithElement(element);
557
+ return (_d = (_b = returnStatement.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : 1;
558
+ };
559
+ const addElementToNullComponentReturn = ({ declaration, element, }) => {
560
+ var _a;
561
+ var _b;
562
+ if (declaration.type === 'VariableDeclarator') {
563
+ if (!declaration.init ||
564
+ (declaration.init.type !== 'ArrowFunctionExpression' &&
565
+ declaration.init.type !== 'FunctionExpression')) {
566
+ return null;
567
+ }
568
+ return replaceNullReturnInFunctionLike({ fn: declaration.init, element });
569
+ }
570
+ if (declaration.type === 'ArrowFunctionExpression' ||
571
+ declaration.type === 'FunctionExpression' ||
572
+ declaration.type === 'FunctionDeclaration') {
573
+ return replaceNullReturnInFunctionLike({ fn: declaration, element });
574
+ }
575
+ if (declaration.type !== 'ClassDeclaration') {
576
+ return null;
577
+ }
578
+ const renderMethod = findRenderMethod(declaration);
579
+ if (!renderMethod) {
580
+ return null;
581
+ }
582
+ const returnStatement = getTopLevelReturnStatement(renderMethod.body.body);
583
+ if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument) ||
584
+ returnStatement.argument.type !== 'NullLiteral') {
585
+ return null;
586
+ }
587
+ returnStatement.argument = createFragmentWithElement(element);
588
+ return (_b = (_a = returnStatement.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _b !== void 0 ? _b : 1;
589
+ };
590
+ const declarationBindsName = (declaration, name) => {
591
+ var _a;
592
+ if (declaration.type === 'FunctionDeclaration' ||
593
+ declaration.type === 'ClassDeclaration') {
594
+ return ((_a = declaration.id) === null || _a === void 0 ? void 0 : _a.name) === name;
595
+ }
596
+ return declaration.declarations.some((variableDeclaration) => {
597
+ return (variableDeclaration.id.type === 'Identifier' &&
598
+ variableDeclaration.id.name === name);
599
+ });
600
+ };
601
+ const hasTopLevelBinding = ({ ast, name }) => {
602
+ return ast.program.body.some((node) => {
603
+ var _a;
604
+ if (node.type === 'FunctionDeclaration' ||
605
+ node.type === 'ClassDeclaration' ||
606
+ node.type === 'VariableDeclaration') {
607
+ return declarationBindsName(node, name);
608
+ }
609
+ if (node.type === 'ExportNamedDeclaration' &&
610
+ node.declaration &&
611
+ (node.declaration.type === 'FunctionDeclaration' ||
612
+ node.declaration.type === 'ClassDeclaration' ||
613
+ node.declaration.type === 'VariableDeclaration')) {
614
+ return declarationBindsName(node.declaration, name);
615
+ }
616
+ if (node.type !== 'ImportDeclaration') {
617
+ return false;
618
+ }
619
+ return (_a = node.specifiers) === null || _a === void 0 ? void 0 : _a.some((specifier) => {
620
+ var _a;
621
+ return ((_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) === name;
622
+ });
623
+ });
624
+ };
625
+ const getAvailableSolidLocalName = (ast) => {
626
+ const candidates = ['Solid', 'RemotionSolid'];
627
+ const available = candidates.find((candidate) => {
628
+ return !hasTopLevelBinding({ ast, name: candidate });
629
+ });
630
+ if (!available) {
631
+ throw new Error('Cannot add <Solid> because Solid is already defined');
632
+ }
633
+ return available;
634
+ };
635
+ const ensureSolidImport = (ast) => {
636
+ return (0, imports_1.ensureNamedImport)({
637
+ ast,
638
+ importedName: 'Solid',
639
+ sourcePath: 'remotion',
640
+ localName: getAvailableSolidLocalName(ast),
641
+ });
642
+ };
643
+ const getImportDeclarations = ({ ast, sourcePath, }) => {
644
+ return ast.program.body.filter((node) => node.type === 'ImportDeclaration' &&
645
+ node.source.type === 'StringLiteral' &&
646
+ node.source.value === sourcePath);
647
+ };
648
+ const importDeclarationHasNamespaceSpecifier = (importDeclaration) => {
649
+ var _a;
650
+ return (_a = importDeclaration.specifiers) === null || _a === void 0 ? void 0 : _a.some((specifier) => specifier.type === 'ImportNamespaceSpecifier');
651
+ };
652
+ const hasOfficialLocalImport = ({ ast, importedName, sourcePath, }) => {
653
+ return getImportDeclarations({ ast, sourcePath }).some((importDeclaration) => {
654
+ var _a;
655
+ return (_a = importDeclaration.specifiers) === null || _a === void 0 ? void 0 : _a.some((specifier) => {
656
+ var _a;
657
+ var _b;
658
+ return (specifier.type === 'ImportSpecifier' &&
659
+ (0, imports_1.getImportedName)(specifier) === importedName &&
660
+ ((_b = (_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : importedName) === importedName);
661
+ });
662
+ });
663
+ };
664
+ const addOfficialNamedImport = ({ ast, importedName, sourcePath, }) => {
665
+ var _a;
666
+ const existingImport = getImportDeclarations({ ast, sourcePath }).find((candidate) => !importDeclarationHasNamespaceSpecifier(candidate));
667
+ const importSpecifier = recast.types.builders.importSpecifier(recast.types.builders.identifier(importedName));
668
+ if (existingImport) {
669
+ existingImport.specifiers = [
670
+ ...((_a = existingImport.specifiers) !== null && _a !== void 0 ? _a : []),
671
+ importSpecifier,
672
+ ];
673
+ return;
674
+ }
675
+ const importDeclaration = recast.types.builders.importDeclaration([importSpecifier], recast.types.builders.stringLiteral(sourcePath));
676
+ (0, imports_1.insertImportDeclaration)(ast, importDeclaration);
677
+ };
678
+ const ensureOfficialNamedImport = ({ ast, importedName, sourcePath, label, }) => {
679
+ if (hasOfficialLocalImport({ ast, importedName, sourcePath })) {
680
+ return importedName;
681
+ }
682
+ if (hasTopLevelBinding({ ast, name: importedName })) {
683
+ throw new Error(`Cannot add ${label} because ${importedName} is already defined`);
684
+ }
685
+ addOfficialNamedImport({ ast, importedName, sourcePath });
686
+ return importedName;
687
+ };
688
+ const ensureStaticFileImport = (ast) => {
689
+ return ensureOfficialNamedImport({
690
+ ast,
691
+ importedName: 'staticFile',
692
+ sourcePath: 'remotion',
693
+ label: 'staticFile()',
694
+ });
695
+ };
696
+ const ensureImgImport = (ast) => {
697
+ return ensureOfficialNamedImport({
698
+ ast,
699
+ importedName: 'Img',
700
+ sourcePath: 'remotion',
701
+ label: '<Img>',
702
+ });
703
+ };
704
+ const ensureVideoImport = (ast) => {
705
+ return ensureOfficialNamedImport({
706
+ ast,
707
+ importedName: 'Video',
708
+ sourcePath: '@remotion/media',
709
+ label: '<Video>',
710
+ });
711
+ };
712
+ const ensureGifImport = (ast) => {
713
+ return ensureOfficialNamedImport({
714
+ ast,
715
+ importedName: 'Gif',
716
+ sourcePath: '@remotion/gif',
717
+ label: '<Gif>',
718
+ });
719
+ };
720
+ const addElementToComponentRoot = ({ ast, exportName, element, }) => {
721
+ var _a;
722
+ var _b;
723
+ const declaration = getDeclarationByExportName({ ast, exportName });
724
+ if (!declaration) {
725
+ throw new Error('Could not find composition component declaration');
726
+ }
727
+ const rootNode = getComponentRootNode(declaration);
728
+ if (!rootNode) {
729
+ const insertedAt = addElementToNullComponentReturn({ declaration, element });
730
+ if (insertedAt !== null) {
731
+ return insertedAt;
732
+ }
733
+ throw new Error('Composition component does not return JSX');
734
+ }
735
+ if (rootNode.type === 'JSXElement' && rootNode.openingElement.selfClosing) {
736
+ throw new Error('Cannot insert into a self-closing root JSX element');
737
+ }
738
+ const CANVAS_ROOT_ELEMENTS = [
739
+ 'ThreeCanvas',
740
+ 'RiveCanvas',
741
+ 'SkiaCanvas',
742
+ 'canvas',
743
+ ];
744
+ if (rootNode.type === 'JSXElement' &&
745
+ rootNode.openingElement.name.type === 'JSXIdentifier' &&
746
+ CANVAS_ROOT_ELEMENTS.includes(rootNode.openingElement.name.name)) {
747
+ throw new Error(`Cannot insert a JSX element into a composition whose root element is <${rootNode.openingElement.name.name}>`);
748
+ }
749
+ if (!rootNode.children) {
750
+ throw new Error('Composition component root does not accept children');
751
+ }
752
+ rootNode.children.push(element);
753
+ return (_b = (_a = rootNode.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _b !== void 0 ? _b : 1;
754
+ };
506
755
  const getDefaultExportDeclaration = (ast) => {
507
756
  let declaration = null;
508
757
  let identifierName = null;
@@ -532,39 +781,16 @@ const getDeclarationByExportName = ({ ast, exportName, }) => {
532
781
  return findLocalComponentDeclaration({ ast, name: exportName });
533
782
  };
534
783
  const canAddSequenceToComponent = ({ ast, exportName, }) => {
535
- const declaration = getDeclarationByExportName({ ast, exportName });
536
- if (!declaration) {
537
- return false;
538
- }
539
- const rootNode = getComponentRootNode(declaration);
540
- if (!rootNode) {
541
- return false;
542
- }
543
- if (rootNode.type === 'JSXElement') {
544
- if (rootNode.openingElement.selfClosing) {
545
- return false;
546
- }
547
- if (!rootNode.children) {
548
- return false;
549
- }
550
- rootNode.children.push(createSequenceElement());
551
- try {
552
- recast.print(ast);
553
- return true;
554
- }
555
- catch (_a) {
556
- return false;
557
- }
558
- }
559
- if (!rootNode.children) {
560
- return false;
561
- }
562
- rootNode.children.push(createSequenceElement());
563
784
  try {
785
+ addElementToComponentRoot({
786
+ ast,
787
+ exportName,
788
+ element: createSequenceElement(),
789
+ });
564
790
  recast.print(ast);
565
791
  return true;
566
792
  }
567
- catch (_b) {
793
+ catch (_a) {
568
794
  return false;
569
795
  }
570
796
  };
@@ -582,6 +808,8 @@ const getComponentLocationInFile = async ({ remotionRoot, fileName, exportName,
582
808
  });
583
809
  return {
584
810
  source: node_path_1.default.relative(remotionRoot, fileName),
811
+ fileName,
812
+ exportName,
585
813
  line: (_a = location === null || location === void 0 ? void 0 : location.line) !== null && _a !== void 0 ? _a : 1,
586
814
  column: (_b = location === null || location === void 0 ? void 0 : location.column) !== null && _b !== void 0 ? _b : 0,
587
815
  canAddSequence,
@@ -641,7 +869,7 @@ const getComponentLocationRecursively = async ({ remotionRoot, fileName, exportN
641
869
  visited.delete(key);
642
870
  }
643
871
  };
644
- const resolveCompositionComponent = async ({ remotionRoot, compositionFile, compositionId, }) => {
872
+ const resolveCompositionComponentWithFile = async ({ remotionRoot, compositionFile, compositionId, }) => {
645
873
  const compositionFileName = node_path_1.default.resolve(remotionRoot, compositionFile);
646
874
  const input = await readSourceFile({
647
875
  remotionRoot,
@@ -688,4 +916,77 @@ const resolveCompositionComponent = async ({ remotionRoot, compositionFile, comp
688
916
  visited: new Set(),
689
917
  });
690
918
  };
919
+ const resolveCompositionComponent = async ({ remotionRoot, compositionFile, compositionId, }) => {
920
+ const { source, line, column, canAddSequence } = await resolveCompositionComponentWithFile({
921
+ remotionRoot,
922
+ compositionFile,
923
+ compositionId,
924
+ });
925
+ return {
926
+ source,
927
+ line,
928
+ column,
929
+ canAddSequence,
930
+ };
931
+ };
691
932
  exports.resolveCompositionComponent = resolveCompositionComponent;
933
+ const createInsertableJsxElement = ({ ast, element, }) => {
934
+ if (element.type === 'solid') {
935
+ const solidLocalName = ensureSolidImport(ast);
936
+ return createSolidElement({
937
+ localName: solidLocalName,
938
+ width: element.width,
939
+ height: element.height,
940
+ });
941
+ }
942
+ if (element.type === 'asset') {
943
+ const staticFileLocalName = ensureStaticFileImport(ast);
944
+ const localName = element.assetType === 'image'
945
+ ? ensureImgImport(ast)
946
+ : element.assetType === 'video'
947
+ ? ensureVideoImport(ast)
948
+ : ensureGifImport(ast);
949
+ return createAssetElement({
950
+ localName,
951
+ staticFileLocalName,
952
+ src: element.src,
953
+ dimensions: element.dimensions,
954
+ });
955
+ }
956
+ throw new Error('Unsupported element type');
957
+ };
958
+ const insertJsxElementIntoComposition = async ({ remotionRoot, compositionFile, compositionId, element, prettierConfigOverride, }) => {
959
+ const location = await resolveCompositionComponentWithFile({
960
+ remotionRoot,
961
+ compositionFile,
962
+ compositionId,
963
+ });
964
+ if (!location.canAddSequence) {
965
+ throw new Error('Cannot insert JSX element into this composition component');
966
+ }
967
+ const input = await readSourceFile({
968
+ remotionRoot,
969
+ fileName: location.fileName,
970
+ });
971
+ const ast = (0, parse_ast_1.parseAst)(input);
972
+ const elementToInsert = createInsertableJsxElement({ ast, element });
973
+ const logLine = addElementToComponentRoot({
974
+ ast,
975
+ exportName: location.exportName,
976
+ element: elementToInsert,
977
+ });
978
+ const finalFile = (0, parse_ast_1.serializeAst)(ast);
979
+ const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
980
+ input: finalFile,
981
+ prettierConfigOverride,
982
+ });
983
+ return {
984
+ fileName: location.fileName,
985
+ source: location.source,
986
+ oldContents: input,
987
+ output,
988
+ formatted,
989
+ logLine,
990
+ };
991
+ };
992
+ exports.insertJsxElementIntoComposition = insertJsxElementIntoComposition;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.allApiRoutes = void 0;
4
+ const add_effect_1 = require("./routes/add-effect");
4
5
  const add_effect_keyframe_1 = require("./routes/add-effect-keyframe");
5
6
  const add_render_1 = require("./routes/add-render");
6
7
  const add_sequence_keyframe_1 = require("./routes/add-sequence-keyframe");
@@ -9,18 +10,20 @@ const apply_visual_control_change_1 = require("./routes/apply-visual-control-cha
9
10
  const cancel_render_1 = require("./routes/cancel-render");
10
11
  const composition_component_info_1 = require("./routes/composition-component-info");
11
12
  const delete_effect_1 = require("./routes/delete-effect");
12
- const delete_effect_keyframe_1 = require("./routes/delete-effect-keyframe");
13
13
  const delete_jsx_node_1 = require("./routes/delete-jsx-node");
14
- const delete_sequence_keyframe_1 = require("./routes/delete-sequence-keyframe");
14
+ const delete_keyframes_1 = require("./routes/delete-keyframes");
15
15
  const delete_static_file_1 = require("./routes/delete-static-file");
16
16
  const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
17
+ const insert_jsx_element_1 = require("./routes/insert-jsx-element");
17
18
  const install_dependency_1 = require("./routes/install-dependency");
18
19
  const open_in_editor_1 = require("./routes/open-in-editor");
19
20
  const open_in_file_explorer_1 = require("./routes/open-in-file-explorer");
21
+ const paste_effects_1 = require("./routes/paste-effects");
20
22
  const project_info_1 = require("./routes/project-info");
21
23
  const redo_1 = require("./routes/redo");
22
24
  const register_client_render_1 = require("./routes/register-client-render");
23
25
  const remove_render_1 = require("./routes/remove-render");
26
+ const reorder_effect_1 = require("./routes/reorder-effect");
24
27
  const restart_studio_1 = require("./routes/restart-studio");
25
28
  const save_effect_props_1 = require("./routes/save-effect-props");
26
29
  const save_sequence_props_1 = require("./routes/save-sequence-props");
@@ -54,11 +57,13 @@ exports.allApiRoutes = {
54
57
  '/api/unsubscribe-from-sequence-props': unsubscribe_from_sequence_props_1.unsubscribeFromSequenceProps,
55
58
  '/api/save-sequence-props': save_sequence_props_1.saveSequencePropsHandler,
56
59
  '/api/save-effect-props': save_effect_props_1.saveEffectPropsHandler,
57
- '/api/delete-sequence-keyframe': delete_sequence_keyframe_1.deleteSequenceKeyframeHandler,
60
+ '/api/add-effect': add_effect_1.addEffectHandler,
61
+ '/api/reorder-effect': reorder_effect_1.reorderEffectHandler,
62
+ '/api/delete-keyframes': delete_keyframes_1.deleteKeyframesHandler,
58
63
  '/api/add-sequence-keyframe': add_sequence_keyframe_1.addSequenceKeyframeHandler,
59
- '/api/delete-effect-keyframe': delete_effect_keyframe_1.deleteEffectKeyframeHandler,
60
64
  '/api/add-effect-keyframe': add_effect_keyframe_1.addEffectKeyframeHandler,
61
65
  '/api/delete-effect': delete_effect_1.deleteEffectHandler,
66
+ '/api/paste-effects': paste_effects_1.pasteEffectsHandler,
62
67
  '/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
63
68
  '/api/duplicate-jsx-node': duplicate_jsx_node_1.duplicateJsxNodeHandler,
64
69
  '/api/update-available': update_available_1.handleUpdate,
@@ -66,6 +71,7 @@ exports.allApiRoutes = {
66
71
  '/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
67
72
  '/api/restart-studio': restart_studio_1.handleRestartStudio,
68
73
  '/api/install-package': install_dependency_1.handleInstallPackage,
74
+ '/api/insert-jsx-element': insert_jsx_element_1.insertJsxElementHandler,
69
75
  '/api/undo': undo_1.undoHandler,
70
76
  '/api/redo': redo_1.redoHandler,
71
77
  };
@@ -23,10 +23,11 @@ const addEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectI
23
23
  });
24
24
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
25
25
  const parsedValue = JSON.parse(value);
26
- const { output, oldValueStrings, newValueStrings, formatted, logLine, effectCallee, } = await (0, update_keyframes_1.updateEffectKeyframes)({
26
+ const { output, oldValueStrings, newValueStrings, formatted, logLine, effectCallee, updatedSequenceNodePath, } = await (0, update_keyframes_1.updateEffectKeyframes)({
27
27
  input: fileContents,
28
28
  sequenceNodePath: sequenceNodePath.nodePath,
29
29
  effectIndex,
30
+ schema,
30
31
  updates: [
31
32
  {
32
33
  key,
@@ -74,7 +75,7 @@ const addEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectI
74
75
  });
75
76
  (0, undo_stack_1.printUndoHint)(logLevel);
76
77
  const ast = (0, parse_ast_1.parseAst)((0, node_fs_1.readFileSync)(absolutePath, 'utf-8'));
77
- const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, sequenceNodePath.nodePath);
78
+ const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, updatedSequenceNodePath);
78
79
  if (!jsx) {
79
80
  return {
80
81
  canUpdate: false,
@@ -83,6 +84,7 @@ const addEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectI
83
84
  };
84
85
  }
85
86
  return (0, can_update_effect_props_1.computeEffectPropStatus)({
87
+ ast,
86
88
  jsx,
87
89
  effectIndex,
88
90
  keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
@@ -0,0 +1,3 @@
1
+ import type { AddEffectRequest, AddEffectResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const addEffectHandler: ApiHandler<AddEffectRequest, AddEffectResponse>;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addEffectHandler = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const renderer_1 = require("@remotion/renderer");
6
+ const add_effect_1 = require("../../codemods/add-effect");
7
+ const file_watcher_1 = require("../../file-watcher");
8
+ const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
9
+ const format_log_file_location_1 = require("../format-log-file-location");
10
+ const undo_stack_1 = require("../undo-stack");
11
+ const formatting_1 = require("./log-updates/formatting");
12
+ const log_update_1 = require("./log-updates/log-update");
13
+ const addEffectHandler = async ({ input: { fileName, sequenceNodePath, effectName, effectImportPath, effectConfig, clientId, }, remotionRoot, logLevel, }) => {
14
+ try {
15
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[add-effect] Received request for fileName="${fileName}" effect="${effectName}"`);
16
+ const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
17
+ remotionRoot,
18
+ fileName,
19
+ action: 'modify',
20
+ });
21
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
22
+ const { output, formatted, effectLabel, nodeLabel, logLine } = await (0, add_effect_1.addEffect)({
23
+ input: fileContents,
24
+ sequenceNodePath: sequenceNodePath.nodePath,
25
+ effectName,
26
+ effectImportPath,
27
+ effectConfig,
28
+ });
29
+ (0, undo_stack_1.pushToUndoStack)({
30
+ filePath: absolutePath,
31
+ oldContents: fileContents,
32
+ newContents: null,
33
+ logLevel,
34
+ remotionRoot,
35
+ logLine,
36
+ description: {
37
+ undoMessage: `↩️ Addition of ${effectLabel} to ${nodeLabel}`,
38
+ redoMessage: `↪️ Addition of ${effectLabel} to ${nodeLabel}`,
39
+ },
40
+ entryType: 'add-effect',
41
+ suppressHmrOnFileRestore: false,
42
+ });
43
+ (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
44
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
45
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
46
+ remotionRoot,
47
+ absolutePath,
48
+ line: logLine,
49
+ });
50
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Added ${(0, formatting_1.attrName)(effectLabel)} to ${nodeLabel}`);
51
+ if (!formatted) {
52
+ (0, log_update_1.warnAboutPrettierOnce)(logLevel);
53
+ }
54
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[add-effect] Wrote ${fileRelativeToRoot}${formatted ? ' (formatted)' : ''}`);
55
+ (0, undo_stack_1.printUndoHint)(logLevel);
56
+ return {
57
+ success: true,
58
+ };
59
+ }
60
+ catch (err) {
61
+ return {
62
+ success: false,
63
+ reason: err.message,
64
+ stack: err.stack,
65
+ };
66
+ }
67
+ };
68
+ exports.addEffectHandler = addEffectHandler;
@@ -21,9 +21,10 @@ const addSequenceKeyframeHandler = ({ input: { fileName, nodePath, key, frame, v
21
21
  });
22
22
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
23
23
  const parsedValue = JSON.parse(value);
24
- const { output, oldValueStrings, newValueStrings, formatted, logLine } = await (0, update_keyframes_1.updateSequenceKeyframes)({
24
+ const { output, oldValueStrings, newValueStrings, formatted, logLine, updatedNodePath, } = await (0, update_keyframes_1.updateSequenceKeyframes)({
25
25
  input: fileContents,
26
26
  nodePath: nodePath.nodePath,
27
+ schema,
27
28
  updates: [
28
29
  {
29
30
  key,
@@ -72,13 +73,16 @@ const addSequenceKeyframeHandler = ({ input: { fileName, nodePath, key, frame, v
72
73
  const status = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
73
74
  fileContents: output,
74
75
  keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
75
- nodePath: nodePath.nodePath,
76
+ nodePath: updatedNodePath,
76
77
  effects: [],
77
78
  });
79
+ const updatedSubscriptionKey = { ...nodePath, nodePath: updatedNodePath };
78
80
  return {
79
81
  canUpdate: true,
80
82
  props: status.props,
81
- results: [{ fileName, nodePath, props: status.props }],
83
+ results: [
84
+ { fileName, nodePath: updatedSubscriptionKey, props: status.props },
85
+ ],
82
86
  };
83
87
  });
84
88
  exports.addSequenceKeyframeHandler = addSequenceKeyframeHandler;
@@ -37,6 +37,24 @@ const getCodemodUndoDescription = (codemod) => {
37
37
  entryType: codemod.type,
38
38
  };
39
39
  }
40
+ if (codemod.type === 'delete-folder') {
41
+ const label = `folder "${codemod.parentName ? `${codemod.parentName}/` : ''}${codemod.folderName}"`;
42
+ return {
43
+ undoMessage: `↩️ Deletion of ${label}`,
44
+ redoMessage: `↪️ Deletion of ${label}`,
45
+ entryType: codemod.type,
46
+ };
47
+ }
48
+ if (codemod.type === 'rename-folder') {
49
+ const oldName = `${codemod.parentName ? `${codemod.parentName}/` : ''}${codemod.folderName}`;
50
+ const newName = `${codemod.parentName ? `${codemod.parentName}/` : ''}${codemod.newName}`;
51
+ const label = `folder "${oldName}" to "${newName}"`;
52
+ return {
53
+ undoMessage: `↩️ Rename of ${label}`,
54
+ redoMessage: `↪️ Rename of ${label}`,
55
+ entryType: codemod.type,
56
+ };
57
+ }
40
58
  return {
41
59
  undoMessage: '↩️ Visual control change',
42
60
  redoMessage: '↪️ Visual control change',
@@ -1,6 +1,7 @@
1
- import type { JSXOpeningElement } from '@babel/types';
1
+ import type { File, JSXOpeningElement } from '@babel/types';
2
2
  import type { CanUpdateEffectPropsResponse, SequenceNodePath, SequenceSchema } from 'remotion';
3
- export declare const computeEffectPropStatus: ({ jsx, effectIndex, keys, }: {
3
+ export declare const computeEffectPropStatus: ({ ast, jsx, effectIndex, keys, }: {
4
+ ast: File;
4
5
  jsx: JSXOpeningElement;
5
6
  effectIndex: number;
6
7
  keys: string[];