@remotion/studio-server 4.0.474 → 4.0.476

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.
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.parseAndApplyCodemod = exports.formatOutput = void 0;
37
+ const imports_1 = require("../helpers/imports");
37
38
  const parse_ast_1 = require("./parse-ast");
38
39
  const recast_mods_1 = require("./recast-mods");
39
40
  const getPrettier = async () => {
@@ -71,6 +72,14 @@ const parseAndApplyCodemod = ({ input, codeMod, }) => {
71
72
  if (changesMade.length === 0) {
72
73
  throw new Error('Unable to calculate the changes needed for this file. Edit the file manually.');
73
74
  }
75
+ if (codeMod.type === 'duplicate-composition' && codeMod.tag) {
76
+ (0, imports_1.ensureNamedImport)({
77
+ ast: newAst,
78
+ importedName: codeMod.tag,
79
+ sourcePath: 'remotion',
80
+ localName: codeMod.tag,
81
+ });
82
+ }
74
83
  const output = (0, parse_ast_1.serializeAst)(newAst);
75
84
  return { changesMade, newContents: output };
76
85
  };
@@ -39,10 +39,7 @@ const imports_1 = require("../helpers/imports");
39
39
  const update_nested_prop_1 = require("./update-nested-prop");
40
40
  const b = recast.types.builders;
41
41
  const isNonLinearEasing = (easing) => easing !== 'linear';
42
- const keyframedParamNeedsEasingImport = (param) => {
43
- return (param.interpolationFunction !== 'interpolateColors' &&
44
- param.easing.some(isNonLinearEasing));
45
- };
42
+ const keyframedParamNeedsEasingImport = (param) => param.easing.some(isNonLinearEasing);
46
43
  const getRequiredRemotionImportsForEffectParams = (params) => {
47
44
  const requiredImports = new Set();
48
45
  for (const param of params) {
@@ -91,10 +88,10 @@ const makeKeyframedOptions = ({ param, remotionLocalNames, }) => {
91
88
  if (param.clamping.right !== 'extend') {
92
89
  properties.push(b.objectProperty(b.identifier('extrapolateRight'), b.stringLiteral(param.clamping.right)));
93
90
  }
94
- if (keyframedParamNeedsEasingImport(param)) {
95
- const easingLocalName = (_a = remotionLocalNames.Easing) !== null && _a !== void 0 ? _a : 'Easing';
96
- properties.push(b.objectProperty(b.identifier('easing'), b.arrayExpression(param.easing.map((easing) => makeEasingExpression({ easing, easingLocalName })))));
97
- }
91
+ }
92
+ if (keyframedParamNeedsEasingImport(param)) {
93
+ const easingLocalName = (_a = remotionLocalNames.Easing) !== null && _a !== void 0 ? _a : 'Easing';
94
+ properties.push(b.objectProperty(b.identifier('easing'), b.arrayExpression(param.easing.map((easing) => makeEasingExpression({ easing, easingLocalName })))));
98
95
  }
99
96
  if (param.posterize !== undefined) {
100
97
  properties.push(b.objectProperty(b.identifier('posterize'), (0, update_nested_prop_1.parseValueExpression)(param.posterize)));
@@ -1,5 +1,8 @@
1
1
  import { type KeyframeInterpolationFunction } from '@remotion/studio-shared';
2
- import type { ExtrapolateType, SequenceNodePath, SequenceSchema } from 'remotion';
2
+ import type { CanUpdateSequencePropStatus, ExtrapolateType, SequenceNodePath, SequenceSchema } from 'remotion';
3
+ type KeyframeEasing = Extract<CanUpdateSequencePropStatus, {
4
+ status: 'keyframed';
5
+ }>['easing'][number];
3
6
  export type KeyframeOperation = {
4
7
  type: 'add';
5
8
  frame: number;
@@ -14,6 +17,10 @@ export type KeyframeOperation = {
14
17
  right: ExtrapolateType;
15
18
  } | undefined;
16
19
  posterize: number | undefined;
20
+ } | {
21
+ type: 'easing';
22
+ segmentIndex: number;
23
+ easing: KeyframeEasing;
17
24
  } | {
18
25
  type: 'move';
19
26
  moves: {
@@ -32,6 +39,7 @@ export type EffectKeyframeUpdate = {
32
39
  export type IntroducedKeyframeIdentifiers = {
33
40
  calleeName: KeyframeInterpolationFunction | null;
34
41
  needsFrameHook: boolean;
42
+ needsEasingImport: boolean;
35
43
  };
36
44
  export declare const updateSequenceKeyframesAst: ({ input, nodePath, updates, schema, }: {
37
45
  input: string;
@@ -89,3 +97,4 @@ export declare const updateEffectKeyframes: ({ input, sequenceNodePath, effectIn
89
97
  effectCallee: string;
90
98
  updatedSequenceNodePath: SequenceNodePath;
91
99
  }>;
100
+ export {};
@@ -44,6 +44,62 @@ const update_effect_props_1 = require("../update-effect-props/update-effect-prop
44
44
  const update_nested_prop_1 = require("../update-nested-prop");
45
45
  const ensure_imports_and_frame_hook_1 = require("./ensure-imports-and-frame-hook");
46
46
  const b = recast.types.builders;
47
+ const getObjectPropertyNameFromUpdateKey = (key) => {
48
+ const dotIndex = key.indexOf('.');
49
+ return dotIndex === -1 ? key : key.slice(dotIndex + 1);
50
+ };
51
+ const lineStartsWithPropertyName = ({ line, propertyName, }) => {
52
+ const trimmed = line.trimStart();
53
+ return (trimmed.startsWith(`${propertyName}:`) ||
54
+ trimmed.startsWith(`'${propertyName}':`) ||
55
+ trimmed.startsWith(`"${propertyName}":`));
56
+ };
57
+ const getIndent = (line) => {
58
+ var _a;
59
+ var _b;
60
+ return (_b = (_a = line.match(/^[ \t]*/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
61
+ };
62
+ const removeBlankLinesFromObjectsWithProperties = ({ input, propertyNames, }) => {
63
+ if (propertyNames.length === 0) {
64
+ return input;
65
+ }
66
+ const lines = input.split('\n');
67
+ const linesToRemove = new Set();
68
+ for (let i = 0; i < lines.length; i++) {
69
+ const propertyName = propertyNames.find((name) => lineStartsWithPropertyName({ line: lines[i], propertyName: name }));
70
+ if (!propertyName) {
71
+ continue;
72
+ }
73
+ const propertyIndentLength = getIndent(lines[i]).length;
74
+ let objectStart = i;
75
+ for (let j = i - 1; j >= 0; j--) {
76
+ const trimmed = lines[j].trim();
77
+ if (trimmed.endsWith('{') &&
78
+ getIndent(lines[j]).length < propertyIndentLength) {
79
+ objectStart = j;
80
+ break;
81
+ }
82
+ }
83
+ let objectEnd = i;
84
+ for (let j = i + 1; j < lines.length; j++) {
85
+ const trimmed = lines[j].trim();
86
+ if (trimmed.startsWith('}') &&
87
+ getIndent(lines[j]).length < propertyIndentLength) {
88
+ objectEnd = j;
89
+ break;
90
+ }
91
+ }
92
+ for (let j = objectStart + 1; j < objectEnd; j++) {
93
+ if (lines[j].trim() === '') {
94
+ linesToRemove.add(j);
95
+ }
96
+ }
97
+ }
98
+ if (linesToRemove.size === 0) {
99
+ return input;
100
+ }
101
+ return lines.filter((_, index) => !linesToRemove.has(index)).join('\n');
102
+ };
47
103
  const getSupportedCallArgument = (arg) => {
48
104
  if (arg === undefined ||
49
105
  arg.type === 'ArgumentPlaceholder' ||
@@ -168,6 +224,203 @@ const setOptionsProperty = ({ options, propertyName, value, }) => {
168
224
  }
169
225
  options.properties.push(b.objectProperty(b.identifier(propertyName), value));
170
226
  };
227
+ const isLinearEasing = (easing) => easing === 'linear';
228
+ const getKeyframeEasing = (node) => {
229
+ if (node.type === 'TSAsExpression') {
230
+ return getKeyframeEasing(node.expression);
231
+ }
232
+ if (node.type === 'MemberExpression' &&
233
+ node.object.type === 'Identifier' &&
234
+ node.object.name === 'Easing' &&
235
+ node.property.type === 'Identifier' &&
236
+ node.property.name === 'linear' &&
237
+ node.computed === false) {
238
+ return 'linear';
239
+ }
240
+ if (node.type !== 'CallExpression' ||
241
+ node.callee.type !== 'MemberExpression' ||
242
+ node.callee.object.type !== 'Identifier' ||
243
+ node.callee.object.name !== 'Easing' ||
244
+ node.callee.property.type !== 'Identifier' ||
245
+ node.callee.property.name !== 'bezier' ||
246
+ node.callee.computed ||
247
+ node.arguments.length !== 4) {
248
+ return null;
249
+ }
250
+ const values = node.arguments.map((arg) => {
251
+ if (arg.type === 'ArgumentPlaceholder' ||
252
+ arg.type === 'JSXNamespacedName' ||
253
+ arg.type === 'SpreadElement') {
254
+ return null;
255
+ }
256
+ return getNumericValue(arg);
257
+ });
258
+ if (values.some((value) => value === null)) {
259
+ return null;
260
+ }
261
+ return values;
262
+ };
263
+ const getKeyframeEasingArray = ({ easingNode, segmentCount, }) => {
264
+ if (segmentCount === 0) {
265
+ return [];
266
+ }
267
+ if (easingNode.type === 'TSAsExpression') {
268
+ return getKeyframeEasingArray({
269
+ easingNode: easingNode.expression,
270
+ segmentCount,
271
+ });
272
+ }
273
+ if (easingNode.type === 'ArrayExpression') {
274
+ if (easingNode.elements.length > segmentCount) {
275
+ return null;
276
+ }
277
+ const parsed = easingNode.elements.map((element) => {
278
+ if (!element || element.type === 'SpreadElement') {
279
+ return null;
280
+ }
281
+ return getKeyframeEasing(element);
282
+ });
283
+ if (parsed.some((value) => value === null)) {
284
+ return null;
285
+ }
286
+ const easingArray = parsed;
287
+ while (easingArray.length < segmentCount) {
288
+ easingArray.push('linear');
289
+ }
290
+ return easingArray;
291
+ }
292
+ const easing = getKeyframeEasing(easingNode);
293
+ if (!easing) {
294
+ return null;
295
+ }
296
+ return new Array(segmentCount).fill(easing);
297
+ };
298
+ const getExistingEasingArray = ({ options, segmentCount, }) => {
299
+ const { prop } = findObjectOptionProperty(options, 'easing');
300
+ if (!prop) {
301
+ return new Array(segmentCount).fill('linear');
302
+ }
303
+ const easing = getKeyframeEasingArray({
304
+ easingNode: prop.value,
305
+ segmentCount,
306
+ });
307
+ if (!easing) {
308
+ throw new Error('Cannot update easing: easing must be inline');
309
+ }
310
+ return easing;
311
+ };
312
+ const getExistingEasingArrayOrNull = ({ options, segmentCount, }) => {
313
+ const { prop } = findObjectOptionProperty(options, 'easing');
314
+ if (!prop) {
315
+ return null;
316
+ }
317
+ return getExistingEasingArray({ options, segmentCount });
318
+ };
319
+ const createEasingExpression = (easing) => {
320
+ if (easing === 'linear') {
321
+ return b.memberExpression(b.identifier('Easing'), b.identifier('linear'));
322
+ }
323
+ return b.callExpression(b.memberExpression(b.identifier('Easing'), b.identifier('bezier')), easing.map((value) => (0, update_nested_prop_1.parseValueExpression)(value)));
324
+ };
325
+ const createEasingArrayExpression = (easing) => b.arrayExpression(easing.map((easingValue) => createEasingExpression(easingValue)));
326
+ const setEasingOption = ({ options, easing, }) => {
327
+ const hasNonLinearEasing = easing.some((easingValue) => !isLinearEasing(easingValue));
328
+ setOptionsProperty({
329
+ options,
330
+ propertyName: 'easing',
331
+ value: hasNonLinearEasing ? createEasingArrayExpression(easing) : null,
332
+ });
333
+ return hasNonLinearEasing;
334
+ };
335
+ const getExtraArgsWithOptions = ({ extraArgs, options, }) => {
336
+ return options.properties.length === 0
337
+ ? extraArgs.slice(1)
338
+ : [options, ...extraArgs.slice(1)];
339
+ };
340
+ const getInlineOptionsFromExtraArgs = (extraArgs) => {
341
+ const existingOptions = extraArgs[0];
342
+ if (!existingOptions || existingOptions.type !== 'ObjectExpression') {
343
+ return null;
344
+ }
345
+ return existingOptions;
346
+ };
347
+ const normalizeEasingAfterAddingKeyframe = ({ extraArgs, previousSegmentCount, nextSegmentCount, }) => {
348
+ const options = getInlineOptionsFromExtraArgs(extraArgs);
349
+ if (!options) {
350
+ return { extraArgs, needsEasingImport: false };
351
+ }
352
+ const easing = getExistingEasingArrayOrNull({
353
+ options,
354
+ segmentCount: previousSegmentCount,
355
+ });
356
+ if (easing === null) {
357
+ return { extraArgs, needsEasingImport: false };
358
+ }
359
+ while (easing.length < nextSegmentCount) {
360
+ easing.push('linear');
361
+ }
362
+ return {
363
+ extraArgs: getExtraArgsWithOptions({ extraArgs, options }),
364
+ needsEasingImport: setEasingOption({ options, easing }),
365
+ };
366
+ };
367
+ const normalizeEasingAfterRemovingKeyframe = ({ extraArgs, previousSegmentCount, nextSegmentCount, removedKeyframeIndex, }) => {
368
+ const options = getInlineOptionsFromExtraArgs(extraArgs);
369
+ if (!options) {
370
+ return { extraArgs, needsEasingImport: false };
371
+ }
372
+ const easing = getExistingEasingArrayOrNull({
373
+ options,
374
+ segmentCount: previousSegmentCount,
375
+ });
376
+ if (easing === null) {
377
+ return { extraArgs, needsEasingImport: false };
378
+ }
379
+ if (easing.length > 0) {
380
+ const easingIndexToRemove = removedKeyframeIndex === 0 ? 0 : removedKeyframeIndex - 1;
381
+ easing.splice(easingIndexToRemove, 1);
382
+ }
383
+ while (easing.length > nextSegmentCount) {
384
+ easing.pop();
385
+ }
386
+ while (easing.length < nextSegmentCount) {
387
+ easing.push('linear');
388
+ }
389
+ return {
390
+ extraArgs: getExtraArgsWithOptions({ extraArgs, options }),
391
+ needsEasingImport: setEasingOption({ options, easing }),
392
+ };
393
+ };
394
+ const normalizeEasingAfterRemovingKeyframes = ({ extraArgs, previousSegmentCount, nextSegmentCount, removedKeyframeIndexes, }) => {
395
+ const options = getInlineOptionsFromExtraArgs(extraArgs);
396
+ if (!options) {
397
+ return { extraArgs, needsEasingImport: false };
398
+ }
399
+ const easing = getExistingEasingArrayOrNull({
400
+ options,
401
+ segmentCount: previousSegmentCount,
402
+ });
403
+ if (easing === null) {
404
+ return { extraArgs, needsEasingImport: false };
405
+ }
406
+ for (const removedKeyframeIndex of [...removedKeyframeIndexes].sort((first, second) => second - first)) {
407
+ if (easing.length === 0) {
408
+ break;
409
+ }
410
+ const easingIndexToRemove = removedKeyframeIndex === 0 ? 0 : removedKeyframeIndex - 1;
411
+ easing.splice(easingIndexToRemove, 1);
412
+ }
413
+ while (easing.length > nextSegmentCount) {
414
+ easing.pop();
415
+ }
416
+ while (easing.length < nextSegmentCount) {
417
+ easing.push('linear');
418
+ }
419
+ return {
420
+ extraArgs: getExtraArgsWithOptions({ extraArgs, options }),
421
+ needsEasingImport: setEasingOption({ options, easing }),
422
+ };
423
+ };
171
424
  const validatePosterize = (posterize) => {
172
425
  if (posterize === undefined) {
173
426
  return;
@@ -227,6 +480,46 @@ const updateKeyframeSettings = ({ expression, clamping, posterize, }) => {
227
480
  keyframes: existing.keyframes,
228
481
  });
229
482
  };
483
+ const updateKeyframeEasing = ({ expression, segmentIndex, easing, }) => {
484
+ const existing = getInterpolationExpression(expression);
485
+ if (!existing) {
486
+ throw new Error('Cannot update easing on non-keyframed value');
487
+ }
488
+ const segmentCount = Math.max(0, existing.keyframes.length - 1);
489
+ if (!Number.isInteger(segmentIndex) ||
490
+ segmentIndex < 0 ||
491
+ segmentIndex >= segmentCount) {
492
+ throw new Error('Cannot update easing: segment index out of range');
493
+ }
494
+ const extraArgs = [...existing.extraArgs];
495
+ const existingOptions = extraArgs[0];
496
+ if (existingOptions && existingOptions.type !== 'ObjectExpression') {
497
+ throw new Error('Cannot update easing: options must be inline');
498
+ }
499
+ const options = (existingOptions === null || existingOptions === void 0 ? void 0 : existingOptions.type) === 'ObjectExpression'
500
+ ? existingOptions
501
+ : createEmptyOptionsExpression();
502
+ const nextEasing = getExistingEasingArray({ options, segmentCount });
503
+ nextEasing[segmentIndex] = easing;
504
+ const hasNonLinearEasing = nextEasing.some((easingValue) => !isLinearEasing(easingValue));
505
+ setOptionsProperty({
506
+ options,
507
+ propertyName: 'easing',
508
+ value: hasNonLinearEasing ? createEasingArrayExpression(nextEasing) : null,
509
+ });
510
+ const nextExtraArgs = options.properties.length === 0
511
+ ? extraArgs.slice(1)
512
+ : [options, ...extraArgs.slice(1)];
513
+ return {
514
+ expression: createInterpolateExpression({
515
+ callee: existing.callee,
516
+ input: existing.input,
517
+ extraArgs: nextExtraArgs,
518
+ keyframes: existing.keyframes,
519
+ }),
520
+ needsEasingImport: hasNonLinearEasing,
521
+ };
522
+ };
230
523
  const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) => {
231
524
  const sortedKeyframes = [...keyframes].sort((first, second) => first.frame - second.frame);
232
525
  return b.callExpression(callee, [
@@ -239,6 +532,7 @@ const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) =
239
532
  const noIntroducedIdentifiers = {
240
533
  calleeName: null,
241
534
  needsFrameHook: false,
535
+ needsEasingImport: false,
242
536
  };
243
537
  const addKeyframe = ({ expression, key, frame, value, schema, }) => {
244
538
  if (!(0, studio_shared_1.isSchemaFieldKeyframable)({ schema, key })) {
@@ -261,11 +555,18 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
261
555
  : existing.keyframes.map((keyframe, index) => index === existingIndex
262
556
  ? { frame, output: newOutput, value }
263
557
  : keyframe);
558
+ const normalizedEasing = existingIndex === -1
559
+ ? normalizeEasingAfterAddingKeyframe({
560
+ extraArgs: existing.extraArgs,
561
+ previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
562
+ nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
563
+ })
564
+ : { extraArgs: existing.extraArgs, needsEasingImport: false };
264
565
  return {
265
566
  expression: createInterpolateExpression({
266
567
  callee: b.identifier(nextCalleeName),
267
568
  input: existing.input,
268
- extraArgs: existing.extraArgs,
569
+ extraArgs: normalizedEasing.extraArgs,
269
570
  keyframes: nextKeyframes,
270
571
  }),
271
572
  introduced: {
@@ -273,6 +574,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
273
574
  ? schemaCalleeName
274
575
  : null,
275
576
  needsFrameHook: false,
577
+ needsEasingImport: normalizedEasing.needsEasingImport,
276
578
  },
277
579
  };
278
580
  }
@@ -302,6 +604,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
302
604
  ? callee.name
303
605
  : null,
304
606
  needsFrameHook: true,
607
+ needsEasingImport: false,
305
608
  },
306
609
  };
307
610
  };
@@ -316,17 +619,31 @@ const removeKeyframe = ({ expression, frame, }) => {
316
619
  }
317
620
  const nextKeyframes = existing.keyframes.filter((_keyframe, index) => index !== keyframeIndex);
318
621
  if (nextKeyframes.length === 0) {
319
- return existing.keyframes[keyframeIndex].output;
622
+ return {
623
+ expression: existing.keyframes[keyframeIndex].output,
624
+ introduced: noIntroducedIdentifiers,
625
+ };
320
626
  }
321
- return createInterpolateExpression({
322
- callee: existing.callee,
323
- input: existing.input,
627
+ const normalizedEasing = normalizeEasingAfterRemovingKeyframe({
324
628
  extraArgs: existing.extraArgs,
325
- keyframes: nextKeyframes,
629
+ previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
630
+ nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
631
+ removedKeyframeIndex: keyframeIndex,
326
632
  });
633
+ return {
634
+ expression: createInterpolateExpression({
635
+ callee: existing.callee,
636
+ input: existing.input,
637
+ extraArgs: normalizedEasing.extraArgs,
638
+ keyframes: nextKeyframes,
639
+ }),
640
+ introduced: {
641
+ ...noIntroducedIdentifiers,
642
+ needsEasingImport: normalizedEasing.needsEasingImport,
643
+ },
644
+ };
327
645
  };
328
646
  const moveKeyframes = ({ expression, moves, }) => {
329
- var _a;
330
647
  const existing = getInterpolationExpression(expression);
331
648
  if (!existing) {
332
649
  throw new Error('Cannot move keyframe in non-interpolated expression');
@@ -351,28 +668,38 @@ const moveKeyframes = ({ expression, moves, }) => {
351
668
  }
352
669
  }
353
670
  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`);
671
+ const movedToFrames = new Set(moveMap.values());
672
+ const removedKeyframeIndexes = [];
673
+ const nextKeyframes = existing.keyframes.flatMap((keyframe, index) => {
674
+ const movedFrame = moveMap.get(keyframe.frame);
675
+ if (movedFrame !== undefined) {
676
+ return [{ ...keyframe, frame: movedFrame }];
359
677
  }
360
- if (!movedFromFrames.has(keyframe.frame) && moveMap.has(nextFrame)) {
361
- throw new Error(`Cannot move keyframe to frame ${nextFrame}: frame already exists`);
678
+ if (movedToFrames.has(keyframe.frame) &&
679
+ !movedFromFrames.has(keyframe.frame)) {
680
+ removedKeyframeIndexes.push(index);
681
+ return [];
682
+ }
683
+ return [keyframe];
684
+ });
685
+ const nextFrames = new Set();
686
+ for (const keyframe of nextKeyframes) {
687
+ if (nextFrames.has(keyframe.frame)) {
688
+ throw new Error(`Cannot move keyframe to frame ${keyframe.frame}: frame already exists`);
362
689
  }
363
- nextFrames.add(nextFrame);
690
+ nextFrames.add(keyframe.frame);
364
691
  }
692
+ const normalizedEasing = normalizeEasingAfterRemovingKeyframes({
693
+ extraArgs: existing.extraArgs,
694
+ previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
695
+ nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
696
+ removedKeyframeIndexes,
697
+ });
365
698
  return createInterpolateExpression({
366
699
  callee: existing.callee,
367
700
  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
- }),
701
+ extraArgs: normalizedEasing.extraArgs,
702
+ keyframes: nextKeyframes,
376
703
  });
377
704
  };
378
705
  const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
@@ -395,16 +722,27 @@ const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
395
722
  introduced: noIntroducedIdentifiers,
396
723
  };
397
724
  }
725
+ if (operation.type === 'easing') {
726
+ const updated = updateKeyframeEasing({
727
+ expression,
728
+ segmentIndex: operation.segmentIndex,
729
+ easing: operation.easing,
730
+ });
731
+ return {
732
+ expression: updated.expression,
733
+ introduced: {
734
+ ...noIntroducedIdentifiers,
735
+ needsEasingImport: updated.needsEasingImport,
736
+ },
737
+ };
738
+ }
398
739
  if (operation.type === 'move') {
399
740
  return {
400
741
  expression: moveKeyframes({ expression, moves: operation.moves }),
401
742
  introduced: noIntroducedIdentifiers,
402
743
  };
403
744
  }
404
- return {
405
- expression: removeKeyframe({ expression, frame: operation.frame }),
406
- introduced: noIntroducedIdentifiers,
407
- };
745
+ return removeKeyframe({ expression, frame: operation.frame });
408
746
  };
409
747
  const getExpressionFromJsxAttribute = (attr) => {
410
748
  if (!attr.value) {
@@ -609,6 +947,9 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, schema, }) => {
609
947
  requiredImports.add('useCurrentFrame');
610
948
  needsFrameHook = true;
611
949
  }
950
+ if (introduced.needsEasingImport) {
951
+ requiredImports.add('Easing');
952
+ }
612
953
  }
613
954
  if (needsFrameHook) {
614
955
  const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
@@ -641,8 +982,12 @@ const updateSequenceKeyframes = async ({ input, nodePath, updates, schema, prett
641
982
  input: serialized,
642
983
  prettierConfigOverride,
643
984
  });
985
+ const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
986
+ input: output,
987
+ propertyNames: updates.map((update) => getObjectPropertyNameFromUpdateKey(update.key)),
988
+ });
644
989
  return {
645
- output,
990
+ output: outputWithoutInsertedBlankLines,
646
991
  formatted,
647
992
  oldValueStrings,
648
993
  newValueStrings,
@@ -699,6 +1044,9 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
699
1044
  requiredImports.add('useCurrentFrame');
700
1045
  needsFrameHook = true;
701
1046
  }
1047
+ if (introduced.needsEasingImport) {
1048
+ requiredImports.add('Easing');
1049
+ }
702
1050
  }
703
1051
  if (needsFrameHook) {
704
1052
  const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
@@ -733,8 +1081,12 @@ const updateEffectKeyframes = async ({ input, sequenceNodePath, effectIndex, upd
733
1081
  input: serialized,
734
1082
  prettierConfigOverride,
735
1083
  });
1084
+ const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
1085
+ input: output,
1086
+ propertyNames: updates.map((update) => update.key),
1087
+ });
736
1088
  return {
737
- output,
1089
+ output: outputWithoutInsertedBlankLines,
738
1090
  formatted,
739
1091
  oldValueStrings,
740
1092
  newValueStrings,
@@ -105,18 +105,23 @@ const ensureNamedImport = ({ ast, importedName, sourcePath, localName, }) => {
105
105
  };
106
106
  exports.ensureNamedImport = ensureNamedImport;
107
107
  const ensureNamedImports = ({ ast, importedNames, sourcePath, }) => {
108
- var _a, _b;
108
+ var _a;
109
+ var _b, _c, _d;
109
110
  if (importedNames.size === 0) {
110
111
  return;
111
112
  }
112
113
  const existingImports = findImportDeclarations(ast, sourcePath);
113
114
  const existingNames = new Set();
114
115
  for (const existingImportDeclaration of existingImports) {
115
- for (const importSpecifierCandidate of (_a = existingImportDeclaration.specifiers) !== null && _a !== void 0 ? _a : []) {
116
+ for (const importSpecifierCandidate of (_b = existingImportDeclaration.specifiers) !== null && _b !== void 0 ? _b : []) {
116
117
  if (importSpecifierCandidate.type !== 'ImportSpecifier') {
117
118
  continue;
118
119
  }
119
- existingNames.add((0, exports.getImportedName)(importSpecifierCandidate));
120
+ const importedName = (0, exports.getImportedName)(importSpecifierCandidate);
121
+ const localName = (_c = (_a = importSpecifierCandidate.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _c !== void 0 ? _c : importedName;
122
+ if (localName === importedName) {
123
+ existingNames.add(importedName);
124
+ }
120
125
  }
121
126
  }
122
127
  const existingImport = existingImports.find((candidateImportDeclaration) => !hasNamespaceSpecifier(candidateImportDeclaration));
@@ -126,7 +131,7 @@ const ensureNamedImports = ({ ast, importedNames, sourcePath, }) => {
126
131
  continue;
127
132
  }
128
133
  existingImport.specifiers = [
129
- ...((_b = existingImport.specifiers) !== null && _b !== void 0 ? _b : []),
134
+ ...((_d = existingImport.specifiers) !== null && _d !== void 0 ? _d : []),
130
135
  b.importSpecifier(b.identifier(importedName)),
131
136
  ];
132
137
  existingNames.add(importedName);
@@ -548,12 +548,12 @@ const createComponentElement = ({ localName, props, }) => {
548
548
  createPositionAbsoluteStyleAttribute(),
549
549
  ], true), null, []);
550
550
  };
551
- const createAssetElement = ({ localName, staticFileLocalName, src, dimensions, }) => {
551
+ const createAssetElement = ({ addPositionStyle, localName, staticFileLocalName, src, dimensions, }) => {
552
552
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
553
553
  staticFileLocalName === null
554
554
  ? createStringSrcAttribute(src)
555
555
  : createStaticFileSrcAttribute({ staticFileLocalName, src }),
556
- createPositionAbsoluteStyleAttribute(),
556
+ ...(addPositionStyle ? [createPositionAbsoluteStyleAttribute()] : []),
557
557
  ...(dimensions
558
558
  ? [
559
559
  createNumberAttribute('width', dimensions.width),
@@ -1043,6 +1043,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
1043
1043
  throw new Error('Unsupported asset type');
1044
1044
  }
1045
1045
  return createAssetElement({
1046
+ addPositionStyle: element.assetType !== 'audio',
1046
1047
  localName,
1047
1048
  staticFileLocalName,
1048
1049
  src: element.src,