@remotion/studio-server 4.0.472 → 4.0.474

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 (35) hide show
  1. package/dist/codemods/effect-param-expression.d.ts +15 -0
  2. package/dist/codemods/effect-param-expression.js +131 -0
  3. package/dist/codemods/paste-effects.js +4 -91
  4. package/dist/codemods/reorder-sequence.d.ts +14 -0
  5. package/dist/codemods/reorder-sequence.js +109 -0
  6. package/dist/codemods/update-effect-props/update-effect-props.d.ts +7 -0
  7. package/dist/codemods/update-effect-props/update-effect-props.js +64 -16
  8. package/dist/codemods/update-keyframes/update-keyframes.d.ts +14 -1
  9. package/dist/codemods/update-keyframes/update-keyframes.js +152 -0
  10. package/dist/helpers/resolve-composition-component.d.ts +1 -1
  11. package/dist/helpers/resolve-composition-component.js +103 -7
  12. package/dist/preview-server/api-routes.js +14 -0
  13. package/dist/preview-server/routes/can-update-effect-props.js +3 -2
  14. package/dist/preview-server/routes/can-update-sequence-props.d.ts +1 -1
  15. package/dist/preview-server/routes/can-update-sequence-props.js +52 -17
  16. package/dist/preview-server/routes/download-remote-asset.d.ts +7 -0
  17. package/dist/preview-server/routes/download-remote-asset.js +268 -0
  18. package/dist/preview-server/routes/insert-jsx-element.d.ts +1 -1
  19. package/dist/preview-server/routes/insert-jsx-element.js +28 -1
  20. package/dist/preview-server/routes/log-studio-error.d.ts +3 -0
  21. package/dist/preview-server/routes/log-studio-error.js +58 -0
  22. package/dist/preview-server/routes/move-keyframes.d.ts +7 -0
  23. package/dist/preview-server/routes/move-keyframes.js +242 -0
  24. package/dist/preview-server/routes/rename-static-file.d.ts +3 -0
  25. package/dist/preview-server/routes/rename-static-file.js +53 -0
  26. package/dist/preview-server/routes/reorder-sequence.d.ts +3 -0
  27. package/dist/preview-server/routes/reorder-sequence.js +67 -0
  28. package/dist/preview-server/routes/save-effect-props.js +24 -9
  29. package/dist/preview-server/routes/save-sequence-props.js +2 -34
  30. package/dist/preview-server/routes/update-effect-keyframe-settings.d.ts +3 -0
  31. package/dist/preview-server/routes/update-effect-keyframe-settings.js +90 -0
  32. package/dist/preview-server/routes/update-sequence-keyframe-settings.d.ts +3 -0
  33. package/dist/preview-server/routes/update-sequence-keyframe-settings.js +85 -0
  34. package/dist/preview-server/undo-stack.d.ts +3 -1
  35. package/package.json +6 -6
@@ -141,6 +141,92 @@ const createClampOptionsExpression = () => {
141
141
  b.objectProperty(b.identifier('extrapolateRight'), b.stringLiteral('clamp')),
142
142
  ]);
143
143
  };
144
+ const createEmptyOptionsExpression = () => b.objectExpression([]);
145
+ const findObjectOptionProperty = (options, propertyName) => {
146
+ const propIndex = options.properties.findIndex((prop) => prop.type === 'ObjectProperty' &&
147
+ !prop.computed &&
148
+ ((prop.key.type === 'Identifier' && prop.key.name === propertyName) ||
149
+ (prop.key.type === 'StringLiteral' && prop.key.value === propertyName)));
150
+ return {
151
+ propIndex,
152
+ prop: propIndex === -1
153
+ ? undefined
154
+ : options.properties[propIndex],
155
+ };
156
+ };
157
+ const setOptionsProperty = ({ options, propertyName, value, }) => {
158
+ const { propIndex, prop } = findObjectOptionProperty(options, propertyName);
159
+ if (value === null) {
160
+ if (propIndex !== -1) {
161
+ options.properties.splice(propIndex, 1);
162
+ }
163
+ return;
164
+ }
165
+ if (prop) {
166
+ prop.value = value;
167
+ return;
168
+ }
169
+ options.properties.push(b.objectProperty(b.identifier(propertyName), value));
170
+ };
171
+ const validatePosterize = (posterize) => {
172
+ if (posterize === undefined) {
173
+ return;
174
+ }
175
+ if (!Number.isFinite(posterize) || posterize <= 0) {
176
+ throw new Error('Cannot update keyframe settings: posterize must be > 0');
177
+ }
178
+ };
179
+ const updateKeyframeSettings = ({ expression, clamping, posterize, }) => {
180
+ validatePosterize(posterize);
181
+ const existing = getInterpolationExpression(expression);
182
+ if (!existing) {
183
+ throw new Error('Cannot update keyframe settings on non-keyframed value');
184
+ }
185
+ const calleeName = existing.callee.type === 'Identifier' ? existing.callee.name : null;
186
+ const isColorInterpolation = calleeName === 'interpolateColors';
187
+ const extraArgs = [...existing.extraArgs];
188
+ const existingOptions = extraArgs[0];
189
+ if (existingOptions && existingOptions.type !== 'ObjectExpression') {
190
+ throw new Error('Cannot update keyframe settings: options must be inline');
191
+ }
192
+ const options = (existingOptions === null || existingOptions === void 0 ? void 0 : existingOptions.type) === 'ObjectExpression'
193
+ ? existingOptions
194
+ : createEmptyOptionsExpression();
195
+ if (isColorInterpolation) {
196
+ setOptionsProperty({ options, propertyName: 'extrapolateLeft', value: null });
197
+ setOptionsProperty({
198
+ options,
199
+ propertyName: 'extrapolateRight',
200
+ value: null,
201
+ });
202
+ }
203
+ else if (clamping) {
204
+ setOptionsProperty({
205
+ options,
206
+ propertyName: 'extrapolateLeft',
207
+ value: b.stringLiteral(clamping.left),
208
+ });
209
+ setOptionsProperty({
210
+ options,
211
+ propertyName: 'extrapolateRight',
212
+ value: b.stringLiteral(clamping.right),
213
+ });
214
+ }
215
+ setOptionsProperty({
216
+ options,
217
+ propertyName: 'posterize',
218
+ value: posterize === undefined ? null : b.numericLiteral(posterize),
219
+ });
220
+ const nextExtraArgs = options.properties.length === 0
221
+ ? extraArgs.slice(1)
222
+ : [options, ...extraArgs.slice(1)];
223
+ return createInterpolateExpression({
224
+ callee: existing.callee,
225
+ input: existing.input,
226
+ extraArgs: nextExtraArgs,
227
+ keyframes: existing.keyframes,
228
+ });
229
+ };
144
230
  const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) => {
145
231
  const sortedKeyframes = [...keyframes].sort((first, second) => first.frame - second.frame);
146
232
  return b.callExpression(callee, [
@@ -239,6 +325,56 @@ const removeKeyframe = ({ expression, frame, }) => {
239
325
  keyframes: nextKeyframes,
240
326
  });
241
327
  };
328
+ const moveKeyframes = ({ expression, moves, }) => {
329
+ var _a;
330
+ const existing = getInterpolationExpression(expression);
331
+ if (!existing) {
332
+ throw new Error('Cannot move keyframe in non-interpolated expression');
333
+ }
334
+ const moveMap = new Map();
335
+ for (const move of moves) {
336
+ if (move.fromFrame === move.toFrame) {
337
+ continue;
338
+ }
339
+ if (moveMap.has(move.fromFrame)) {
340
+ throw new Error(`Cannot move keyframe at frame ${move.fromFrame} twice`);
341
+ }
342
+ moveMap.set(move.fromFrame, move.toFrame);
343
+ }
344
+ if (moveMap.size === 0) {
345
+ return expression;
346
+ }
347
+ const frames = new Set(existing.keyframes.map((keyframe) => keyframe.frame));
348
+ for (const fromFrame of moveMap.keys()) {
349
+ if (!frames.has(fromFrame)) {
350
+ throw new Error(`Cannot move keyframe at frame ${fromFrame}: not found`);
351
+ }
352
+ }
353
+ const movedFromFrames = new Set(moveMap.keys());
354
+ const nextFrames = new Set();
355
+ for (const keyframe of existing.keyframes) {
356
+ const nextFrame = (_a = moveMap.get(keyframe.frame)) !== null && _a !== void 0 ? _a : keyframe.frame;
357
+ if (nextFrames.has(nextFrame)) {
358
+ throw new Error(`Cannot move keyframe to frame ${nextFrame}: frame already exists`);
359
+ }
360
+ if (!movedFromFrames.has(keyframe.frame) && moveMap.has(nextFrame)) {
361
+ throw new Error(`Cannot move keyframe to frame ${nextFrame}: frame already exists`);
362
+ }
363
+ nextFrames.add(nextFrame);
364
+ }
365
+ return createInterpolateExpression({
366
+ callee: existing.callee,
367
+ input: existing.input,
368
+ extraArgs: existing.extraArgs,
369
+ keyframes: existing.keyframes.map((keyframe) => {
370
+ var _a;
371
+ return ({
372
+ ...keyframe,
373
+ frame: (_a = moveMap.get(keyframe.frame)) !== null && _a !== void 0 ? _a : keyframe.frame,
374
+ });
375
+ }),
376
+ });
377
+ };
242
378
  const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
243
379
  if (operation.type === 'add') {
244
380
  return addKeyframe({
@@ -249,6 +385,22 @@ const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
249
385
  schema,
250
386
  });
251
387
  }
388
+ if (operation.type === 'settings') {
389
+ return {
390
+ expression: updateKeyframeSettings({
391
+ expression,
392
+ clamping: operation.clamping,
393
+ posterize: operation.posterize,
394
+ }),
395
+ introduced: noIntroducedIdentifiers,
396
+ };
397
+ }
398
+ if (operation.type === 'move') {
399
+ return {
400
+ expression: moveKeyframes({ expression, moves: operation.moves }),
401
+ introduced: noIntroducedIdentifiers,
402
+ };
403
+ }
252
404
  return {
253
405
  expression: removeKeyframe({ expression, frame: operation.frame }),
254
406
  introduced: noIntroducedIdentifiers,
@@ -1,4 +1,4 @@
1
- import type { InsertableCompositionElement } from '@remotion/studio-shared';
1
+ import { type InsertableCompositionElement } from '@remotion/studio-shared';
2
2
  export type ResolvedCompositionComponent = {
3
3
  source: string;
4
4
  line: number;
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
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
+ const studio_shared_1 = require("@remotion/studio-shared");
42
43
  const recast = __importStar(require("recast"));
43
44
  const format_file_content_1 = require("../codemods/format-file-content");
44
45
  const parse_ast_1 = require("../codemods/parse-ast");
@@ -508,6 +509,12 @@ const createSequenceElement = () => {
508
509
  const createNumberAttribute = (name, value) => {
509
510
  return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.jsxExpressionContainer(recast.types.builders.numericLiteral(value)));
510
511
  };
512
+ const createStringAttribute = (name, value) => {
513
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.stringLiteral(value));
514
+ };
515
+ const createBooleanAttribute = (name, value) => {
516
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.jsxExpressionContainer(recast.types.builders.booleanLiteral(value)));
517
+ };
511
518
  const createPositionAbsoluteStyleAttribute = () => {
512
519
  return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('style'), recast.types.builders.jsxExpressionContainer(recast.types.builders.objectExpression([
513
520
  recast.types.builders.objectProperty(recast.types.builders.identifier('position'), recast.types.builders.stringLiteral('absolute')),
@@ -516,6 +523,18 @@ const createPositionAbsoluteStyleAttribute = () => {
516
523
  const createStaticFileSrcAttribute = ({ staticFileLocalName, src, }) => {
517
524
  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
525
  };
526
+ const createComponentProp = ({ name, value, }) => {
527
+ if (typeof value === 'number') {
528
+ return createNumberAttribute(name, value);
529
+ }
530
+ if (typeof value === 'boolean') {
531
+ return createBooleanAttribute(name, value);
532
+ }
533
+ return createStringAttribute(name, value);
534
+ };
535
+ const createStringSrcAttribute = (src) => {
536
+ return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('src'), recast.types.builders.stringLiteral(src));
537
+ };
519
538
  const createSolidElement = ({ localName, width, height, }) => {
520
539
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
521
540
  createNumberAttribute('width', width),
@@ -523,9 +542,17 @@ const createSolidElement = ({ localName, width, height, }) => {
523
542
  createPositionAbsoluteStyleAttribute(),
524
543
  ], true), null, []);
525
544
  };
545
+ const createComponentElement = ({ localName, props, }) => {
546
+ return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
547
+ ...props.map(createComponentProp),
548
+ createPositionAbsoluteStyleAttribute(),
549
+ ], true), null, []);
550
+ };
526
551
  const createAssetElement = ({ localName, staticFileLocalName, src, dimensions, }) => {
527
552
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
528
- createStaticFileSrcAttribute({ staticFileLocalName, src }),
553
+ staticFileLocalName === null
554
+ ? createStringSrcAttribute(src)
555
+ : createStaticFileSrcAttribute({ staticFileLocalName, src }),
529
556
  createPositionAbsoluteStyleAttribute(),
530
557
  ...(dimensions
531
558
  ? [
@@ -709,6 +736,14 @@ const ensureVideoImport = (ast) => {
709
736
  label: '<Video>',
710
737
  });
711
738
  };
739
+ const ensureAudioImport = (ast) => {
740
+ return ensureOfficialNamedImport({
741
+ ast,
742
+ importedName: 'Audio',
743
+ sourcePath: '@remotion/media',
744
+ label: '<Audio>',
745
+ });
746
+ };
712
747
  const ensureGifImport = (ast) => {
713
748
  return ensureOfficialNamedImport({
714
749
  ast,
@@ -717,6 +752,41 @@ const ensureGifImport = (ast) => {
717
752
  label: '<Gif>',
718
753
  });
719
754
  };
755
+ const hasComponentLocalImport = ({ ast, importName, importPath, }) => {
756
+ var _a;
757
+ var _b, _c;
758
+ for (const importDeclaration of getImportDeclarations({
759
+ ast,
760
+ sourcePath: importPath,
761
+ })) {
762
+ for (const specifier of (_b = importDeclaration.specifiers) !== null && _b !== void 0 ? _b : []) {
763
+ if (specifier.type === 'ImportSpecifier' &&
764
+ (0, imports_1.getImportedName)(specifier) === importName) {
765
+ return (_c = (_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _c !== void 0 ? _c : importName;
766
+ }
767
+ }
768
+ }
769
+ return null;
770
+ };
771
+ const ensureComponentImport = ({ ast, componentName, importName, importPath, }) => {
772
+ const existingLocalName = hasComponentLocalImport({
773
+ ast,
774
+ importName,
775
+ importPath,
776
+ });
777
+ if (existingLocalName) {
778
+ return existingLocalName;
779
+ }
780
+ if (hasTopLevelBinding({ ast, name: componentName })) {
781
+ throw new Error(`Cannot add <${componentName}> because ${componentName} is already defined`);
782
+ }
783
+ return (0, imports_1.ensureNamedImport)({
784
+ ast,
785
+ importedName: importName,
786
+ sourcePath: importPath,
787
+ localName: componentName,
788
+ });
789
+ };
720
790
  const addElementToComponentRoot = ({ ast, exportName, element, }) => {
721
791
  var _a;
722
792
  var _b;
@@ -939,13 +1009,39 @@ const createInsertableJsxElement = ({ ast, element, }) => {
939
1009
  height: element.height,
940
1010
  });
941
1011
  }
1012
+ if (element.type === 'component') {
1013
+ const componentLocalName = ensureComponentImport({
1014
+ ast,
1015
+ componentName: element.componentName,
1016
+ importName: element.importName,
1017
+ importPath: element.importPath,
1018
+ });
1019
+ return createComponentElement({
1020
+ localName: componentLocalName,
1021
+ props: element.props,
1022
+ });
1023
+ }
942
1024
  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);
1025
+ if (element.srcType === 'remote' && !(0, studio_shared_1.isUrl)(element.src)) {
1026
+ throw new Error('Remote asset source must be a URL');
1027
+ }
1028
+ const staticFileLocalName = element.srcType === 'remote' ? null : ensureStaticFileImport(ast);
1029
+ let localName;
1030
+ if (element.assetType === 'image') {
1031
+ localName = ensureImgImport(ast);
1032
+ }
1033
+ else if (element.assetType === 'video') {
1034
+ localName = ensureVideoImport(ast);
1035
+ }
1036
+ else if (element.assetType === 'gif') {
1037
+ localName = ensureGifImport(ast);
1038
+ }
1039
+ else if (element.assetType === 'audio') {
1040
+ localName = ensureAudioImport(ast);
1041
+ }
1042
+ else {
1043
+ throw new Error('Unsupported asset type');
1044
+ }
949
1045
  return createAssetElement({
950
1046
  localName,
951
1047
  staticFileLocalName,
@@ -13,9 +13,12 @@ const delete_effect_1 = require("./routes/delete-effect");
13
13
  const delete_jsx_node_1 = require("./routes/delete-jsx-node");
14
14
  const delete_keyframes_1 = require("./routes/delete-keyframes");
15
15
  const delete_static_file_1 = require("./routes/delete-static-file");
16
+ const download_remote_asset_1 = require("./routes/download-remote-asset");
16
17
  const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
17
18
  const insert_jsx_element_1 = require("./routes/insert-jsx-element");
18
19
  const install_dependency_1 = require("./routes/install-dependency");
20
+ const log_studio_error_1 = require("./routes/log-studio-error");
21
+ const move_keyframes_1 = require("./routes/move-keyframes");
19
22
  const open_in_editor_1 = require("./routes/open-in-editor");
20
23
  const open_in_file_explorer_1 = require("./routes/open-in-file-explorer");
21
24
  const paste_effects_1 = require("./routes/paste-effects");
@@ -23,7 +26,9 @@ const project_info_1 = require("./routes/project-info");
23
26
  const redo_1 = require("./routes/redo");
24
27
  const register_client_render_1 = require("./routes/register-client-render");
25
28
  const remove_render_1 = require("./routes/remove-render");
29
+ const rename_static_file_1 = require("./routes/rename-static-file");
26
30
  const reorder_effect_1 = require("./routes/reorder-effect");
31
+ const reorder_sequence_1 = require("./routes/reorder-sequence");
27
32
  const restart_studio_1 = require("./routes/restart-studio");
28
33
  const save_effect_props_1 = require("./routes/save-effect-props");
29
34
  const save_sequence_props_1 = require("./routes/save-sequence-props");
@@ -37,6 +42,8 @@ const unsubscribe_from_file_existence_1 = require("./routes/unsubscribe-from-fil
37
42
  const unsubscribe_from_sequence_props_1 = require("./routes/unsubscribe-from-sequence-props");
38
43
  const update_available_1 = require("./routes/update-available");
39
44
  const update_default_props_1 = require("./routes/update-default-props");
45
+ const update_effect_keyframe_settings_1 = require("./routes/update-effect-keyframe-settings");
46
+ const update_sequence_keyframe_settings_1 = require("./routes/update-sequence-keyframe-settings");
40
47
  exports.allApiRoutes = {
41
48
  '/api/composition-component-info': composition_component_info_1.compositionComponentInfoHandler,
42
49
  '/api/cancel': cancel_render_1.handleCancelRender,
@@ -59,9 +66,13 @@ exports.allApiRoutes = {
59
66
  '/api/save-effect-props': save_effect_props_1.saveEffectPropsHandler,
60
67
  '/api/add-effect': add_effect_1.addEffectHandler,
61
68
  '/api/reorder-effect': reorder_effect_1.reorderEffectHandler,
69
+ '/api/reorder-sequence': reorder_sequence_1.reorderSequenceHandler,
62
70
  '/api/delete-keyframes': delete_keyframes_1.deleteKeyframesHandler,
71
+ '/api/move-keyframes': move_keyframes_1.moveKeyframesHandler,
63
72
  '/api/add-sequence-keyframe': add_sequence_keyframe_1.addSequenceKeyframeHandler,
64
73
  '/api/add-effect-keyframe': add_effect_keyframe_1.addEffectKeyframeHandler,
74
+ '/api/update-sequence-keyframe-settings': update_sequence_keyframe_settings_1.updateSequenceKeyframeSettingsHandler,
75
+ '/api/update-effect-keyframe-settings': update_effect_keyframe_settings_1.updateEffectKeyframeSettingsHandler,
65
76
  '/api/delete-effect': delete_effect_1.deleteEffectHandler,
66
77
  '/api/paste-effects': paste_effects_1.pasteEffectsHandler,
67
78
  '/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
@@ -69,9 +80,12 @@ exports.allApiRoutes = {
69
80
  '/api/update-available': update_available_1.handleUpdate,
70
81
  '/api/project-info': project_info_1.projectInfoHandler,
71
82
  '/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
83
+ '/api/rename-static-file': rename_static_file_1.renameStaticFileHandler,
72
84
  '/api/restart-studio': restart_studio_1.handleRestartStudio,
73
85
  '/api/install-package': install_dependency_1.handleInstallPackage,
74
86
  '/api/insert-jsx-element': insert_jsx_element_1.insertJsxElementHandler,
87
+ '/api/download-remote-asset': download_remote_asset_1.downloadRemoteAssetHandler,
75
88
  '/api/undo': undo_1.undoHandler,
76
89
  '/api/redo': redo_1.redoHandler,
90
+ '/api/log-studio-error': log_studio_error_1.logStudioErrorHandler,
77
91
  };
@@ -88,7 +88,7 @@ const resolveEffectImport = ({ ast, call, fallbackCallee, }) => {
88
88
  }
89
89
  return { callee: fallbackCallee, importPath: null };
90
90
  };
91
- const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
91
+ const getPropsFromObjectExpression = ({ ast, objExpr, keys, }) => {
92
92
  const out = {};
93
93
  for (const key of keys) {
94
94
  const prop = objExpr.properties.find((p) => p.type === 'ObjectProperty' &&
@@ -101,7 +101,7 @@ const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
101
101
  }
102
102
  const valueExpr = prop.value;
103
103
  if (!(0, can_update_sequence_props_1.isStaticValue)(valueExpr)) {
104
- out[key] = (0, can_update_sequence_props_1.getComputedStatus)(valueExpr);
104
+ out[key] = (0, can_update_sequence_props_1.getComputedStatus)(valueExpr, ast);
105
105
  continue;
106
106
  }
107
107
  out[key] = {
@@ -164,6 +164,7 @@ const computeEffectPropStatus = ({ ast, jsx, effectIndex, keys, }) => {
164
164
  };
165
165
  }
166
166
  const resolvedProps = getPropsFromObjectExpression({
167
+ ast,
167
168
  objExpr: firstArg,
168
169
  keys,
169
170
  });
@@ -3,7 +3,7 @@ import type { SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
3
3
  import type { CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, SequenceNodePath } from 'remotion';
4
4
  export declare const isStaticValue: (node: Expression) => boolean;
5
5
  export declare const extractStaticValue: (node: Expression) => unknown;
6
- export declare const getComputedStatus: (node: Expression) => CanUpdateSequencePropStatus;
6
+ export declare const getComputedStatus: (node: Expression, ast: File) => CanUpdateSequencePropStatus;
7
7
  export declare const findJsxElementAtNodePath: (ast: File, nodePath: SequenceNodePath) => JSXOpeningElement | null;
8
8
  export declare const findNodePathForJsxElement: (ast: File, target: JSXOpeningElement) => SequenceNodePath | null;
9
9
  export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
@@ -305,9 +305,9 @@ const getInterpolationMetadata = (interpolationFunction, callExpression, keyfram
305
305
  posterize,
306
306
  };
307
307
  };
308
- const getInterpolationKeyframes = (node) => {
308
+ const getInterpolationKeyframes = (node, ast) => {
309
309
  if (node.type === 'TSAsExpression') {
310
- return getInterpolationKeyframes(node.expression);
310
+ return getInterpolationKeyframes(node.expression, ast);
311
311
  }
312
312
  if (node.type !== 'CallExpression') {
313
313
  return undefined;
@@ -318,9 +318,13 @@ const getInterpolationKeyframes = (node) => {
318
318
  return undefined;
319
319
  }
320
320
  const interpolationFunction = callExpression.callee.name;
321
+ const frameArg = callExpression.arguments[0];
321
322
  const inputArg = callExpression.arguments[1];
322
323
  const outputArg = callExpression.arguments[2];
323
- if (!inputArg ||
324
+ if (!frameArg ||
325
+ frameArg.type === 'SpreadElement' ||
326
+ !isCurrentFrameIdentifier(frameArg, ast) ||
327
+ !inputArg ||
324
328
  !outputArg ||
325
329
  inputArg.type !== 'ArrayExpression' ||
326
330
  outputArg.type !== 'ArrayExpression') {
@@ -363,14 +367,45 @@ const getInterpolationKeyframes = (node) => {
363
367
  posterize: metadata.posterize,
364
368
  };
365
369
  };
366
- const getComputedStatus = (node) => {
367
- const interpolation = getInterpolationKeyframes(node);
370
+ const isUseCurrentFrameCall = (node) => {
371
+ return (node.type === 'CallExpression' &&
372
+ node.callee.type === 'Identifier' &&
373
+ node.callee.name === 'useCurrentFrame' &&
374
+ node.arguments.length === 0);
375
+ };
376
+ const isCurrentFrameIdentifier = (node, ast) => {
377
+ if (node.type === 'TSAsExpression') {
378
+ return isCurrentFrameIdentifier(node.expression, ast);
379
+ }
380
+ if (node.type !== 'Identifier') {
381
+ return false;
382
+ }
383
+ let hasUseCurrentFrameDeclaration = false;
384
+ let hasOtherDeclaration = false;
385
+ recast.types.visit(ast, {
386
+ visitVariableDeclarator(p) {
387
+ const { id, init } = p.node;
388
+ if (id.type !== 'Identifier' || id.name !== node.name) {
389
+ return this.traverse(p);
390
+ }
391
+ if (init && isUseCurrentFrameCall(init)) {
392
+ hasUseCurrentFrameDeclaration = true;
393
+ }
394
+ else {
395
+ hasOtherDeclaration = true;
396
+ }
397
+ return false;
398
+ },
399
+ });
400
+ return hasUseCurrentFrameDeclaration && !hasOtherDeclaration;
401
+ };
402
+ const getComputedStatus = (node, ast) => {
403
+ const interpolation = getInterpolationKeyframes(node, ast);
368
404
  if (!interpolation) {
369
405
  return computedStatus();
370
406
  }
371
407
  return {
372
408
  status: 'keyframed',
373
- codeValue: undefined,
374
409
  interpolationFunction: interpolation.interpolationFunction,
375
410
  keyframes: interpolation.keyframes,
376
411
  easing: interpolation.easing,
@@ -379,7 +414,7 @@ const getComputedStatus = (node) => {
379
414
  };
380
415
  };
381
416
  exports.getComputedStatus = getComputedStatus;
382
- const getPropsStatus = (jsxElement) => {
417
+ const getPropsStatus = (jsxElement, ast) => {
383
418
  const props = {};
384
419
  for (const attr of jsxElement.attributes) {
385
420
  if (attr.type === 'JSXSpreadAttribute') {
@@ -408,7 +443,7 @@ const getPropsStatus = (jsxElement) => {
408
443
  continue;
409
444
  }
410
445
  if (!(0, exports.isStaticValue)(expression)) {
411
- props[name] = (0, exports.getComputedStatus)(expression);
446
+ props[name] = (0, exports.getComputedStatus)(expression, ast);
412
447
  continue;
413
448
  }
414
449
  props[name] = staticStatus((0, exports.extractStaticValue)(expression));
@@ -488,7 +523,7 @@ const validateStyleValue = (childKey, value) => {
488
523
  }
489
524
  return true;
490
525
  };
491
- const getNestedPropStatus = (jsxElement, parentKey, childKey) => {
526
+ const getNestedPropStatus = (jsxElement, ast, parentKey, childKey) => {
492
527
  const attr = jsxElement.attributes.find((a) => a.type !== 'JSXSpreadAttribute' &&
493
528
  a.name.type !== 'JSXNamespacedName' &&
494
529
  a.name.name === parentKey);
@@ -515,13 +550,13 @@ const getNestedPropStatus = (jsxElement, parentKey, childKey) => {
515
550
  }
516
551
  const propValue = prop.value;
517
552
  if (!(0, exports.isStaticValue)(propValue)) {
518
- return (0, exports.getComputedStatus)(propValue);
553
+ return (0, exports.getComputedStatus)(propValue, ast);
519
554
  }
520
- const codeValue = (0, exports.extractStaticValue)(propValue);
521
- if (!validateStyleValue(childKey, codeValue)) {
555
+ const propStatus = (0, exports.extractStaticValue)(propValue);
556
+ if (!validateStyleValue(childKey, propStatus)) {
522
557
  return computedStatus();
523
558
  }
524
- return staticStatus(codeValue);
559
+ return staticStatus(propStatus);
525
560
  };
526
561
  const computeEffectsForJsx = ({ ast, jsxElement, effects, }) => {
527
562
  return effects.map((effect, effectIndex) => (0, can_update_effect_props_1.computeEffectPropStatus)({
@@ -531,13 +566,13 @@ const computeEffectsForJsx = ({ ast, jsxElement, effects, }) => {
531
566
  keys: effect,
532
567
  }));
533
568
  };
534
- const computeSequenceOnlyPropsRecord = ({ jsxElement, keys, }) => {
535
- const allProps = getPropsStatus(jsxElement);
569
+ const computeSequenceOnlyPropsRecord = ({ jsxElement, ast, keys, }) => {
570
+ const allProps = getPropsStatus(jsxElement, ast);
536
571
  const filteredProps = {};
537
572
  for (const key of keys) {
538
573
  const dotIndex = key.indexOf('.');
539
574
  if (dotIndex !== -1) {
540
- filteredProps[key] = getNestedPropStatus(jsxElement, key.slice(0, dotIndex), key.slice(dotIndex + 1));
575
+ filteredProps[key] = getNestedPropStatus(jsxElement, ast, key.slice(0, dotIndex), key.slice(dotIndex + 1));
541
576
  }
542
577
  else if (key in allProps) {
543
578
  filteredProps[key] = allProps[key];
@@ -554,7 +589,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, keys, e
554
589
  if (!jsxElement) {
555
590
  throw new jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError();
556
591
  }
557
- const filteredProps = computeSequenceOnlyPropsRecord({ jsxElement, keys });
592
+ const filteredProps = computeSequenceOnlyPropsRecord({ jsxElement, ast, keys });
558
593
  const effectsStatuses = computeEffectsForJsx({ ast, jsxElement, effects });
559
594
  return {
560
595
  canUpdate: true,
@@ -0,0 +1,7 @@
1
+ import { type DownloadRemoteAssetRequest, type DownloadRemoteAssetResponse, type ImageFileType } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const getRemoteAssetFilename: ({ fileType, url, }: {
4
+ fileType: ImageFileType;
5
+ url: URL;
6
+ }) => string;
7
+ export declare const downloadRemoteAssetHandler: ApiHandler<DownloadRemoteAssetRequest, DownloadRemoteAssetResponse>;