@remotion/studio-server 4.0.528 → 4.0.530

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 (64) hide show
  1. package/dist/codemods/add-composition-to-file.d.ts +7 -0
  2. package/dist/codemods/add-composition-to-file.js +63 -0
  3. package/dist/codemods/apply-codemod-to-file.js +6 -1
  4. package/dist/codemods/effect-param-expression.d.ts +1 -1
  5. package/dist/codemods/effect-param-expression.js +3 -2
  6. package/dist/codemods/update-keyframes/update-keyframes.d.ts +3 -3
  7. package/dist/codemods/update-keyframes/update-keyframes.js +1 -1
  8. package/dist/codemods/update-sequence-props/update-sequence-props.js +1 -1
  9. package/dist/helpers/get-local-package-override.d.ts +5 -0
  10. package/dist/helpers/get-local-package-override.js +39 -0
  11. package/dist/helpers/resolve-composition-component.d.ts +2 -1
  12. package/dist/helpers/resolve-composition-component.js +66 -15
  13. package/dist/index.d.ts +5 -0
  14. package/dist/index.js +3 -0
  15. package/dist/preview-server/api-routes.js +32 -12
  16. package/dist/preview-server/element-install-state.js +10 -2
  17. package/dist/preview-server/routes/add-composition.d.ts +3 -0
  18. package/dist/preview-server/routes/add-composition.js +97 -0
  19. package/dist/preview-server/routes/add-folder.d.ts +3 -0
  20. package/dist/preview-server/routes/add-folder.js +107 -0
  21. package/dist/preview-server/routes/add-keyframes.d.ts +2 -2
  22. package/dist/preview-server/routes/add-keyframes.js +49 -6
  23. package/dist/preview-server/routes/can-update-sequence-props.js +40 -11
  24. package/dist/preview-server/routes/delete-composition.d.ts +3 -0
  25. package/dist/preview-server/routes/delete-composition.js +104 -0
  26. package/dist/preview-server/routes/delete-nodes.d.ts +3 -0
  27. package/dist/preview-server/routes/delete-nodes.js +142 -0
  28. package/dist/preview-server/routes/duplicate-composition.d.ts +3 -0
  29. package/dist/preview-server/routes/duplicate-composition.js +114 -0
  30. package/dist/preview-server/routes/duplicate-nodes.d.ts +3 -0
  31. package/dist/preview-server/routes/duplicate-nodes.js +123 -0
  32. package/dist/preview-server/routes/insert-basic-captions.js +2 -1
  33. package/dist/preview-server/routes/insert-composition-element.d.ts +3 -0
  34. package/dist/preview-server/routes/insert-composition-element.js +236 -0
  35. package/dist/preview-server/routes/insert-element.js +26 -19
  36. package/dist/preview-server/routes/install-dependency.js +10 -1
  37. package/dist/preview-server/routes/move-composition.d.ts +3 -0
  38. package/dist/preview-server/routes/move-composition.js +148 -0
  39. package/dist/preview-server/routes/move-folder.d.ts +3 -0
  40. package/dist/preview-server/routes/move-folder.js +151 -0
  41. package/dist/preview-server/routes/precompose-jsx-nodes.d.ts +3 -0
  42. package/dist/preview-server/routes/precompose-jsx-nodes.js +209 -0
  43. package/dist/preview-server/routes/rename-composition.d.ts +3 -0
  44. package/dist/preview-server/routes/rename-composition.js +105 -0
  45. package/dist/preview-server/routes/rename-folder.d.ts +3 -0
  46. package/dist/preview-server/routes/rename-folder.js +111 -0
  47. package/dist/preview-server/routes/reorder-sequence.js +7 -2
  48. package/dist/preview-server/routes/replace-video-source.js +7 -2
  49. package/dist/preview-server/routes/save-sequence-props.js +6 -3
  50. package/dist/preview-server/routes/split-sequences.d.ts +3 -0
  51. package/dist/preview-server/routes/split-sequences.js +122 -0
  52. package/dist/preview-server/routes/split-video-from-audio.js +6 -1
  53. package/dist/preview-server/routes/unwrap-folder.d.ts +3 -0
  54. package/dist/preview-server/routes/unwrap-folder.js +107 -0
  55. package/dist/preview-server/routes/update-composition-metadata.d.ts +3 -0
  56. package/dist/preview-server/routes/update-composition-metadata.js +110 -0
  57. package/dist/preview-server/routes/wrap-node.d.ts +3 -0
  58. package/dist/preview-server/routes/wrap-node.js +108 -0
  59. package/dist/preview-server/studio-protocol/handle-discovery.js +3 -10
  60. package/dist/preview-server/studio-protocol/handle-install.js +0 -3
  61. package/dist/preview-server/undo-stack.d.ts +1 -1
  62. package/dist/preview-server/undo-stack.js +6 -0
  63. package/dist/start-studio.js +1 -1
  64. package/package.json +8 -8
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addFolderHandler = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const codemods_1 = require("@remotion/codemods");
10
+ const renderer_1 = require("@remotion/renderer");
11
+ const file_watcher_1 = require("../../file-watcher");
12
+ const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
13
+ const format_log_file_location_1 = require("../format-log-file-location");
14
+ const project_info_1 = require("../project-info");
15
+ const undo_stack_1 = require("../undo-stack");
16
+ const can_update_default_props_1 = require("./can-update-default-props");
17
+ const source_file_write_queue_1 = require("./source-file-write-queue");
18
+ const addFolderHandler = ({ input: request, logLevel, remotionRoot, entryPoint }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
19
+ var _a, _b;
20
+ var _c, _d;
21
+ try {
22
+ let filePath;
23
+ if ((_a = request.symbolicatedStack) === null || _a === void 0 ? void 0 : _a.originalFileName) {
24
+ filePath = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
25
+ remotionRoot,
26
+ fileName: request.symbolicatedStack.originalFileName,
27
+ action: 'add a folder to',
28
+ }).absolutePath;
29
+ }
30
+ else {
31
+ const { rootFile } = await (0, project_info_1.getProjectInfo)(remotionRoot, entryPoint);
32
+ if (rootFile === null) {
33
+ throw new Error('Cannot find the Remotion root file');
34
+ }
35
+ filePath = rootFile;
36
+ }
37
+ (0, can_update_default_props_1.checkIfTypeScriptFile)(filePath);
38
+ const result = (0, codemods_1.addFolder)({
39
+ project: {
40
+ files: { [filePath]: (0, node_fs_1.readFileSync)(filePath, 'utf-8') },
41
+ rootDir: node_path_1.default.dirname(filePath),
42
+ },
43
+ compositionFile: filePath,
44
+ folder: { name: request.folderName, parentName: request.parentName },
45
+ });
46
+ for (const change of result.changes) {
47
+ const currentContents = (0, node_fs_1.existsSync)(change.filePath)
48
+ ? (0, node_fs_1.readFileSync)(change.filePath, 'utf-8')
49
+ : null;
50
+ if (currentContents !== change.previousContents) {
51
+ throw new Error(`Source changed before adding folder: ${change.filePath}`);
52
+ }
53
+ }
54
+ if (result.changes.length > 0) {
55
+ const logLine = (_c = (_b = request.symbolicatedStack) === null || _b === void 0 ? void 0 : _b.originalLineNumber) !== null && _c !== void 0 ? _c : 1;
56
+ const folderPath = request.parentName
57
+ ? `${request.parentName}/${request.folderName}`
58
+ : request.folderName;
59
+ (0, undo_stack_1.pushTransactionToUndoStack)({
60
+ snapshots: result.changes.map((change) => ({
61
+ filePath: change.filePath,
62
+ oldContents: change.previousContents,
63
+ newContents: change.nextContents,
64
+ logLine: change.filePath === filePath ? logLine : 1,
65
+ nodePathRemappings: null,
66
+ })),
67
+ logLevel,
68
+ remotionRoot,
69
+ description: {
70
+ undoMessage: `↩️ Creation of folder "${folderPath}"`,
71
+ redoMessage: `↪️ Creation of folder "${folderPath}"`,
72
+ },
73
+ entryType: 'new-folder',
74
+ suppressHmrOnFileRestore: false,
75
+ undoRedoNavigation: request.undoRedoNavigation,
76
+ });
77
+ for (const change of result.changes) {
78
+ if (change.nextContents === null) {
79
+ throw new Error('Adding a folder cannot remove source files');
80
+ }
81
+ (0, undo_stack_1.suppressUndoStackInvalidation)(change.filePath);
82
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
83
+ file: change.filePath,
84
+ content: change.nextContents,
85
+ originatorClientId: undefined,
86
+ metadata: null,
87
+ });
88
+ }
89
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
90
+ remotionRoot,
91
+ absolutePath: filePath,
92
+ line: logLine,
93
+ });
94
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(locationLabel)} Created folder "${folderPath}"`);
95
+ (0, undo_stack_1.printUndoHint)(logLevel);
96
+ }
97
+ return { success: true, nodePathMutation: null };
98
+ }
99
+ catch (error) {
100
+ return {
101
+ success: false,
102
+ reason: error instanceof Error ? error.message : String(error),
103
+ stack: error instanceof Error ? ((_d = error.stack) !== null && _d !== void 0 ? _d : '') : '',
104
+ };
105
+ }
106
+ });
107
+ exports.addFolderHandler = addFolderHandler;
@@ -1,7 +1,7 @@
1
- import type { AddKeyframesRequest, AddKeyframesResponse } from '@remotion/studio-shared';
1
+ import type { AddKeyframesRequest, AddKeyframesResponse, SequenceNodePathMutation } from '@remotion/studio-shared';
2
2
  import type { ApiHandler } from '../api-types';
3
3
  export declare const addKeyframes: ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }: AddKeyframesRequest & {
4
4
  readonly remotionRoot: string;
5
5
  readonly logLevel: "error" | "info" | "trace" | "verbose" | "warn";
6
- }) => Promise<void>;
6
+ }) => Promise<SequenceNodePathMutation | null>;
7
7
  export declare const addKeyframesHandler: ApiHandler<AddKeyframesRequest, AddKeyframesResponse>;
@@ -3,9 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addKeyframesHandler = exports.addKeyframes = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const renderer_1 = require("@remotion/renderer");
6
+ const get_node_path_remappings_1 = require("../../codemods/get-node-path-remappings");
7
+ const parse_ast_1 = require("../../codemods/parse-ast");
6
8
  const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
7
9
  const file_watcher_1 = require("../../file-watcher");
8
10
  const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
11
+ const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
9
12
  const undo_stack_1 = require("../undo-stack");
10
13
  const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
11
14
  const log_effect_update_1 = require("./log-updates/log-effect-update");
@@ -86,6 +89,20 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
86
89
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
87
90
  let output = fileContents;
88
91
  let firstLogLine = Number.POSITIVE_INFINITY;
92
+ const originalNodes = (0, get_node_path_remappings_1.captureJsxNodePaths)((0, parse_ast_1.parseAst)(fileContents));
93
+ // Keyframe codemods may wrap a concise arrow in a return statement.
94
+ // JSX nodes remain in order, but their node paths can all change.
95
+ const currentPathFor = (originalPath) => {
96
+ const index = originalNodes.findIndex(({ nodePath }) => JSON.stringify(nodePath) === JSON.stringify(originalPath));
97
+ if (index === -1) {
98
+ throw new Error('Could not find the original JSX node for keyframing');
99
+ }
100
+ const currentNodes = (0, get_node_path_remappings_1.captureJsxNodePaths)((0, parse_ast_1.parseAst)(output));
101
+ if (currentNodes.length !== originalNodes.length) {
102
+ throw new Error('Could not remap JSX nodes after keyframing');
103
+ }
104
+ return currentNodes[index].nodePath;
105
+ };
89
106
  for (const keyframeGroup of groupBy(group.sequenceKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
90
107
  const [firstSequenceKeyframe] = keyframeGroup;
91
108
  if (!firstSequenceKeyframe) {
@@ -93,7 +110,7 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
93
110
  }
94
111
  const result = await (0, update_keyframes_1.updateSequenceKeyframes)({
95
112
  input: output,
96
- nodePath: firstSequenceKeyframe.nodePath.nodePath,
113
+ nodePath: currentPathFor(firstSequenceKeyframe.nodePath.nodePath),
97
114
  schema: firstSequenceKeyframe.schema,
98
115
  videoConfigValues: firstSequenceKeyframe.nodePath.videoConfigValues,
99
116
  updates: keyframeGroup.map((keyframe) => ({
@@ -125,7 +142,7 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
125
142
  }
126
143
  const result = await (0, update_keyframes_1.updateEffectKeyframes)({
127
144
  input: output,
128
- sequenceNodePath: firstEffectKeyframe.sequenceNodePath.nodePath,
145
+ sequenceNodePath: currentPathFor(firstEffectKeyframe.sequenceNodePath.nodePath),
129
146
  effectIndex: firstEffectKeyframe.effectIndex,
130
147
  schema: firstEffectKeyframe.schema,
131
148
  videoConfigValues: firstEffectKeyframe.sequenceNodePath.videoConfigValues,
@@ -152,21 +169,39 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
152
169
  });
153
170
  }
154
171
  }
172
+ const finalNodes = (0, get_node_path_remappings_1.captureJsxNodePaths)((0, parse_ast_1.parseAst)(output));
173
+ if (finalNodes.length !== originalNodes.length) {
174
+ throw new Error('Could not remap JSX nodes after keyframing');
175
+ }
155
176
  snapshots.push({
156
177
  filePath: absolutePath,
157
178
  oldContents: fileContents,
158
179
  newContents: output,
159
180
  logLine: Number.isFinite(firstLogLine) ? firstLogLine : 1,
181
+ nodePathRemappings: originalNodes.flatMap(({ nodePath }, index) => {
182
+ const newNodePath = finalNodes[index].nodePath;
183
+ return JSON.stringify(nodePath) === JSON.stringify(newNodePath)
184
+ ? []
185
+ : [{ oldNodePath: nodePath, newNodePath }];
186
+ }),
160
187
  });
161
188
  }
162
189
  const [firstKeyframe] = sequenceKeyframes.length > 0 ? sequenceKeyframes : effectKeyframes;
163
190
  if (!firstKeyframe) {
164
191
  throw new Error('No keyframes were specified for adding');
165
192
  }
193
+ const filesWithRemappings = snapshots
194
+ .filter((snapshot) => snapshot.nodePathRemappings.length > 0)
195
+ .map((snapshot) => ({
196
+ absolutePath: snapshot.filePath,
197
+ remappings: snapshot.nodePathRemappings,
198
+ }));
166
199
  (0, undo_stack_1.pushTransactionToUndoStack)({
167
200
  snapshots: snapshots.map((snapshot) => ({
168
201
  ...snapshot,
169
- nodePathRemappings: null,
202
+ nodePathRemappings: snapshot.nodePathRemappings.length
203
+ ? snapshot.nodePathRemappings
204
+ : null,
170
205
  })),
171
206
  logLevel,
172
207
  remotionRoot,
@@ -181,6 +216,8 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
181
216
  suppressHmrOnFileRestore: true,
182
217
  undoRedoNavigation: null,
183
218
  });
219
+ // Visual Mode evaluates keyframes from prop statuses. Remap and refresh the
220
+ // subscriptions instead of remounting the composition when a hook is added.
184
221
  for (const snapshot of snapshots) {
185
222
  (0, undo_stack_1.suppressUndoStackInvalidation)(snapshot.filePath);
186
223
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
@@ -188,9 +225,14 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
188
225
  file: snapshot.filePath,
189
226
  content: snapshot.newContents,
190
227
  originatorClientId: clientId,
191
- metadata: null,
228
+ metadata: snapshot.nodePathRemappings.length
229
+ ? { skipSequencePropsUpdate: true }
230
+ : null,
192
231
  });
193
232
  }
233
+ const nodePathMutation = filesWithRemappings.length
234
+ ? (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(filesWithRemappings, null)
235
+ : null;
194
236
  for (const log of sequenceLogs) {
195
237
  (0, log_update_1.logUpdate)({
196
238
  fileRelativeToRoot: log.fileRelativeToRoot,
@@ -221,17 +263,18 @@ const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remo
221
263
  });
222
264
  }
223
265
  (0, undo_stack_1.printUndoHint)(logLevel);
266
+ return nodePathMutation;
224
267
  };
225
268
  exports.addKeyframes = addKeyframes;
226
269
  const addKeyframesHandler = ({ input: { sequenceKeyframes, effectKeyframes, clientId }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
227
270
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[add-keyframes] Received request to add ${sequenceKeyframes.length + effectKeyframes.length} keyframe(s)`);
228
- await (0, exports.addKeyframes)({
271
+ const nodePathMutation = await (0, exports.addKeyframes)({
229
272
  sequenceKeyframes,
230
273
  effectKeyframes,
231
274
  clientId,
232
275
  remotionRoot,
233
276
  logLevel,
234
277
  });
235
- return { success: true };
278
+ return { success: true, nodePathMutation };
236
279
  });
237
280
  exports.addKeyframesHandler = addKeyframesHandler;
@@ -314,7 +314,9 @@ const getInterpolationMetadata = (interpolationFunction, callExpression, keyfram
314
314
  return null;
315
315
  }
316
316
  const extrapolateType = getExtrapolateType(value);
317
- if (!extrapolateType) {
317
+ if (!extrapolateType ||
318
+ (interpolationFunction === 'interpolatePaths' &&
319
+ extrapolateType === 'identity')) {
318
320
  return null;
319
321
  }
320
322
  clamping =
@@ -334,7 +336,7 @@ const getInterpolationMetadata = (interpolationFunction, callExpression, keyfram
334
336
  continue;
335
337
  }
336
338
  if (key === 'output') {
337
- if (interpolationFunction === 'interpolateColors') {
339
+ if (interpolationFunction !== 'interpolate') {
338
340
  return null;
339
341
  }
340
342
  const parsedOutput = getInterpolateOutputOption(value);
@@ -345,7 +347,7 @@ const getInterpolationMetadata = (interpolationFunction, callExpression, keyfram
345
347
  continue;
346
348
  }
347
349
  if (key === 'outputType') {
348
- if (interpolationFunction === 'interpolateColors' ||
350
+ if (interpolationFunction !== 'interpolate' ||
349
351
  getInterpolateOutputType(value) === null) {
350
352
  return null;
351
353
  }
@@ -387,11 +389,16 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
387
389
  return undefined;
388
390
  }
389
391
  const callExpression = node;
390
- if (callExpression.callee.type !== 'Identifier' ||
391
- !(0, studio_shared_1.isKeyframeInterpolationFunction)(callExpression.callee.name)) {
392
+ if (callExpression.callee.type !== 'Identifier') {
393
+ return undefined;
394
+ }
395
+ const interpolationFunction = codemods_1.CodemodsInternals.getKeyframeInterpolationFunctionForCallee({
396
+ ast,
397
+ callee: callExpression.callee,
398
+ });
399
+ if (interpolationFunction === null) {
392
400
  return undefined;
393
401
  }
394
- const interpolationFunction = callExpression.callee.name;
395
402
  const frameArg = callExpression.arguments[0];
396
403
  const inputArg = callExpression.arguments[1];
397
404
  const outputArg = callExpression.arguments[2];
@@ -451,6 +458,7 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
451
458
  clamping: metadata.clamping,
452
459
  posterize: metadata.posterize,
453
460
  output: metadata.output,
461
+ keyframePlaybackRateAdjustment: frameDisplayOffset.playbackRateAdjustment,
454
462
  keyframeDisplayOffsetAdjustment: frameDisplayOffset.hasEnclosingElement
455
463
  ? frameDisplayOffset.adjustment
456
464
  : null,
@@ -541,6 +549,7 @@ const getFrameDisplayOffsetAdjustmentBetweenPaths = ({ startPath, endPath, video
541
549
  let hasSeenControlledElement = false;
542
550
  let hasEnclosingElement = false;
543
551
  let adjustment = 0;
552
+ let playbackRateAdjustment = 1;
544
553
  while (current && current.value !== endPath.value) {
545
554
  const currentNode = current.value;
546
555
  if (currentNode.type === 'FunctionDeclaration' ||
@@ -568,15 +577,30 @@ const getFrameDisplayOffsetAdjustmentBetweenPaths = ({ startPath, endPath, video
568
577
  defaultValue: 0,
569
578
  videoConfigValues,
570
579
  });
571
- if (from === null || trimBefore === null) {
580
+ const playbackRate = getJsxNumericAttribute({
581
+ openingElement: currentNode.openingElement,
582
+ name: 'playbackRate',
583
+ defaultValue: 1,
584
+ videoConfigValues,
585
+ });
586
+ if (from === null ||
587
+ trimBefore === null ||
588
+ playbackRate === null ||
589
+ !Number.isFinite(playbackRate) ||
590
+ playbackRate <= 0) {
572
591
  return null;
573
592
  }
574
- adjustment -= from - trimBefore;
593
+ // Walk from the controlled element back to the hook's scope.
594
+ // A sequence maps parent time to (parent - from) * rate + trimBefore.
595
+ adjustment = (adjustment + trimBefore) / playbackRate - from;
596
+ playbackRateAdjustment /= playbackRate;
575
597
  }
576
598
  }
577
599
  current = current.parentPath;
578
600
  }
579
- return current ? { adjustment, hasEnclosingElement } : null;
601
+ return current
602
+ ? { adjustment, playbackRateAdjustment, hasEnclosingElement }
603
+ : null;
580
604
  };
581
605
  const resolveCurrentFrameExpression = ({ node, ast, seenDeclarations, }) => {
582
606
  var _a;
@@ -716,6 +740,11 @@ const getComputedStatus = (node, ast, videoConfigValues) => {
716
740
  status: 'keyframed',
717
741
  interpolationFunction: interpolation.interpolationFunction,
718
742
  keyframeDisplayOffsetAdjustment: interpolation.keyframeDisplayOffsetAdjustment,
743
+ ...(interpolation.keyframePlaybackRateAdjustment === 1
744
+ ? {}
745
+ : {
746
+ keyframePlaybackRateAdjustment: interpolation.keyframePlaybackRateAdjustment,
747
+ }),
719
748
  keyframes: interpolation.keyframes,
720
749
  easing: interpolation.easing,
721
750
  clamping: interpolation.clamping,
@@ -927,7 +956,7 @@ const resolveSequencePropsNodePathsFromFilename = ({ fileName, targets, remotion
927
956
  action: 'read',
928
957
  });
929
958
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
930
- const nodes = (0, codemods_1.getJsxNodes)({
959
+ const nodes = (0, codemods_1.getNodes)({
931
960
  project: { rootDir: remotionRoot, files: { [absolutePath]: fileContents } },
932
961
  filePath: absolutePath,
933
962
  });
@@ -948,7 +977,7 @@ const resolveSequencePropsNodePathsFromFilename = ({ fileName, targets, remotion
948
977
  exports.resolveSequencePropsNodePathsFromFilename = resolveSequencePropsNodePathsFromFilename;
949
978
  const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
950
979
  try {
951
- return (0, codemods_1.getJsxNodeProps)({
980
+ return (0, codemods_1.getNodeProps)({
952
981
  project: { rootDir: '/', files: { 'source.tsx': fileContents } },
953
982
  node: { filePath: 'source.tsx', nodePath },
954
983
  componentIdentity,
@@ -0,0 +1,3 @@
1
+ import type { CompositionEditResponse, DeleteCompositionRequest } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const deleteCompositionHandler: ApiHandler<DeleteCompositionRequest, CompositionEditResponse>;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deleteCompositionHandler = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const codemods_1 = require("@remotion/codemods");
10
+ const renderer_1 = require("@remotion/renderer");
11
+ const file_watcher_1 = require("../../file-watcher");
12
+ const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
13
+ const format_log_file_location_1 = require("../format-log-file-location");
14
+ const project_info_1 = require("../project-info");
15
+ const undo_stack_1 = require("../undo-stack");
16
+ const can_update_default_props_1 = require("./can-update-default-props");
17
+ const source_file_write_queue_1 = require("./source-file-write-queue");
18
+ const deleteCompositionHandler = ({ input: request, logLevel, remotionRoot, entryPoint }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
19
+ var _a, _b;
20
+ var _c, _d;
21
+ try {
22
+ let filePath;
23
+ if ((_a = request.symbolicatedStack) === null || _a === void 0 ? void 0 : _a.originalFileName) {
24
+ filePath = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
25
+ remotionRoot,
26
+ fileName: request.symbolicatedStack.originalFileName,
27
+ action: 'delete a composition from',
28
+ }).absolutePath;
29
+ }
30
+ else {
31
+ const { rootFile } = await (0, project_info_1.getProjectInfo)(remotionRoot, entryPoint);
32
+ if (rootFile === null) {
33
+ throw new Error('Cannot find the Remotion root file');
34
+ }
35
+ filePath = rootFile;
36
+ }
37
+ (0, can_update_default_props_1.checkIfTypeScriptFile)(filePath);
38
+ const result = (0, codemods_1.deleteComposition)({
39
+ project: {
40
+ files: { [filePath]: (0, node_fs_1.readFileSync)(filePath, 'utf-8') },
41
+ rootDir: node_path_1.default.dirname(filePath),
42
+ },
43
+ compositionFile: filePath,
44
+ compositionId: request.idToDelete,
45
+ });
46
+ for (const change of result.changes) {
47
+ const currentContents = (0, node_fs_1.existsSync)(change.filePath)
48
+ ? (0, node_fs_1.readFileSync)(change.filePath, 'utf-8')
49
+ : null;
50
+ if (currentContents !== change.previousContents) {
51
+ throw new Error(`Source changed before deleting composition: ${change.filePath}`);
52
+ }
53
+ }
54
+ if (result.changes.length > 0) {
55
+ const logLine = (_c = (_b = request.symbolicatedStack) === null || _b === void 0 ? void 0 : _b.originalLineNumber) !== null && _c !== void 0 ? _c : 1;
56
+ (0, undo_stack_1.pushTransactionToUndoStack)({
57
+ snapshots: result.changes.map((change) => ({
58
+ filePath: change.filePath,
59
+ oldContents: change.previousContents,
60
+ newContents: change.nextContents,
61
+ logLine: change.filePath === filePath ? logLine : 1,
62
+ nodePathRemappings: null,
63
+ })),
64
+ logLevel,
65
+ remotionRoot,
66
+ description: {
67
+ undoMessage: `↩️ Deletion of composition "${request.idToDelete}"`,
68
+ redoMessage: `↪️ Deletion of composition "${request.idToDelete}"`,
69
+ },
70
+ entryType: 'delete-composition',
71
+ suppressHmrOnFileRestore: false,
72
+ undoRedoNavigation: request.undoRedoNavigation,
73
+ });
74
+ for (const change of result.changes) {
75
+ if (change.nextContents === null) {
76
+ throw new Error('Deleting a composition cannot remove source files');
77
+ }
78
+ (0, undo_stack_1.suppressUndoStackInvalidation)(change.filePath);
79
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
80
+ file: change.filePath,
81
+ content: change.nextContents,
82
+ originatorClientId: undefined,
83
+ metadata: null,
84
+ });
85
+ }
86
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
87
+ remotionRoot,
88
+ absolutePath: filePath,
89
+ line: logLine,
90
+ });
91
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(locationLabel)} Deleted composition "${request.idToDelete}"`);
92
+ (0, undo_stack_1.printUndoHint)(logLevel);
93
+ }
94
+ return { success: true, nodePathMutation: null };
95
+ }
96
+ catch (error) {
97
+ return {
98
+ success: false,
99
+ reason: error instanceof Error ? error.message : String(error),
100
+ stack: error instanceof Error ? ((_d = error.stack) !== null && _d !== void 0 ? _d : '') : '',
101
+ };
102
+ }
103
+ });
104
+ exports.deleteCompositionHandler = deleteCompositionHandler;
@@ -0,0 +1,3 @@
1
+ import type { DeleteNodesRequest, DeleteNodesResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const deleteNodesHandler: ApiHandler<DeleteNodesRequest, DeleteNodesResponse>;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteNodesHandler = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const codemods_1 = require("@remotion/codemods");
6
+ const renderer_1 = require("@remotion/renderer");
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 hmr_timing_1 = require("../hmr-timing");
11
+ const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
12
+ const undo_stack_1 = require("../undo-stack");
13
+ const source_file_write_queue_1 = require("./source-file-write-queue");
14
+ const getDeletedNodeDescription = (nodeLabels) => {
15
+ if (nodeLabels.length === 1) {
16
+ return nodeLabels[0];
17
+ }
18
+ return `${nodeLabels.length} JSX nodes`;
19
+ };
20
+ const deleteNodesHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
21
+ return (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
22
+ var _a;
23
+ try {
24
+ (0, hmr_timing_1.logHmrTiming)({
25
+ detail: null,
26
+ logLevel,
27
+ stage: 'delete-nodes-request-start',
28
+ });
29
+ if (nodes.length === 0) {
30
+ throw new Error('No JSX nodes were specified for deletion');
31
+ }
32
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[delete-nodes] Received request to delete ${nodes.length} JSX node${nodes.length === 1 ? '' : 's'}`);
33
+ const itemsByFileName = new Map();
34
+ for (const item of nodes) {
35
+ const fileItems = (_a = itemsByFileName.get(item.fileName)) !== null && _a !== void 0 ? _a : [];
36
+ fileItems.push(item);
37
+ itemsByFileName.set(item.fileName, fileItems);
38
+ }
39
+ const updates = await Promise.all([...itemsByFileName.entries()].map(async ([fileName, fileItems]) => {
40
+ var _a;
41
+ var _b;
42
+ const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
43
+ remotionRoot,
44
+ fileName,
45
+ action: 'modify',
46
+ });
47
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
48
+ const result = await (0, codemods_1.deleteNodes)({
49
+ project: {
50
+ files: { [absolutePath]: fileContents },
51
+ rootDir: remotionRoot,
52
+ },
53
+ nodes: fileItems.map((item) => ({
54
+ filePath: absolutePath,
55
+ nodePath: item.nodePath,
56
+ })),
57
+ });
58
+ const output = (_b = (_a = result.changes[0]) === null || _a === void 0 ? void 0 : _a.nextContents) !== null && _b !== void 0 ? _b : fileContents;
59
+ const { nodeLabels, logLines } = result.editDetails[0];
60
+ const nodePathRemappings = result.nodePathRemappings.map(({ oldNodePath, newNodePath, oldJsxName, newJsxName }) => ({
61
+ oldNodePath,
62
+ newNodePath,
63
+ oldJsxName,
64
+ newJsxName,
65
+ }));
66
+ return {
67
+ absolutePath,
68
+ fileRelativeToRoot,
69
+ fileContents,
70
+ output,
71
+ nodeLabels,
72
+ nodePathRemappings,
73
+ logLine: Math.min(...logLines),
74
+ };
75
+ }));
76
+ (0, hmr_timing_1.logHmrTiming)({
77
+ detail: `files=${updates.length}`,
78
+ logLevel,
79
+ stage: 'delete-nodes-codemod-complete',
80
+ });
81
+ const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
82
+ absolutePath: update.absolutePath,
83
+ remappings: update.nodePathRemappings,
84
+ })), null);
85
+ for (const update of updates) {
86
+ const deletedNodeDescription = getDeletedNodeDescription(update.nodeLabels);
87
+ (0, undo_stack_1.pushToUndoStack)({
88
+ filePath: update.absolutePath,
89
+ oldContents: update.fileContents,
90
+ newContents: null,
91
+ logLevel,
92
+ remotionRoot,
93
+ logLine: update.logLine,
94
+ description: {
95
+ undoMessage: `↩️ Deletion of ${deletedNodeDescription}`,
96
+ redoMessage: `↪️ Deletion of ${deletedNodeDescription}`,
97
+ },
98
+ entryType: 'delete-nodes',
99
+ suppressHmrOnFileRestore: false,
100
+ nodePathRemappings: update.nodePathRemappings,
101
+ });
102
+ (0, undo_stack_1.suppressUndoStackInvalidation)(update.absolutePath);
103
+ (0, hmr_timing_1.logHmrTiming)({
104
+ detail: `file=${update.fileRelativeToRoot}`,
105
+ logLevel,
106
+ stage: 'source-file-write-start',
107
+ });
108
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
109
+ file: update.absolutePath,
110
+ content: update.output,
111
+ originatorClientId: undefined,
112
+ metadata: { skipSequencePropsUpdate: true },
113
+ });
114
+ (0, hmr_timing_1.logHmrTiming)({
115
+ detail: `file=${update.fileRelativeToRoot}`,
116
+ logLevel,
117
+ stage: 'source-file-write-complete',
118
+ });
119
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
120
+ remotionRoot,
121
+ absolutePath: update.absolutePath,
122
+ line: update.logLine,
123
+ });
124
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Deleted ${deletedNodeDescription}`);
125
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[delete-nodes] Wrote ${update.fileRelativeToRoot}`);
126
+ }
127
+ (0, undo_stack_1.printUndoHint)(logLevel);
128
+ return {
129
+ success: true,
130
+ nodePathMutation,
131
+ };
132
+ }
133
+ catch (err) {
134
+ return {
135
+ success: false,
136
+ reason: err.message,
137
+ stack: err.stack,
138
+ };
139
+ }
140
+ });
141
+ };
142
+ exports.deleteNodesHandler = deleteNodesHandler;
@@ -0,0 +1,3 @@
1
+ import type { CompositionEditResponse, DuplicateCompositionRequest } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const duplicateCompositionHandler: ApiHandler<DuplicateCompositionRequest, CompositionEditResponse>;