@remotion/studio-server 4.0.485 → 4.0.487
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/duplicate-composition.js +8 -0
- package/dist/codemods/recast-mods.js +209 -5
- package/dist/codemods/update-keyframes/update-keyframes.js +2 -49
- package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +2 -0
- package/dist/codemods/update-sequence-props/update-sequence-props.js +344 -2
- package/dist/helpers/import-agnostic-node-path.js +30 -4
- package/dist/helpers/parse-keyframe-easing-expression.d.ts +3 -0
- package/dist/helpers/parse-keyframe-easing-expression.js +141 -0
- package/dist/helpers/resolve-composition-component.d.ts +2 -1
- package/dist/helpers/resolve-composition-component.js +212 -11
- package/dist/open-browser-shortcut.d.ts +9 -0
- package/dist/open-browser-shortcut.js +111 -0
- package/dist/preview-server/live-events.d.ts +1 -0
- package/dist/preview-server/live-events.js +10 -7
- package/dist/preview-server/routes/apply-codemod.js +19 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +2 -49
- package/dist/preview-server/routes/insert-element.js +3 -0
- package/dist/preview-server/routes/insert-jsx-element.js +51 -2
- package/dist/preview-server/routes/save-sequence-props.d.ts +3 -1
- package/dist/preview-server/routes/save-sequence-props.js +207 -23
- package/dist/preview-server/undo-stack.d.ts +5 -1
- package/dist/start-studio.js +17 -4
- package/package.json +6 -6
|
@@ -94,6 +94,14 @@ const parseAndApplyCodemod = ({ input, codeMod, }) => {
|
|
|
94
94
|
localName: codeMod.componentName,
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
|
+
if (codeMod.type === 'new-folder') {
|
|
98
|
+
(0, imports_1.ensureNamedImport)({
|
|
99
|
+
ast: newAst,
|
|
100
|
+
importedName: 'Folder',
|
|
101
|
+
sourcePath: 'remotion',
|
|
102
|
+
localName: 'Folder',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
97
105
|
const output = (0, parse_ast_1.serializeAst)(newAst);
|
|
98
106
|
return { changesMade, newContents: output };
|
|
99
107
|
};
|
|
@@ -36,12 +36,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.applyCodemod = void 0;
|
|
37
37
|
const recast = __importStar(require("recast"));
|
|
38
38
|
const apply_visual_control_1 = require("./apply-visual-control");
|
|
39
|
+
const delete_jsx_node_1 = require("./delete-jsx-node");
|
|
39
40
|
const b = recast.types.builders;
|
|
40
41
|
const applyCodemod = ({ file, codeMod, }) => {
|
|
41
42
|
const changesMade = [];
|
|
42
43
|
if (codeMod.type === 'apply-visual-control') {
|
|
43
44
|
return (0, apply_visual_control_1.applyVisualControl)({ file, transformation: codeMod, changesMade });
|
|
44
45
|
}
|
|
46
|
+
if (codeMod.type === 'move-composition-to-folder') {
|
|
47
|
+
return moveCompositionToFolder({
|
|
48
|
+
file,
|
|
49
|
+
transformation: codeMod,
|
|
50
|
+
changesMade,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
45
53
|
const body = file.program.body.map((node) => {
|
|
46
54
|
return mapAll(node, codeMod, changesMade, null);
|
|
47
55
|
});
|
|
@@ -104,6 +112,15 @@ const mapReturnStatement = (statement, transformation, changesMade, parentFolder
|
|
|
104
112
|
argument: addNewCompositionToRootJsx(statement.argument, transformation, changesMade),
|
|
105
113
|
};
|
|
106
114
|
}
|
|
115
|
+
if (transformation.type === 'new-folder' &&
|
|
116
|
+
transformation.parentName === null &&
|
|
117
|
+
(statement.argument.type === 'JSXElement' ||
|
|
118
|
+
statement.argument.type === 'JSXFragment')) {
|
|
119
|
+
return {
|
|
120
|
+
...statement,
|
|
121
|
+
argument: addNewFolderToRootJsx(statement.argument, transformation, changesMade),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
107
124
|
const replacement = transformLoneJsxElement(statement.argument, transformation, changesMade, parentFolderName);
|
|
108
125
|
if (replacement !== null) {
|
|
109
126
|
return { ...statement, argument: replacement };
|
|
@@ -177,6 +194,19 @@ const newCompositionElement = (transformation) => {
|
|
|
177
194
|
children: [],
|
|
178
195
|
};
|
|
179
196
|
};
|
|
197
|
+
const newFolderElement = (transformation) => {
|
|
198
|
+
return {
|
|
199
|
+
type: 'JSXElement',
|
|
200
|
+
openingElement: {
|
|
201
|
+
type: 'JSXOpeningElement',
|
|
202
|
+
name: jsxId('Folder'),
|
|
203
|
+
attributes: [jsxAttributeWithString('name', transformation.folderName)],
|
|
204
|
+
selfClosing: true,
|
|
205
|
+
},
|
|
206
|
+
closingElement: null,
|
|
207
|
+
children: [],
|
|
208
|
+
};
|
|
209
|
+
};
|
|
180
210
|
const addNewCompositionToRootJsx = (root, transformation, changesMade) => {
|
|
181
211
|
if (changesMade.length > 0) {
|
|
182
212
|
return root;
|
|
@@ -192,6 +222,21 @@ const addNewCompositionToRootJsx = (root, transformation, changesMade) => {
|
|
|
192
222
|
}
|
|
193
223
|
return wrapInJsxFragment([root, newCompositionElement(transformation)]);
|
|
194
224
|
};
|
|
225
|
+
const addNewFolderToRootJsx = (root, transformation, changesMade) => {
|
|
226
|
+
if (changesMade.length > 0) {
|
|
227
|
+
return root;
|
|
228
|
+
}
|
|
229
|
+
changesMade.push({
|
|
230
|
+
description: 'Added new folder',
|
|
231
|
+
});
|
|
232
|
+
if (root.type === 'JSXFragment') {
|
|
233
|
+
return {
|
|
234
|
+
...root,
|
|
235
|
+
children: [...root.children, newFolderElement(transformation)],
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return wrapInJsxFragment([root, newFolderElement(transformation)]);
|
|
239
|
+
};
|
|
195
240
|
const addNewCompositionToFolder = (folderElement, transformation, changesMade) => {
|
|
196
241
|
var _a;
|
|
197
242
|
if (changesMade.length > 0) {
|
|
@@ -216,6 +261,146 @@ const addNewCompositionToFolder = (folderElement, transformation, changesMade) =
|
|
|
216
261
|
],
|
|
217
262
|
};
|
|
218
263
|
};
|
|
264
|
+
const addNewFolderToFolder = (folderElement, transformation, changesMade) => {
|
|
265
|
+
var _a;
|
|
266
|
+
if (changesMade.length > 0) {
|
|
267
|
+
return folderElement;
|
|
268
|
+
}
|
|
269
|
+
changesMade.push({
|
|
270
|
+
description: 'Added new folder',
|
|
271
|
+
});
|
|
272
|
+
return {
|
|
273
|
+
...folderElement,
|
|
274
|
+
openingElement: {
|
|
275
|
+
...folderElement.openingElement,
|
|
276
|
+
selfClosing: false,
|
|
277
|
+
},
|
|
278
|
+
closingElement: (_a = folderElement.closingElement) !== null && _a !== void 0 ? _a : {
|
|
279
|
+
type: 'JSXClosingElement',
|
|
280
|
+
name: folderElement.openingElement.name,
|
|
281
|
+
},
|
|
282
|
+
children: [...folderElement.children, newFolderElement(transformation)],
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const getChildFolderParentName = ({ folderName, parentFolderName, }) => {
|
|
286
|
+
return [parentFolderName, folderName].filter(Boolean).join('/');
|
|
287
|
+
};
|
|
288
|
+
const appendCompositionToFolder = ({ compositionElement, folderElement, }) => {
|
|
289
|
+
var _a;
|
|
290
|
+
folderElement.openingElement.selfClosing = false;
|
|
291
|
+
folderElement.closingElement = (_a = folderElement.closingElement) !== null && _a !== void 0 ? _a : {
|
|
292
|
+
type: 'JSXClosingElement',
|
|
293
|
+
name: folderElement.openingElement.name,
|
|
294
|
+
};
|
|
295
|
+
folderElement.children.push(stripParenthesizedExtra(compositionElement));
|
|
296
|
+
};
|
|
297
|
+
const appendCompositionToRoot = ({ compositionElement, file, }) => {
|
|
298
|
+
let appended = false;
|
|
299
|
+
recast.types.visit(file, {
|
|
300
|
+
visitReturnStatement(astPath) {
|
|
301
|
+
if (appended) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
const { argument } = astPath.node;
|
|
305
|
+
if ((argument === null || argument === void 0 ? void 0 : argument.type) !== 'JSXFragment' && (argument === null || argument === void 0 ? void 0 : argument.type) !== 'JSXElement') {
|
|
306
|
+
this.traverse(astPath);
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
if (argument.type === 'JSXFragment') {
|
|
310
|
+
argument.children.push(stripParenthesizedExtra(compositionElement));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
astPath.node.argument = wrapInJsxFragment([
|
|
314
|
+
argument,
|
|
315
|
+
compositionElement,
|
|
316
|
+
]);
|
|
317
|
+
}
|
|
318
|
+
appended = true;
|
|
319
|
+
return false;
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
if (!appended) {
|
|
323
|
+
throw new Error('Could not find a root JSX element');
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const moveCompositionToFolder = ({ file, transformation, changesMade, }) => {
|
|
327
|
+
let sourcePath = null;
|
|
328
|
+
let sourceParentFolderName = null;
|
|
329
|
+
let sourceIsDirectJsxChild = false;
|
|
330
|
+
let targetFolder = null;
|
|
331
|
+
const folderStack = [];
|
|
332
|
+
const isDirectJsxChild = (astPath) => {
|
|
333
|
+
var _a;
|
|
334
|
+
const parent = (_a = astPath.parentPath) === null || _a === void 0 ? void 0 : _a.node;
|
|
335
|
+
return (((parent === null || parent === void 0 ? void 0 : parent.type) === 'JSXElement' || (parent === null || parent === void 0 ? void 0 : parent.type) === 'JSXFragment') &&
|
|
336
|
+
parent.children.includes(astPath.node));
|
|
337
|
+
};
|
|
338
|
+
const visitJsxElementWithFolderContext = (astPath) => {
|
|
339
|
+
const node = astPath.node;
|
|
340
|
+
const compositionId = getCompositionIdFromJSXElement(node);
|
|
341
|
+
if (compositionId === transformation.idToMove) {
|
|
342
|
+
sourcePath = astPath;
|
|
343
|
+
sourceParentFolderName = folderStack.join('/') || null;
|
|
344
|
+
sourceIsDirectJsxChild = isDirectJsxChild(astPath);
|
|
345
|
+
}
|
|
346
|
+
const folderName = getFolderNameFromJSXElement(node);
|
|
347
|
+
const parentName = folderStack.join('/') || null;
|
|
348
|
+
if (transformation.folderName !== null &&
|
|
349
|
+
folderName === transformation.folderName &&
|
|
350
|
+
parentName === transformation.parentName) {
|
|
351
|
+
targetFolder = node;
|
|
352
|
+
}
|
|
353
|
+
if (folderName) {
|
|
354
|
+
folderStack.push(folderName);
|
|
355
|
+
}
|
|
356
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
357
|
+
if (node.children[i].type !== 'JSXElement') {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
visitJsxElementWithFolderContext(astPath.get('children', i));
|
|
361
|
+
}
|
|
362
|
+
if (folderName) {
|
|
363
|
+
folderStack.pop();
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
recast.types.visit(file, {
|
|
367
|
+
visitJSXElement(astPath) {
|
|
368
|
+
visitJsxElementWithFolderContext(astPath);
|
|
369
|
+
return false;
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
if (!sourcePath) {
|
|
373
|
+
throw new Error(`Could not find composition "${transformation.idToMove}"`);
|
|
374
|
+
}
|
|
375
|
+
if (!sourceIsDirectJsxChild) {
|
|
376
|
+
throw new Error(`Cannot move composition "${transformation.idToMove}" because it is not a direct JSX child`);
|
|
377
|
+
}
|
|
378
|
+
if (transformation.folderName === null && sourceParentFolderName === null) {
|
|
379
|
+
return { newAst: file, changesMade };
|
|
380
|
+
}
|
|
381
|
+
if (transformation.folderName !== null && !targetFolder) {
|
|
382
|
+
const folderLabel = `${transformation.parentName ? `${transformation.parentName}/` : ''}${transformation.folderName}`;
|
|
383
|
+
throw new Error(`Could not find folder "${folderLabel}"`);
|
|
384
|
+
}
|
|
385
|
+
const compositionElement = sourcePath
|
|
386
|
+
.node;
|
|
387
|
+
(0, delete_jsx_node_1.deleteJsxElementAtPath)(sourcePath);
|
|
388
|
+
if (transformation.folderName === null) {
|
|
389
|
+
appendCompositionToRoot({ compositionElement, file });
|
|
390
|
+
changesMade.push({ description: 'Moved composition to root' });
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
if (targetFolder === null) {
|
|
394
|
+
throw new Error('Could not find target folder');
|
|
395
|
+
}
|
|
396
|
+
appendCompositionToFolder({
|
|
397
|
+
compositionElement,
|
|
398
|
+
folderElement: targetFolder,
|
|
399
|
+
});
|
|
400
|
+
changesMade.push({ description: 'Moved composition into folder' });
|
|
401
|
+
}
|
|
402
|
+
return { newAst: file, changesMade };
|
|
403
|
+
};
|
|
219
404
|
// When a <Composition> JSX element appears in a position where it cannot
|
|
220
405
|
// simply be removed from a parent's children list (e.g. as the sole return
|
|
221
406
|
// value of a wrapper component or as the concise body of an arrow function),
|
|
@@ -237,7 +422,10 @@ const transformLoneJsxElement = (expression, transformation, changesMade, parent
|
|
|
237
422
|
parentFolderName === transformation.parentName) ||
|
|
238
423
|
(transformation.type === 'new-composition' &&
|
|
239
424
|
folderName === transformation.folderName &&
|
|
240
|
-
parentFolderName === transformation.parentName)
|
|
425
|
+
parentFolderName === transformation.parentName) ||
|
|
426
|
+
(transformation.type === 'new-folder' &&
|
|
427
|
+
getChildFolderParentName({ folderName, parentFolderName }) ===
|
|
428
|
+
transformation.parentName));
|
|
241
429
|
if (!isFolderMatch) {
|
|
242
430
|
return null;
|
|
243
431
|
}
|
|
@@ -256,7 +444,11 @@ const transformLoneJsxElement = (expression, transformation, changesMade, parent
|
|
|
256
444
|
parentFolderName === transformation.parentName) ||
|
|
257
445
|
(transformation.type === 'new-composition' &&
|
|
258
446
|
folderName === transformation.folderName &&
|
|
259
|
-
parentFolderName === transformation.parentName)
|
|
447
|
+
parentFolderName === transformation.parentName) ||
|
|
448
|
+
(transformation.type === 'new-folder' &&
|
|
449
|
+
folderName !== null &&
|
|
450
|
+
getChildFolderParentName({ folderName, parentFolderName }) ===
|
|
451
|
+
transformation.parentName);
|
|
260
452
|
if (!isMatch) {
|
|
261
453
|
return null;
|
|
262
454
|
}
|
|
@@ -283,9 +475,6 @@ const mapJsxElementOrFragment = (jsxFragment, transformation, changesMade, paren
|
|
|
283
475
|
.flat(1),
|
|
284
476
|
};
|
|
285
477
|
};
|
|
286
|
-
const getChildFolderParentName = ({ folderName, parentFolderName, }) => {
|
|
287
|
-
return [parentFolderName, folderName].filter(Boolean).join('/');
|
|
288
|
-
};
|
|
289
478
|
const mapJsxChild = (c, transformation, changesMade, parentFolderName) => {
|
|
290
479
|
const compId = getCompositionIdFromJSXElement(c);
|
|
291
480
|
const folderName = getFolderNameFromJSXElement(c);
|
|
@@ -354,6 +543,12 @@ const mapJsxChild = (c, transformation, changesMade, parentFolderName) => {
|
|
|
354
543
|
parentFolderName === transformation.parentName) {
|
|
355
544
|
return [addNewCompositionToFolder(c, transformation, changesMade)];
|
|
356
545
|
}
|
|
546
|
+
if (transformation.type === 'new-folder' &&
|
|
547
|
+
folderName !== null &&
|
|
548
|
+
getChildFolderParentName({ folderName, parentFolderName }) ===
|
|
549
|
+
transformation.parentName) {
|
|
550
|
+
return [addNewFolderToFolder(c, transformation, changesMade)];
|
|
551
|
+
}
|
|
357
552
|
const childParentFolderName = folderName
|
|
358
553
|
? getChildFolderParentName({ folderName, parentFolderName })
|
|
359
554
|
: parentFolderName;
|
|
@@ -374,6 +569,15 @@ const mapRecognizedType = (expression, transformation, changesMade, parentFolder
|
|
|
374
569
|
body: addNewCompositionToRootJsx(expression.body, transformation, changesMade),
|
|
375
570
|
};
|
|
376
571
|
}
|
|
572
|
+
if (transformation.type === 'new-folder' &&
|
|
573
|
+
transformation.parentName === null &&
|
|
574
|
+
(expression.body.type === 'JSXElement' ||
|
|
575
|
+
expression.body.type === 'JSXFragment')) {
|
|
576
|
+
return {
|
|
577
|
+
...expression,
|
|
578
|
+
body: addNewFolderToRootJsx(expression.body, transformation, changesMade),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
377
581
|
if (expression.type === 'ArrowFunctionExpression' &&
|
|
378
582
|
expression.body.type === 'JSXElement') {
|
|
379
583
|
const replacement = transformLoneJsxElement(expression.body, transformation, changesMade, parentFolderName);
|
|
@@ -37,6 +37,7 @@ exports.updateEffectKeyframes = exports.updateEffectKeyframesAst = exports.updat
|
|
|
37
37
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
38
38
|
const recast = __importStar(require("recast"));
|
|
39
39
|
const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
|
|
40
|
+
const parse_keyframe_easing_expression_1 = require("../../helpers/parse-keyframe-easing-expression");
|
|
40
41
|
const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
|
|
41
42
|
const format_file_content_1 = require("../format-file-content");
|
|
42
43
|
const parse_ast_1 = require("../parse-ast");
|
|
@@ -225,55 +226,7 @@ const setOptionsProperty = ({ options, propertyName, value, }) => {
|
|
|
225
226
|
options.properties.push(b.objectProperty(b.identifier(propertyName), value));
|
|
226
227
|
};
|
|
227
228
|
const isLinearEasing = (easing) => easing.type === '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 { type: '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.computed) {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
if (node.callee.property.name === 'spring') {
|
|
249
|
-
if (node.arguments.length > 1) {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
const springConfig = node.arguments[0];
|
|
253
|
-
if ((springConfig === null || springConfig === void 0 ? void 0 : springConfig.type) === 'ArgumentPlaceholder' ||
|
|
254
|
-
(springConfig === null || springConfig === void 0 ? void 0 : springConfig.type) === 'JSXNamespacedName' ||
|
|
255
|
-
(springConfig === null || springConfig === void 0 ? void 0 : springConfig.type) === 'SpreadElement') {
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
return (0, studio_shared_1.parseSpringEasingConfig)(springConfig);
|
|
259
|
-
}
|
|
260
|
-
if (node.callee.property.name !== 'bezier' || node.arguments.length !== 4) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
const values = node.arguments.map((arg) => {
|
|
264
|
-
if (arg.type === 'ArgumentPlaceholder' ||
|
|
265
|
-
arg.type === 'JSXNamespacedName' ||
|
|
266
|
-
arg.type === 'SpreadElement') {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
return getNumericValue(arg);
|
|
270
|
-
});
|
|
271
|
-
if (values.some((value) => value === null)) {
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
const [x1, y1, x2, y2] = values;
|
|
275
|
-
return { type: 'bezier', x1, y1, x2, y2 };
|
|
276
|
-
};
|
|
229
|
+
const getKeyframeEasing = (node) => (0, parse_keyframe_easing_expression_1.parseKeyframeEasingExpression)(node);
|
|
277
230
|
const getKeyframeEasingArray = ({ easingNode, segmentCount, }) => {
|
|
278
231
|
if (segmentCount === 0) {
|
|
279
232
|
return [];
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { GoogleFontSourceEdit } from '@remotion/studio-shared';
|
|
1
2
|
import type { InteractivitySchema, SequenceNodePath } from 'remotion';
|
|
2
3
|
export type SequencePropUpdate = {
|
|
3
4
|
key: string;
|
|
4
5
|
value: unknown;
|
|
5
6
|
defaultValue: unknown | null;
|
|
7
|
+
googleFont?: GoogleFontSourceEdit | null;
|
|
6
8
|
};
|
|
7
9
|
export type RemovedProp = {
|
|
8
10
|
key: string;
|