@remotion/studio-server 4.0.473 → 4.0.475
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.
- package/dist/codemods/effect-param-expression.js +5 -8
- package/dist/codemods/update-keyframes/update-keyframes.d.ts +10 -1
- package/dist/codemods/update-keyframes/update-keyframes.js +325 -12
- package/dist/helpers/imports.js +9 -4
- package/dist/helpers/resolve-composition-component.d.ts +1 -1
- package/dist/helpers/resolve-composition-component.js +81 -3
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/routes/add-keyframes.d.ts +7 -0
- package/dist/preview-server/routes/add-keyframes.js +226 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +3 -7
- package/dist/preview-server/routes/download-remote-asset.js +1 -0
- package/dist/preview-server/routes/insert-jsx-element.d.ts +1 -1
- package/dist/preview-server/routes/insert-jsx-element.js +25 -1
- package/dist/preview-server/routes/log-updates/format-prop-change.js +1 -1
- package/dist/preview-server/routes/log-updates/formatting.d.ts +6 -0
- package/dist/preview-server/routes/log-updates/formatting.js +256 -1
- package/dist/preview-server/routes/update-effect-keyframe-settings.js +11 -5
- package/dist/preview-server/routes/update-sequence-keyframe-settings.js +11 -5
- package/dist/preview-server/undo-stack.d.ts +3 -1
- package/package.json +6 -6
|
@@ -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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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,173 @@ 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
|
+
};
|
|
171
394
|
const validatePosterize = (posterize) => {
|
|
172
395
|
if (posterize === undefined) {
|
|
173
396
|
return;
|
|
@@ -227,6 +450,46 @@ const updateKeyframeSettings = ({ expression, clamping, posterize, }) => {
|
|
|
227
450
|
keyframes: existing.keyframes,
|
|
228
451
|
});
|
|
229
452
|
};
|
|
453
|
+
const updateKeyframeEasing = ({ expression, segmentIndex, easing, }) => {
|
|
454
|
+
const existing = getInterpolationExpression(expression);
|
|
455
|
+
if (!existing) {
|
|
456
|
+
throw new Error('Cannot update easing on non-keyframed value');
|
|
457
|
+
}
|
|
458
|
+
const segmentCount = Math.max(0, existing.keyframes.length - 1);
|
|
459
|
+
if (!Number.isInteger(segmentIndex) ||
|
|
460
|
+
segmentIndex < 0 ||
|
|
461
|
+
segmentIndex >= segmentCount) {
|
|
462
|
+
throw new Error('Cannot update easing: segment index out of range');
|
|
463
|
+
}
|
|
464
|
+
const extraArgs = [...existing.extraArgs];
|
|
465
|
+
const existingOptions = extraArgs[0];
|
|
466
|
+
if (existingOptions && existingOptions.type !== 'ObjectExpression') {
|
|
467
|
+
throw new Error('Cannot update easing: options must be inline');
|
|
468
|
+
}
|
|
469
|
+
const options = (existingOptions === null || existingOptions === void 0 ? void 0 : existingOptions.type) === 'ObjectExpression'
|
|
470
|
+
? existingOptions
|
|
471
|
+
: createEmptyOptionsExpression();
|
|
472
|
+
const nextEasing = getExistingEasingArray({ options, segmentCount });
|
|
473
|
+
nextEasing[segmentIndex] = easing;
|
|
474
|
+
const hasNonLinearEasing = nextEasing.some((easingValue) => !isLinearEasing(easingValue));
|
|
475
|
+
setOptionsProperty({
|
|
476
|
+
options,
|
|
477
|
+
propertyName: 'easing',
|
|
478
|
+
value: hasNonLinearEasing ? createEasingArrayExpression(nextEasing) : null,
|
|
479
|
+
});
|
|
480
|
+
const nextExtraArgs = options.properties.length === 0
|
|
481
|
+
? extraArgs.slice(1)
|
|
482
|
+
: [options, ...extraArgs.slice(1)];
|
|
483
|
+
return {
|
|
484
|
+
expression: createInterpolateExpression({
|
|
485
|
+
callee: existing.callee,
|
|
486
|
+
input: existing.input,
|
|
487
|
+
extraArgs: nextExtraArgs,
|
|
488
|
+
keyframes: existing.keyframes,
|
|
489
|
+
}),
|
|
490
|
+
needsEasingImport: hasNonLinearEasing,
|
|
491
|
+
};
|
|
492
|
+
};
|
|
230
493
|
const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) => {
|
|
231
494
|
const sortedKeyframes = [...keyframes].sort((first, second) => first.frame - second.frame);
|
|
232
495
|
return b.callExpression(callee, [
|
|
@@ -239,6 +502,7 @@ const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) =
|
|
|
239
502
|
const noIntroducedIdentifiers = {
|
|
240
503
|
calleeName: null,
|
|
241
504
|
needsFrameHook: false,
|
|
505
|
+
needsEasingImport: false,
|
|
242
506
|
};
|
|
243
507
|
const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
244
508
|
if (!(0, studio_shared_1.isSchemaFieldKeyframable)({ schema, key })) {
|
|
@@ -261,11 +525,18 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
261
525
|
: existing.keyframes.map((keyframe, index) => index === existingIndex
|
|
262
526
|
? { frame, output: newOutput, value }
|
|
263
527
|
: keyframe);
|
|
528
|
+
const normalizedEasing = existingIndex === -1
|
|
529
|
+
? normalizeEasingAfterAddingKeyframe({
|
|
530
|
+
extraArgs: existing.extraArgs,
|
|
531
|
+
previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
|
|
532
|
+
nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
|
|
533
|
+
})
|
|
534
|
+
: { extraArgs: existing.extraArgs, needsEasingImport: false };
|
|
264
535
|
return {
|
|
265
536
|
expression: createInterpolateExpression({
|
|
266
537
|
callee: b.identifier(nextCalleeName),
|
|
267
538
|
input: existing.input,
|
|
268
|
-
extraArgs:
|
|
539
|
+
extraArgs: normalizedEasing.extraArgs,
|
|
269
540
|
keyframes: nextKeyframes,
|
|
270
541
|
}),
|
|
271
542
|
introduced: {
|
|
@@ -273,6 +544,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
273
544
|
? schemaCalleeName
|
|
274
545
|
: null,
|
|
275
546
|
needsFrameHook: false,
|
|
547
|
+
needsEasingImport: normalizedEasing.needsEasingImport,
|
|
276
548
|
},
|
|
277
549
|
};
|
|
278
550
|
}
|
|
@@ -302,6 +574,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
302
574
|
? callee.name
|
|
303
575
|
: null,
|
|
304
576
|
needsFrameHook: true,
|
|
577
|
+
needsEasingImport: false,
|
|
305
578
|
},
|
|
306
579
|
};
|
|
307
580
|
};
|
|
@@ -316,14 +589,29 @@ const removeKeyframe = ({ expression, frame, }) => {
|
|
|
316
589
|
}
|
|
317
590
|
const nextKeyframes = existing.keyframes.filter((_keyframe, index) => index !== keyframeIndex);
|
|
318
591
|
if (nextKeyframes.length === 0) {
|
|
319
|
-
return
|
|
592
|
+
return {
|
|
593
|
+
expression: existing.keyframes[keyframeIndex].output,
|
|
594
|
+
introduced: noIntroducedIdentifiers,
|
|
595
|
+
};
|
|
320
596
|
}
|
|
321
|
-
|
|
322
|
-
callee: existing.callee,
|
|
323
|
-
input: existing.input,
|
|
597
|
+
const normalizedEasing = normalizeEasingAfterRemovingKeyframe({
|
|
324
598
|
extraArgs: existing.extraArgs,
|
|
325
|
-
|
|
599
|
+
previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
|
|
600
|
+
nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
|
|
601
|
+
removedKeyframeIndex: keyframeIndex,
|
|
326
602
|
});
|
|
603
|
+
return {
|
|
604
|
+
expression: createInterpolateExpression({
|
|
605
|
+
callee: existing.callee,
|
|
606
|
+
input: existing.input,
|
|
607
|
+
extraArgs: normalizedEasing.extraArgs,
|
|
608
|
+
keyframes: nextKeyframes,
|
|
609
|
+
}),
|
|
610
|
+
introduced: {
|
|
611
|
+
...noIntroducedIdentifiers,
|
|
612
|
+
needsEasingImport: normalizedEasing.needsEasingImport,
|
|
613
|
+
},
|
|
614
|
+
};
|
|
327
615
|
};
|
|
328
616
|
const moveKeyframes = ({ expression, moves, }) => {
|
|
329
617
|
var _a;
|
|
@@ -395,16 +683,27 @@ const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
|
|
|
395
683
|
introduced: noIntroducedIdentifiers,
|
|
396
684
|
};
|
|
397
685
|
}
|
|
686
|
+
if (operation.type === 'easing') {
|
|
687
|
+
const updated = updateKeyframeEasing({
|
|
688
|
+
expression,
|
|
689
|
+
segmentIndex: operation.segmentIndex,
|
|
690
|
+
easing: operation.easing,
|
|
691
|
+
});
|
|
692
|
+
return {
|
|
693
|
+
expression: updated.expression,
|
|
694
|
+
introduced: {
|
|
695
|
+
...noIntroducedIdentifiers,
|
|
696
|
+
needsEasingImport: updated.needsEasingImport,
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
}
|
|
398
700
|
if (operation.type === 'move') {
|
|
399
701
|
return {
|
|
400
702
|
expression: moveKeyframes({ expression, moves: operation.moves }),
|
|
401
703
|
introduced: noIntroducedIdentifiers,
|
|
402
704
|
};
|
|
403
705
|
}
|
|
404
|
-
return {
|
|
405
|
-
expression: removeKeyframe({ expression, frame: operation.frame }),
|
|
406
|
-
introduced: noIntroducedIdentifiers,
|
|
407
|
-
};
|
|
706
|
+
return removeKeyframe({ expression, frame: operation.frame });
|
|
408
707
|
};
|
|
409
708
|
const getExpressionFromJsxAttribute = (attr) => {
|
|
410
709
|
if (!attr.value) {
|
|
@@ -609,6 +908,9 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, schema, }) => {
|
|
|
609
908
|
requiredImports.add('useCurrentFrame');
|
|
610
909
|
needsFrameHook = true;
|
|
611
910
|
}
|
|
911
|
+
if (introduced.needsEasingImport) {
|
|
912
|
+
requiredImports.add('Easing');
|
|
913
|
+
}
|
|
612
914
|
}
|
|
613
915
|
if (needsFrameHook) {
|
|
614
916
|
const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
|
|
@@ -641,8 +943,12 @@ const updateSequenceKeyframes = async ({ input, nodePath, updates, schema, prett
|
|
|
641
943
|
input: serialized,
|
|
642
944
|
prettierConfigOverride,
|
|
643
945
|
});
|
|
946
|
+
const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
|
|
947
|
+
input: output,
|
|
948
|
+
propertyNames: updates.map((update) => getObjectPropertyNameFromUpdateKey(update.key)),
|
|
949
|
+
});
|
|
644
950
|
return {
|
|
645
|
-
output,
|
|
951
|
+
output: outputWithoutInsertedBlankLines,
|
|
646
952
|
formatted,
|
|
647
953
|
oldValueStrings,
|
|
648
954
|
newValueStrings,
|
|
@@ -699,6 +1005,9 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
|
|
|
699
1005
|
requiredImports.add('useCurrentFrame');
|
|
700
1006
|
needsFrameHook = true;
|
|
701
1007
|
}
|
|
1008
|
+
if (introduced.needsEasingImport) {
|
|
1009
|
+
requiredImports.add('Easing');
|
|
1010
|
+
}
|
|
702
1011
|
}
|
|
703
1012
|
if (needsFrameHook) {
|
|
704
1013
|
const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
|
|
@@ -733,8 +1042,12 @@ const updateEffectKeyframes = async ({ input, sequenceNodePath, effectIndex, upd
|
|
|
733
1042
|
input: serialized,
|
|
734
1043
|
prettierConfigOverride,
|
|
735
1044
|
});
|
|
1045
|
+
const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
|
|
1046
|
+
input: output,
|
|
1047
|
+
propertyNames: updates.map((update) => update.key),
|
|
1048
|
+
});
|
|
736
1049
|
return {
|
|
737
|
-
output,
|
|
1050
|
+
output: outputWithoutInsertedBlankLines,
|
|
738
1051
|
formatted,
|
|
739
1052
|
oldValueStrings,
|
|
740
1053
|
newValueStrings,
|
package/dist/helpers/imports.js
CHANGED
|
@@ -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
|
|
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 (
|
|
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
|
-
|
|
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
|
-
...((
|
|
134
|
+
...((_d = existingImport.specifiers) !== null && _d !== void 0 ? _d : []),
|
|
130
135
|
b.importSpecifier(b.identifier(importedName)),
|
|
131
136
|
];
|
|
132
137
|
existingNames.add(importedName);
|
|
@@ -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,10 +542,18 @@ const createSolidElement = ({ localName, width, height, }) => {
|
|
|
523
542
|
createPositionAbsoluteStyleAttribute(),
|
|
524
543
|
], true), null, []);
|
|
525
544
|
};
|
|
526
|
-
const
|
|
545
|
+
const createComponentElement = ({ localName, props, }) => {
|
|
527
546
|
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
528
|
-
|
|
547
|
+
...props.map(createComponentProp),
|
|
529
548
|
createPositionAbsoluteStyleAttribute(),
|
|
549
|
+
], true), null, []);
|
|
550
|
+
};
|
|
551
|
+
const createAssetElement = ({ addPositionStyle, localName, staticFileLocalName, src, dimensions, }) => {
|
|
552
|
+
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
553
|
+
staticFileLocalName === null
|
|
554
|
+
? createStringSrcAttribute(src)
|
|
555
|
+
: createStaticFileSrcAttribute({ staticFileLocalName, src }),
|
|
556
|
+
...(addPositionStyle ? [createPositionAbsoluteStyleAttribute()] : []),
|
|
530
557
|
...(dimensions
|
|
531
558
|
? [
|
|
532
559
|
createNumberAttribute('width', dimensions.width),
|
|
@@ -725,6 +752,41 @@ const ensureGifImport = (ast) => {
|
|
|
725
752
|
label: '<Gif>',
|
|
726
753
|
});
|
|
727
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
|
+
};
|
|
728
790
|
const addElementToComponentRoot = ({ ast, exportName, element, }) => {
|
|
729
791
|
var _a;
|
|
730
792
|
var _b;
|
|
@@ -947,8 +1009,23 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
947
1009
|
height: element.height,
|
|
948
1010
|
});
|
|
949
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
|
+
}
|
|
950
1024
|
if (element.type === 'asset') {
|
|
951
|
-
|
|
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);
|
|
952
1029
|
let localName;
|
|
953
1030
|
if (element.assetType === 'image') {
|
|
954
1031
|
localName = ensureImgImport(ast);
|
|
@@ -966,6 +1043,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
966
1043
|
throw new Error('Unsupported asset type');
|
|
967
1044
|
}
|
|
968
1045
|
return createAssetElement({
|
|
1046
|
+
addPositionStyle: element.assetType !== 'audio',
|
|
969
1047
|
localName,
|
|
970
1048
|
staticFileLocalName,
|
|
971
1049
|
src: element.src,
|