@remotion/studio-server 4.0.483 → 4.0.485
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/recast-mods.js +37 -0
- package/dist/codemods/split-jsx-sequence.d.ts +14 -0
- package/dist/codemods/split-jsx-sequence.js +345 -0
- package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +1 -1
- package/dist/codemods/update-sequence-props/update-sequence-props.js +62 -7
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/routes/add-effect-keyframe.js +2 -2
- package/dist/preview-server/routes/add-effect.js +56 -53
- package/dist/preview-server/routes/add-keyframes.js +2 -2
- package/dist/preview-server/routes/add-sequence-keyframe.js +2 -2
- package/dist/preview-server/routes/apply-codemod.js +104 -101
- package/dist/preview-server/routes/apply-visual-control-change.js +83 -80
- package/dist/preview-server/routes/can-update-sequence-props.d.ts +13 -1
- package/dist/preview-server/routes/can-update-sequence-props.js +101 -7
- package/dist/preview-server/routes/delete-effect.js +83 -80
- package/dist/preview-server/routes/delete-jsx-node.js +74 -71
- package/dist/preview-server/routes/delete-keyframes.js +2 -2
- package/dist/preview-server/routes/duplicate-effect.js +77 -74
- package/dist/preview-server/routes/duplicate-jsx-node.js +53 -50
- package/dist/preview-server/routes/insert-element.js +2 -2
- package/dist/preview-server/routes/insert-jsx-element.js +2 -2
- package/dist/preview-server/routes/move-keyframes.js +2 -2
- package/dist/preview-server/routes/paste-effects.js +59 -56
- package/dist/preview-server/routes/reorder-effect.js +55 -52
- package/dist/preview-server/routes/reorder-sequence.js +55 -52
- package/dist/preview-server/routes/save-effect-props.js +2 -2
- package/dist/preview-server/routes/save-sequence-props.js +2 -2
- package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -0
- package/dist/preview-server/routes/source-file-write-queue.js +11 -0
- package/dist/preview-server/routes/split-jsx-sequence.d.ts +3 -0
- package/dist/preview-server/routes/split-jsx-sequence.js +66 -0
- package/dist/preview-server/routes/update-default-props.js +58 -55
- package/dist/preview-server/routes/update-effect-keyframe-settings.js +2 -2
- package/dist/preview-server/routes/update-sequence-keyframe-settings.js +2 -2
- package/dist/preview-server/undo-stack.d.ts +3 -1
- package/package.json +6 -6
|
@@ -96,6 +96,7 @@ const mapReturnStatement = (statement, transformation, changesMade, parentFolder
|
|
|
96
96
|
return statement;
|
|
97
97
|
}
|
|
98
98
|
if (transformation.type === 'new-composition' &&
|
|
99
|
+
transformation.folderName === null &&
|
|
99
100
|
(statement.argument.type === 'JSXElement' ||
|
|
100
101
|
statement.argument.type === 'JSXFragment')) {
|
|
101
102
|
return {
|
|
@@ -191,6 +192,30 @@ const addNewCompositionToRootJsx = (root, transformation, changesMade) => {
|
|
|
191
192
|
}
|
|
192
193
|
return wrapInJsxFragment([root, newCompositionElement(transformation)]);
|
|
193
194
|
};
|
|
195
|
+
const addNewCompositionToFolder = (folderElement, transformation, changesMade) => {
|
|
196
|
+
var _a;
|
|
197
|
+
if (changesMade.length > 0) {
|
|
198
|
+
return folderElement;
|
|
199
|
+
}
|
|
200
|
+
changesMade.push({
|
|
201
|
+
description: 'Added new composition',
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
...folderElement,
|
|
205
|
+
openingElement: {
|
|
206
|
+
...folderElement.openingElement,
|
|
207
|
+
selfClosing: false,
|
|
208
|
+
},
|
|
209
|
+
closingElement: (_a = folderElement.closingElement) !== null && _a !== void 0 ? _a : {
|
|
210
|
+
type: 'JSXClosingElement',
|
|
211
|
+
name: folderElement.openingElement.name,
|
|
212
|
+
},
|
|
213
|
+
children: [
|
|
214
|
+
...folderElement.children,
|
|
215
|
+
newCompositionElement(transformation),
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
};
|
|
194
219
|
// When a <Composition> JSX element appears in a position where it cannot
|
|
195
220
|
// simply be removed from a parent's children list (e.g. as the sole return
|
|
196
221
|
// value of a wrapper component or as the concise body of an arrow function),
|
|
@@ -208,6 +233,9 @@ const transformLoneJsxElement = (expression, transformation, changesMade, parent
|
|
|
208
233
|
folderName === transformation.folderName &&
|
|
209
234
|
parentFolderName === transformation.parentName) ||
|
|
210
235
|
(transformation.type === 'rename-folder' &&
|
|
236
|
+
folderName === transformation.folderName &&
|
|
237
|
+
parentFolderName === transformation.parentName) ||
|
|
238
|
+
(transformation.type === 'new-composition' &&
|
|
211
239
|
folderName === transformation.folderName &&
|
|
212
240
|
parentFolderName === transformation.parentName));
|
|
213
241
|
if (!isFolderMatch) {
|
|
@@ -224,6 +252,9 @@ const transformLoneJsxElement = (expression, transformation, changesMade, parent
|
|
|
224
252
|
folderName === transformation.folderName &&
|
|
225
253
|
parentFolderName === transformation.parentName) ||
|
|
226
254
|
(transformation.type === 'rename-folder' &&
|
|
255
|
+
folderName === transformation.folderName &&
|
|
256
|
+
parentFolderName === transformation.parentName) ||
|
|
257
|
+
(transformation.type === 'new-composition' &&
|
|
227
258
|
folderName === transformation.folderName &&
|
|
228
259
|
parentFolderName === transformation.parentName);
|
|
229
260
|
if (!isMatch) {
|
|
@@ -318,6 +349,11 @@ const mapJsxChild = (c, transformation, changesMade, parentFolderName) => {
|
|
|
318
349
|
});
|
|
319
350
|
return c.children;
|
|
320
351
|
}
|
|
352
|
+
if (transformation.type === 'new-composition' &&
|
|
353
|
+
folderName === transformation.folderName &&
|
|
354
|
+
parentFolderName === transformation.parentName) {
|
|
355
|
+
return [addNewCompositionToFolder(c, transformation, changesMade)];
|
|
356
|
+
}
|
|
321
357
|
const childParentFolderName = folderName
|
|
322
358
|
? getChildFolderParentName({ folderName, parentFolderName })
|
|
323
359
|
: parentFolderName;
|
|
@@ -330,6 +366,7 @@ const mapRecognizedType = (expression, transformation, changesMade, parentFolder
|
|
|
330
366
|
if (expression.type === 'ArrowFunctionExpression' ||
|
|
331
367
|
expression.type === 'FunctionExpression') {
|
|
332
368
|
if (transformation.type === 'new-composition' &&
|
|
369
|
+
transformation.folderName === null &&
|
|
333
370
|
(expression.body.type === 'JSXElement' ||
|
|
334
371
|
expression.body.type === 'JSXFragment')) {
|
|
335
372
|
return {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SequenceNodePath } from 'remotion';
|
|
2
|
+
export declare const getSplitUnsupportedSequenceTagReason: (tagName: string) => string | null;
|
|
3
|
+
export declare const getIsSplittableSequenceTag: (tagName: string) => boolean;
|
|
4
|
+
export declare const splitJsxSequence: ({ input, nodePath, splitFrame, prettierConfigOverride, }: {
|
|
5
|
+
input: string;
|
|
6
|
+
nodePath: SequenceNodePath;
|
|
7
|
+
splitFrame: number;
|
|
8
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
9
|
+
}) => Promise<{
|
|
10
|
+
output: string;
|
|
11
|
+
formatted: boolean;
|
|
12
|
+
nodeLabel: string;
|
|
13
|
+
logLine: number;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.splitJsxSequence = exports.getIsSplittableSequenceTag = exports.getSplitUnsupportedSequenceTagReason = void 0;
|
|
37
|
+
const types_1 = require("@babel/types");
|
|
38
|
+
const recast = __importStar(require("recast"));
|
|
39
|
+
const delete_jsx_node_1 = require("./delete-jsx-node");
|
|
40
|
+
const format_file_content_1 = require("./format-file-content");
|
|
41
|
+
const parse_ast_1 = require("./parse-ast");
|
|
42
|
+
const { builders: b, namedTypes } = recast.types;
|
|
43
|
+
const jsxId = (name) => ({ type: 'JSXIdentifier', name });
|
|
44
|
+
const numericAttribute = (name, value) => ({
|
|
45
|
+
type: 'JSXAttribute',
|
|
46
|
+
name: jsxId(name),
|
|
47
|
+
value: {
|
|
48
|
+
type: 'JSXExpressionContainer',
|
|
49
|
+
expression: value === Infinity ? b.identifier('Infinity') : b.numericLiteral(value),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const getAttributeName = (attribute) => {
|
|
53
|
+
if (attribute.type !== 'JSXAttribute' ||
|
|
54
|
+
attribute.name.type !== 'JSXIdentifier') {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return attribute.name.name;
|
|
58
|
+
};
|
|
59
|
+
const getStaticNumber = (attribute) => {
|
|
60
|
+
if (attribute.type !== 'JSXAttribute') {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (!attribute.value) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (attribute.value.type === 'StringLiteral') {
|
|
67
|
+
const parsed = Number(attribute.value.value);
|
|
68
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
69
|
+
}
|
|
70
|
+
if (attribute.value.type !== 'JSXExpressionContainer') {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const { expression } = attribute.value;
|
|
74
|
+
if (expression.type === 'NumericLiteral') {
|
|
75
|
+
return expression.value;
|
|
76
|
+
}
|
|
77
|
+
if (expression.type === 'Identifier' && expression.name === 'Infinity') {
|
|
78
|
+
return Infinity;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
};
|
|
82
|
+
const readSequenceTiming = (element) => {
|
|
83
|
+
let from = 0;
|
|
84
|
+
let durationInFrames = Infinity;
|
|
85
|
+
let trimBefore = 0;
|
|
86
|
+
let hasFrom = false;
|
|
87
|
+
let hasDurationInFrames = false;
|
|
88
|
+
let hasTrimBefore = false;
|
|
89
|
+
for (const attribute of element.openingElement.attributes) {
|
|
90
|
+
const name = getAttributeName(attribute);
|
|
91
|
+
if (!name) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (name !== 'from' &&
|
|
95
|
+
name !== 'durationInFrames' &&
|
|
96
|
+
name !== 'trimBefore') {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const value = getStaticNumber(attribute);
|
|
100
|
+
if (value === null) {
|
|
101
|
+
throw new Error(`Cannot split sequence with dynamic ${name}`);
|
|
102
|
+
}
|
|
103
|
+
if (name === 'from') {
|
|
104
|
+
from = value;
|
|
105
|
+
hasFrom = true;
|
|
106
|
+
}
|
|
107
|
+
if (name === 'durationInFrames') {
|
|
108
|
+
durationInFrames = value;
|
|
109
|
+
hasDurationInFrames = true;
|
|
110
|
+
}
|
|
111
|
+
if (name === 'trimBefore') {
|
|
112
|
+
trimBefore = value;
|
|
113
|
+
hasTrimBefore = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
from,
|
|
118
|
+
durationInFrames,
|
|
119
|
+
trimBefore,
|
|
120
|
+
hasFrom,
|
|
121
|
+
hasDurationInFrames,
|
|
122
|
+
hasTrimBefore,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const setNumericAttribute = ({ element, name, value, omitIfMissing, }) => {
|
|
126
|
+
const { openingElement: { attributes }, } = element;
|
|
127
|
+
const index = attributes.findIndex((attribute) => getAttributeName(attribute) === name);
|
|
128
|
+
if (value === null || (index === -1 && omitIfMissing)) {
|
|
129
|
+
if (index !== -1) {
|
|
130
|
+
attributes.splice(index, 1);
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const next = numericAttribute(name, value);
|
|
135
|
+
if (index === -1) {
|
|
136
|
+
attributes.push(next);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
attributes[index] = next;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const timingAttributeOrder = ['from', 'durationInFrames', 'trimBefore'];
|
|
143
|
+
const orderTimingAttributes = (element) => {
|
|
144
|
+
const { openingElement: { attributes }, } = element;
|
|
145
|
+
const timingAttributes = new Map();
|
|
146
|
+
const otherAttributes = [];
|
|
147
|
+
let firstTimingIndex = null;
|
|
148
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
149
|
+
const attribute = attributes[i];
|
|
150
|
+
const name = getAttributeName(attribute);
|
|
151
|
+
if (name && timingAttributeOrder.includes(name)) {
|
|
152
|
+
timingAttributes.set(name, attribute);
|
|
153
|
+
firstTimingIndex = firstTimingIndex === null ? i : firstTimingIndex;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
otherAttributes.push(attribute);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (firstTimingIndex === null) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const orderedTimingAttributes = timingAttributeOrder.flatMap((name) => {
|
|
163
|
+
const attribute = timingAttributes.get(name);
|
|
164
|
+
return attribute ? [attribute] : [];
|
|
165
|
+
});
|
|
166
|
+
const insertionIndex = Math.min(firstTimingIndex, otherAttributes.length);
|
|
167
|
+
attributes.splice(0, attributes.length, ...otherAttributes.slice(0, insertionIndex), ...orderedTimingAttributes, ...otherAttributes.slice(insertionIndex));
|
|
168
|
+
};
|
|
169
|
+
const splittableSequenceTags = new Set([
|
|
170
|
+
'AnimatedImage',
|
|
171
|
+
'Arrow',
|
|
172
|
+
'Audio',
|
|
173
|
+
'Callout',
|
|
174
|
+
'CanvasImage',
|
|
175
|
+
'Circle',
|
|
176
|
+
'Ellipse',
|
|
177
|
+
'Gif',
|
|
178
|
+
'Heart',
|
|
179
|
+
'Html5Audio',
|
|
180
|
+
'Html5Video',
|
|
181
|
+
'HtmlInCanvas',
|
|
182
|
+
'Img',
|
|
183
|
+
'OffthreadVideo',
|
|
184
|
+
'Pie',
|
|
185
|
+
'Polygon',
|
|
186
|
+
'Rect',
|
|
187
|
+
'RemotionRiveCanvas',
|
|
188
|
+
'Sequence',
|
|
189
|
+
'Solid',
|
|
190
|
+
'Spark',
|
|
191
|
+
'Star',
|
|
192
|
+
'Starburst',
|
|
193
|
+
'Triangle',
|
|
194
|
+
'Video',
|
|
195
|
+
]);
|
|
196
|
+
const unsupportedSequenceTags = new Set([
|
|
197
|
+
'Series.Sequence',
|
|
198
|
+
'TransitionSeries.Overlay',
|
|
199
|
+
'TransitionSeries.Sequence',
|
|
200
|
+
]);
|
|
201
|
+
const jsxMemberNameToString = (name) => {
|
|
202
|
+
if (name.type === 'JSXIdentifier') {
|
|
203
|
+
return name.name;
|
|
204
|
+
}
|
|
205
|
+
return `${jsxMemberNameToString(name.object)}.${name.property.name}`;
|
|
206
|
+
};
|
|
207
|
+
const jsxNameToString = (name) => {
|
|
208
|
+
if (name.type === 'JSXNamespacedName') {
|
|
209
|
+
return `${name.namespace.name}:${name.name.name}`;
|
|
210
|
+
}
|
|
211
|
+
return jsxMemberNameToString(name);
|
|
212
|
+
};
|
|
213
|
+
const getSplitUnsupportedSequenceTagReason = (tagName) => {
|
|
214
|
+
if (tagName === 'Series.Sequence' ||
|
|
215
|
+
tagName === 'TransitionSeries.Sequence' ||
|
|
216
|
+
tagName === 'TransitionSeries.Overlay') {
|
|
217
|
+
return `<${tagName}> cannot be split from source`;
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
};
|
|
221
|
+
exports.getSplitUnsupportedSequenceTagReason = getSplitUnsupportedSequenceTagReason;
|
|
222
|
+
const getIsSplittableSequenceTag = (tagName) => {
|
|
223
|
+
if (unsupportedSequenceTags.has(tagName)) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
if (tagName.startsWith('Interactive.')) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return splittableSequenceTags.has(tagName);
|
|
230
|
+
};
|
|
231
|
+
exports.getIsSplittableSequenceTag = getIsSplittableSequenceTag;
|
|
232
|
+
const getSplittableSequenceTagName = (element) => {
|
|
233
|
+
return jsxNameToString(element.openingElement.name);
|
|
234
|
+
};
|
|
235
|
+
const makeFragment = (first, second) => ({
|
|
236
|
+
type: 'JSXFragment',
|
|
237
|
+
openingFragment: { type: 'JSXOpeningFragment' },
|
|
238
|
+
closingFragment: { type: 'JSXClosingFragment' },
|
|
239
|
+
children: [first, second],
|
|
240
|
+
});
|
|
241
|
+
const insertAfter = (parentNode, node, clone) => {
|
|
242
|
+
if (namedTypes.JSXElement.check(parentNode) ||
|
|
243
|
+
namedTypes.JSXFragment.check(parentNode)) {
|
|
244
|
+
const idx = parentNode.children.indexOf(node);
|
|
245
|
+
if (idx !== -1) {
|
|
246
|
+
parentNode.children.splice(idx + 1, 0, clone);
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (namedTypes.ReturnStatement.check(parentNode)) {
|
|
251
|
+
const parent = parentNode;
|
|
252
|
+
if (parent.argument === node) {
|
|
253
|
+
parent.argument = makeFragment(node, clone);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (namedTypes.ArrowFunctionExpression.check(parentNode)) {
|
|
258
|
+
const parent = parentNode;
|
|
259
|
+
if (parent.body === node) {
|
|
260
|
+
parent.body = makeFragment(node, clone);
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
};
|
|
266
|
+
const splitJsxSequence = async ({ input, nodePath, splitFrame, prettierConfigOverride, }) => {
|
|
267
|
+
var _a, _b;
|
|
268
|
+
var _c, _d;
|
|
269
|
+
if (!Number.isInteger(splitFrame)) {
|
|
270
|
+
throw new Error('Split frame must be an integer');
|
|
271
|
+
}
|
|
272
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
273
|
+
const jsxPath = (0, delete_jsx_node_1.findJsxElementPathForDeletion)(ast, nodePath);
|
|
274
|
+
if (!jsxPath) {
|
|
275
|
+
throw new Error('Could not find a JSX sequence at the specified location to split');
|
|
276
|
+
}
|
|
277
|
+
const jsxElement = jsxPath.node;
|
|
278
|
+
const tagName = getSplittableSequenceTagName(jsxElement);
|
|
279
|
+
const unsupportedReason = (0, exports.getSplitUnsupportedSequenceTagReason)(tagName);
|
|
280
|
+
if (unsupportedReason) {
|
|
281
|
+
throw new Error(unsupportedReason);
|
|
282
|
+
}
|
|
283
|
+
if (!(0, exports.getIsSplittableSequenceTag)(tagName)) {
|
|
284
|
+
throw new Error(`<${tagName}> does not support sequence timing props and cannot be split`);
|
|
285
|
+
}
|
|
286
|
+
const timing = readSequenceTiming(jsxElement);
|
|
287
|
+
const finiteEnd = timing.durationInFrames === Infinity
|
|
288
|
+
? Infinity
|
|
289
|
+
: timing.from + timing.durationInFrames;
|
|
290
|
+
if (splitFrame <= timing.from) {
|
|
291
|
+
throw new Error('Cannot split at or before the sequence start');
|
|
292
|
+
}
|
|
293
|
+
if (splitFrame >= finiteEnd) {
|
|
294
|
+
throw new Error('Cannot split at or after the sequence end');
|
|
295
|
+
}
|
|
296
|
+
const right = (0, types_1.cloneNode)(jsxElement, true);
|
|
297
|
+
const leftDuration = splitFrame - timing.from;
|
|
298
|
+
const rightDuration = timing.durationInFrames === Infinity ? Infinity : finiteEnd - splitFrame;
|
|
299
|
+
const rightTrimBefore = timing.trimBefore + leftDuration;
|
|
300
|
+
setNumericAttribute({
|
|
301
|
+
element: jsxElement,
|
|
302
|
+
name: 'durationInFrames',
|
|
303
|
+
value: leftDuration,
|
|
304
|
+
omitIfMissing: false,
|
|
305
|
+
});
|
|
306
|
+
setNumericAttribute({
|
|
307
|
+
element: right,
|
|
308
|
+
name: 'from',
|
|
309
|
+
value: splitFrame,
|
|
310
|
+
omitIfMissing: false,
|
|
311
|
+
});
|
|
312
|
+
setNumericAttribute({
|
|
313
|
+
element: right,
|
|
314
|
+
name: 'durationInFrames',
|
|
315
|
+
value: rightDuration === Infinity ? null : rightDuration,
|
|
316
|
+
omitIfMissing: !timing.hasDurationInFrames,
|
|
317
|
+
});
|
|
318
|
+
setNumericAttribute({
|
|
319
|
+
element: right,
|
|
320
|
+
name: 'trimBefore',
|
|
321
|
+
value: rightTrimBefore === 0 ? null : rightTrimBefore,
|
|
322
|
+
omitIfMissing: !timing.hasTrimBefore && rightTrimBefore === 0,
|
|
323
|
+
});
|
|
324
|
+
orderTimingAttributes(jsxElement);
|
|
325
|
+
orderTimingAttributes(right);
|
|
326
|
+
const { parentPath } = jsxPath;
|
|
327
|
+
if (!parentPath) {
|
|
328
|
+
throw new Error('Cannot split JSX sequence with no parent');
|
|
329
|
+
}
|
|
330
|
+
if (!insertAfter(parentPath.node, jsxElement, right)) {
|
|
331
|
+
jsxPath.replace(makeFragment(jsxElement, right));
|
|
332
|
+
}
|
|
333
|
+
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
334
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
335
|
+
input: finalFile,
|
|
336
|
+
prettierConfigOverride,
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
output,
|
|
340
|
+
formatted,
|
|
341
|
+
nodeLabel: (0, delete_jsx_node_1.getJsxElementTagLabel)(jsxElement),
|
|
342
|
+
logLine: (_d = (_c = (_a = jsxElement.openingElement.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _c !== void 0 ? _c : (_b = jsxElement.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : 1,
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
exports.splitJsxSequence = splitJsxSequence;
|
|
@@ -85,9 +85,59 @@ const snapshotTopLevelAttrs = (node) => {
|
|
|
85
85
|
}
|
|
86
86
|
return result;
|
|
87
87
|
};
|
|
88
|
-
const
|
|
88
|
+
const escapeJsxText = (value) => {
|
|
89
|
+
return value
|
|
90
|
+
.replace(/&/g, '&')
|
|
91
|
+
.replace(/</g, '<')
|
|
92
|
+
.replace(/>/g, '>')
|
|
93
|
+
.replace(/{/g, '{')
|
|
94
|
+
.replace(/}/g, '}');
|
|
95
|
+
};
|
|
96
|
+
const findChildrenAttribute = (node) => {
|
|
97
|
+
var _a;
|
|
98
|
+
return (_a = node.attributes) === null || _a === void 0 ? void 0 : _a.find((attr) => {
|
|
99
|
+
return (attr.type === 'JSXAttribute' &&
|
|
100
|
+
attr.name.type === 'JSXIdentifier' &&
|
|
101
|
+
attr.name.name === 'children');
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const updateJsxTextContent = ({ jsxElement, value, }) => {
|
|
105
|
+
const nextValue = String(value !== null && value !== void 0 ? value : '');
|
|
106
|
+
const staticChildrenAttribute = (0, can_update_sequence_props_1.getStaticJsxChildrenAttribute)(jsxElement.openingElement);
|
|
107
|
+
if (staticChildrenAttribute) {
|
|
108
|
+
const childrenAttribute = findChildrenAttribute(jsxElement.openingElement);
|
|
109
|
+
if (!childrenAttribute) {
|
|
110
|
+
throw new Error('Expected static children attribute to exist');
|
|
111
|
+
}
|
|
112
|
+
childrenAttribute.value = b.stringLiteral(nextValue);
|
|
113
|
+
return staticChildrenAttribute.value;
|
|
114
|
+
}
|
|
115
|
+
if ((0, can_update_sequence_props_1.hasJsxChildrenAttribute)(jsxElement.openingElement)) {
|
|
116
|
+
throw new Error('Cannot update text content because the children attribute is not static text');
|
|
117
|
+
}
|
|
118
|
+
const staticTextContent = (0, can_update_sequence_props_1.getStaticJsxTextContent)(jsxElement);
|
|
119
|
+
if (!staticTextContent) {
|
|
120
|
+
throw new Error('Cannot update text content because JSX children are not static text');
|
|
121
|
+
}
|
|
122
|
+
const canRepresentAsJsxText = staticTextContent.kind === 'jsx-text' &&
|
|
123
|
+
!nextValue.includes('\n') &&
|
|
124
|
+
nextValue.trim() === nextValue;
|
|
125
|
+
if (canRepresentAsJsxText) {
|
|
126
|
+
jsxElement.children = [
|
|
127
|
+
b.jsxText(escapeJsxText(nextValue)),
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
jsxElement.children = [
|
|
132
|
+
b.jsxExpressionContainer(b.stringLiteral(nextValue)),
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
return staticTextContent.value;
|
|
136
|
+
};
|
|
137
|
+
const updateSequencePropsNode = ({ jsxElement, updates, schema, }) => {
|
|
89
138
|
var _a, _b, _c;
|
|
90
139
|
var _d, _e;
|
|
140
|
+
const node = jsxElement.openingElement;
|
|
91
141
|
const logLine = (_d = (_a = node.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _d !== void 0 ? _d : 1;
|
|
92
142
|
const oldValueStrings = [];
|
|
93
143
|
const initialAttrs = snapshotTopLevelAttrs(node);
|
|
@@ -97,6 +147,11 @@ const updateSequencePropsNode = ({ node, updates, schema, }) => {
|
|
|
97
147
|
}));
|
|
98
148
|
for (const { key, value, defaultValue } of updates) {
|
|
99
149
|
let oldValueString = '';
|
|
150
|
+
if (key === 'children') {
|
|
151
|
+
oldValueString = updateJsxTextContent({ jsxElement, value });
|
|
152
|
+
oldValueStrings.push(oldValueString);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
100
155
|
const isDefault = defaultValue !== null &&
|
|
101
156
|
JSON.stringify(value) === JSON.stringify(defaultValue);
|
|
102
157
|
const dotIndex = key.indexOf('.');
|
|
@@ -197,12 +252,12 @@ const updateSequencePropsNode = ({ node, updates, schema, }) => {
|
|
|
197
252
|
};
|
|
198
253
|
const updateSequencePropsAst = ({ input, nodePath, updates, schema, }) => {
|
|
199
254
|
const ast = (0, parse_ast_1.parseAst)(input);
|
|
200
|
-
const
|
|
201
|
-
if (!
|
|
255
|
+
const jsxElement = (0, can_update_sequence_props_1.findJsxElementNodeAtNodePath)(ast, nodePath);
|
|
256
|
+
if (!jsxElement) {
|
|
202
257
|
throw new Error('Could not find a JSX element at the specified line to update');
|
|
203
258
|
}
|
|
204
259
|
const { oldValueStrings, logLine, removedProps } = updateSequencePropsNode({
|
|
205
|
-
|
|
260
|
+
jsxElement,
|
|
206
261
|
updates,
|
|
207
262
|
schema,
|
|
208
263
|
});
|
|
@@ -217,11 +272,11 @@ exports.updateSequencePropsAst = updateSequencePropsAst;
|
|
|
217
272
|
const updateMultipleSequenceProps = async ({ input, changes, prettierConfigOverride, }) => {
|
|
218
273
|
const ast = (0, parse_ast_1.parseAst)(input);
|
|
219
274
|
const results = changes.map(({ nodePath, updates, schema }) => {
|
|
220
|
-
const
|
|
221
|
-
if (!
|
|
275
|
+
const jsxElement = (0, can_update_sequence_props_1.findJsxElementNodeAtNodePath)(ast, nodePath);
|
|
276
|
+
if (!jsxElement) {
|
|
222
277
|
throw new Error('Could not find a JSX element at the specified line to update');
|
|
223
278
|
}
|
|
224
|
-
return updateSequencePropsNode({
|
|
279
|
+
return updateSequencePropsNode({ jsxElement, updates, schema });
|
|
225
280
|
});
|
|
226
281
|
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
227
282
|
input: (0, parse_ast_1.serializeAst)(ast),
|
|
@@ -35,6 +35,7 @@ const reorder_sequence_1 = require("./routes/reorder-sequence");
|
|
|
35
35
|
const restart_studio_1 = require("./routes/restart-studio");
|
|
36
36
|
const save_effect_props_1 = require("./routes/save-effect-props");
|
|
37
37
|
const save_sequence_props_1 = require("./routes/save-sequence-props");
|
|
38
|
+
const split_jsx_sequence_1 = require("./routes/split-jsx-sequence");
|
|
38
39
|
const subscribe_to_default_props_1 = require("./routes/subscribe-to-default-props");
|
|
39
40
|
const subscribe_to_file_existence_1 = require("./routes/subscribe-to-file-existence");
|
|
40
41
|
const subscribe_to_sequence_props_1 = require("./routes/subscribe-to-sequence-props");
|
|
@@ -82,6 +83,7 @@ exports.allApiRoutes = {
|
|
|
82
83
|
'/api/paste-effects': paste_effects_1.pasteEffectsHandler,
|
|
83
84
|
'/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
|
|
84
85
|
'/api/duplicate-jsx-node': duplicate_jsx_node_1.duplicateJsxNodeHandler,
|
|
86
|
+
'/api/split-jsx-sequence': split_jsx_sequence_1.splitJsxSequenceHandler,
|
|
85
87
|
'/api/update-available': update_available_1.handleUpdate,
|
|
86
88
|
'/api/project-info': project_info_1.projectInfoHandler,
|
|
87
89
|
'/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
|
|
@@ -13,8 +13,8 @@ const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
|
13
13
|
const can_update_effect_props_1 = require("./can-update-effect-props");
|
|
14
14
|
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
15
15
|
const log_effect_update_1 = require("./log-updates/log-effect-update");
|
|
16
|
-
const
|
|
17
|
-
const addEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, frame, value, schema, clientId, }, remotionRoot, logLevel, }) => (0,
|
|
16
|
+
const source_file_write_queue_1 = require("./source-file-write-queue");
|
|
17
|
+
const addEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, frame, value, schema, clientId, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
18
18
|
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[add-effect-keyframe] Received request for fileName="${fileName}" effectIndex=${effectIndex} key="${key}" frame=${frame}`);
|
|
19
19
|
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
20
20
|
remotionRoot,
|