@remotion/studio-server 4.0.485 → 4.0.486
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-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/resolve-composition-component.d.ts +1 -0
- package/dist/helpers/resolve-composition-component.js +206 -9
- package/dist/preview-server/routes/apply-codemod.js +19 -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/package.json +6 -6
|
@@ -4,15 +4,41 @@ exports.saveSequencePropsHandler = exports.shouldSuppressHmrForSequencePropEdits
|
|
|
4
4
|
const node_fs_1 = require("node:fs");
|
|
5
5
|
const renderer_1 = require("@remotion/renderer");
|
|
6
6
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
7
|
+
const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
|
|
7
8
|
const update_sequence_props_1 = require("../../codemods/update-sequence-props/update-sequence-props");
|
|
8
9
|
const file_watcher_1 = require("../../file-watcher");
|
|
9
10
|
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
10
11
|
const undo_stack_1 = require("../undo-stack");
|
|
11
12
|
const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
12
13
|
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
14
|
+
const log_effect_update_1 = require("./log-updates/log-effect-update");
|
|
13
15
|
const log_update_1 = require("./log-updates/log-update");
|
|
14
16
|
const source_file_write_queue_1 = require("./source-file-write-queue");
|
|
17
|
+
const parseSequencePropEditValue = (value) => {
|
|
18
|
+
if (value.type === 'undefined') {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(value.serialized);
|
|
22
|
+
};
|
|
23
|
+
const stringifySequencePropEditValue = (value) => {
|
|
24
|
+
if (value === undefined) {
|
|
25
|
+
return 'undefined';
|
|
26
|
+
}
|
|
27
|
+
return JSON.stringify(value);
|
|
28
|
+
};
|
|
29
|
+
const groupBy = (items, getKey) => {
|
|
30
|
+
var _a;
|
|
31
|
+
const groups = new Map();
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
const key = getKey(item);
|
|
34
|
+
const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : [];
|
|
35
|
+
group.push(item);
|
|
36
|
+
groups.set(key, group);
|
|
37
|
+
}
|
|
38
|
+
return [...groups.values()];
|
|
39
|
+
};
|
|
15
40
|
const convertSequencePropEditToCodemodChange = (edit) => {
|
|
41
|
+
var _a;
|
|
16
42
|
return {
|
|
17
43
|
nodePath: edit.nodePath.nodePath,
|
|
18
44
|
updates: [
|
|
@@ -20,6 +46,7 @@ const convertSequencePropEditToCodemodChange = (edit) => {
|
|
|
20
46
|
key: edit.key,
|
|
21
47
|
value: edit.value,
|
|
22
48
|
defaultValue: edit.defaultValue,
|
|
49
|
+
googleFont: ((_a = edit.sourceEdit) === null || _a === void 0 ? void 0 : _a.type) === 'google-font' ? edit.sourceEdit.font : null,
|
|
23
50
|
},
|
|
24
51
|
],
|
|
25
52
|
schema: edit.schema,
|
|
@@ -27,18 +54,21 @@ const convertSequencePropEditToCodemodChange = (edit) => {
|
|
|
27
54
|
};
|
|
28
55
|
exports.convertSequencePropEditToCodemodChange = convertSequencePropEditToCodemodChange;
|
|
29
56
|
const shouldSuppressHmrForSequencePropEdits = (edits) => {
|
|
30
|
-
return edits.every((edit) => edit.key !== 'showInTimeline'
|
|
57
|
+
return edits.every((edit) => edit.key !== 'showInTimeline' &&
|
|
58
|
+
(edit.sourceEdit === null || edit.sourceEdit === undefined));
|
|
31
59
|
};
|
|
32
60
|
exports.shouldSuppressHmrForSequencePropEdits = shouldSuppressHmrForSequencePropEdits;
|
|
33
|
-
const saveSequencePropsHandler = ({ input: { edits, clientId, undoLabel, redoLabel }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
34
|
-
var _a;
|
|
35
|
-
|
|
61
|
+
const saveSequencePropsHandler = ({ input: { edits, movedKeyframes = { sequenceKeyframes: [], effectKeyframes: [] }, clientId, undoLabel, redoLabel, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
62
|
+
var _a, _b, _c;
|
|
63
|
+
const totalKeyframeMoves = movedKeyframes.sequenceKeyframes.length +
|
|
64
|
+
movedKeyframes.effectKeyframes.length;
|
|
65
|
+
if (edits.length === 0 && totalKeyframeMoves === 0) {
|
|
36
66
|
throw new Error('No sequence prop edits to save');
|
|
37
67
|
}
|
|
38
|
-
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request with ${edits.length} edit(s)`);
|
|
68
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request with ${edits.length} edit(s) and ${totalKeyframeMoves} moved keyframe(s)`);
|
|
39
69
|
const editGroups = new Map();
|
|
40
70
|
for (const [index, edit] of edits.entries()) {
|
|
41
|
-
const parsedValue =
|
|
71
|
+
const parsedValue = parseSequencePropEditValue(edit.value);
|
|
42
72
|
const parsedDefaultValue = edit.defaultValue !== null ? JSON.parse(edit.defaultValue) : null;
|
|
43
73
|
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
44
74
|
remotionRoot,
|
|
@@ -48,6 +78,8 @@ const saveSequencePropsHandler = ({ input: { edits, clientId, undoLabel, redoLab
|
|
|
48
78
|
const group = (_a = editGroups.get(absolutePath)) !== null && _a !== void 0 ? _a : {
|
|
49
79
|
fileRelativeToRoot,
|
|
50
80
|
edits: [],
|
|
81
|
+
sequenceKeyframes: [],
|
|
82
|
+
effectKeyframes: [],
|
|
51
83
|
};
|
|
52
84
|
group.edits.push({
|
|
53
85
|
index,
|
|
@@ -55,42 +87,165 @@ const saveSequencePropsHandler = ({ input: { edits, clientId, undoLabel, redoLab
|
|
|
55
87
|
nodePath: edit.nodePath,
|
|
56
88
|
key: edit.key,
|
|
57
89
|
value: parsedValue,
|
|
58
|
-
valueString:
|
|
90
|
+
valueString: stringifySequencePropEditValue(parsedValue),
|
|
59
91
|
defaultValue: parsedDefaultValue,
|
|
60
92
|
defaultValueString: parsedDefaultValue !== null
|
|
61
93
|
? JSON.stringify(parsedDefaultValue)
|
|
62
94
|
: null,
|
|
63
95
|
schema: edit.schema,
|
|
96
|
+
sourceEdit: edit.sourceEdit,
|
|
64
97
|
});
|
|
65
98
|
editGroups.set(absolutePath, group);
|
|
66
99
|
}
|
|
100
|
+
for (const [index, keyframe,] of movedKeyframes.sequenceKeyframes.entries()) {
|
|
101
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
102
|
+
remotionRoot,
|
|
103
|
+
fileName: keyframe.fileName,
|
|
104
|
+
action: 'modify',
|
|
105
|
+
});
|
|
106
|
+
const group = (_b = editGroups.get(absolutePath)) !== null && _b !== void 0 ? _b : {
|
|
107
|
+
fileRelativeToRoot,
|
|
108
|
+
edits: [],
|
|
109
|
+
sequenceKeyframes: [],
|
|
110
|
+
effectKeyframes: [],
|
|
111
|
+
};
|
|
112
|
+
group.sequenceKeyframes.push({ ...keyframe, index });
|
|
113
|
+
editGroups.set(absolutePath, group);
|
|
114
|
+
}
|
|
115
|
+
for (const [index, keyframe] of movedKeyframes.effectKeyframes.entries()) {
|
|
116
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
117
|
+
remotionRoot,
|
|
118
|
+
fileName: keyframe.fileName,
|
|
119
|
+
action: 'modify',
|
|
120
|
+
});
|
|
121
|
+
const group = (_c = editGroups.get(absolutePath)) !== null && _c !== void 0 ? _c : {
|
|
122
|
+
fileRelativeToRoot,
|
|
123
|
+
edits: [],
|
|
124
|
+
sequenceKeyframes: [],
|
|
125
|
+
effectKeyframes: [],
|
|
126
|
+
};
|
|
127
|
+
group.effectKeyframes.push({ ...keyframe, index });
|
|
128
|
+
editGroups.set(absolutePath, group);
|
|
129
|
+
}
|
|
67
130
|
const snapshots = [];
|
|
68
131
|
const outputByPath = new Map();
|
|
69
132
|
const resultByIndex = new Map();
|
|
133
|
+
const sequenceKeyframeLogs = [];
|
|
134
|
+
const effectKeyframeLogs = [];
|
|
70
135
|
for (const [absolutePath, group] of editGroups) {
|
|
71
136
|
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
137
|
+
let output = fileContents;
|
|
138
|
+
let firstLogLine = Number.POSITIVE_INFINITY;
|
|
139
|
+
if (group.edits.length > 0) {
|
|
140
|
+
const { output: sequencePropsOutput, formatted, results: updateResults, } = await (0, update_sequence_props_1.updateMultipleSequenceProps)({
|
|
141
|
+
input: output,
|
|
142
|
+
changes: group.edits.map(exports.convertSequencePropEditToCodemodChange),
|
|
143
|
+
prettierConfigOverride: null,
|
|
144
|
+
});
|
|
145
|
+
output = sequencePropsOutput;
|
|
146
|
+
const firstUpdate = updateResults[0];
|
|
147
|
+
if (firstUpdate) {
|
|
148
|
+
firstLogLine = Math.min(firstLogLine, firstUpdate.logLine);
|
|
149
|
+
}
|
|
150
|
+
for (const [resultIndex, result] of updateResults.entries()) {
|
|
151
|
+
const edit = group.edits[resultIndex];
|
|
152
|
+
resultByIndex.set(edit.index, {
|
|
153
|
+
oldValueString: result.oldValueStrings[0],
|
|
154
|
+
logLine: result.logLine,
|
|
155
|
+
removedProps: result.removedProps,
|
|
156
|
+
formatted,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (const keyframeGroup of groupBy(group.sequenceKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
|
|
161
|
+
const [firstSequenceKeyframe] = keyframeGroup;
|
|
162
|
+
if (!firstSequenceKeyframe) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const updates = groupBy(keyframeGroup, (keyframe) => keyframe.key).map((keyframes) => {
|
|
166
|
+
const [firstMove] = keyframes;
|
|
167
|
+
if (!firstMove) {
|
|
168
|
+
throw new Error('Expected keyframe');
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
key: firstMove.key,
|
|
172
|
+
operation: {
|
|
173
|
+
type: 'move',
|
|
174
|
+
moves: keyframes.map((keyframe) => ({
|
|
175
|
+
fromFrame: keyframe.fromFrame,
|
|
176
|
+
toFrame: keyframe.toFrame,
|
|
177
|
+
})),
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
const result = await (0, update_keyframes_1.updateSequenceKeyframes)({
|
|
182
|
+
input: output,
|
|
183
|
+
nodePath: firstSequenceKeyframe.nodePath.nodePath,
|
|
184
|
+
schema: firstSequenceKeyframe.schema,
|
|
185
|
+
updates,
|
|
186
|
+
});
|
|
187
|
+
output = result.output;
|
|
188
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
189
|
+
for (const [updateIndex, update] of updates.entries()) {
|
|
190
|
+
sequenceKeyframeLogs.push({
|
|
191
|
+
fileRelativeToRoot: group.fileRelativeToRoot,
|
|
192
|
+
line: result.logLine,
|
|
193
|
+
key: update.key,
|
|
194
|
+
oldValueString: result.oldValueStrings[updateIndex],
|
|
195
|
+
newValueString: result.newValueStrings[updateIndex],
|
|
196
|
+
formatted: result.formatted,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const keyframeGroup of groupBy(group.effectKeyframes, (keyframe) => `${JSON.stringify(keyframe.sequenceNodePath.nodePath)}:${keyframe.effectIndex}`)) {
|
|
201
|
+
const [firstEffectKeyframe] = keyframeGroup;
|
|
202
|
+
if (!firstEffectKeyframe) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const updates = groupBy(keyframeGroup, (keyframe) => keyframe.key).map((keyframes) => {
|
|
206
|
+
const [firstMove] = keyframes;
|
|
207
|
+
if (!firstMove) {
|
|
208
|
+
throw new Error('Expected keyframe');
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
key: firstMove.key,
|
|
212
|
+
operation: {
|
|
213
|
+
type: 'move',
|
|
214
|
+
moves: keyframes.map((keyframe) => ({
|
|
215
|
+
fromFrame: keyframe.fromFrame,
|
|
216
|
+
toFrame: keyframe.toFrame,
|
|
217
|
+
})),
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
const result = await (0, update_keyframes_1.updateEffectKeyframes)({
|
|
222
|
+
input: output,
|
|
223
|
+
sequenceNodePath: firstEffectKeyframe.sequenceNodePath.nodePath,
|
|
224
|
+
effectIndex: firstEffectKeyframe.effectIndex,
|
|
225
|
+
schema: firstEffectKeyframe.schema,
|
|
226
|
+
updates,
|
|
227
|
+
});
|
|
228
|
+
output = result.output;
|
|
229
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
230
|
+
for (const [updateIndex, update] of updates.entries()) {
|
|
231
|
+
effectKeyframeLogs.push({
|
|
232
|
+
fileRelativeToRoot: group.fileRelativeToRoot,
|
|
233
|
+
line: result.logLine,
|
|
234
|
+
effectName: result.effectCallee,
|
|
235
|
+
propKey: update.key,
|
|
236
|
+
oldValueString: result.oldValueStrings[updateIndex],
|
|
237
|
+
newValueString: result.newValueStrings[updateIndex],
|
|
238
|
+
formatted: result.formatted,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
78
242
|
outputByPath.set(absolutePath, output);
|
|
79
243
|
snapshots.push({
|
|
80
244
|
filePath: absolutePath,
|
|
81
245
|
oldContents: fileContents,
|
|
82
246
|
newContents: output,
|
|
83
|
-
logLine: firstLogLine,
|
|
247
|
+
logLine: Number.isFinite(firstLogLine) ? firstLogLine : 1,
|
|
84
248
|
});
|
|
85
|
-
for (const [resultIndex, result] of updateResults.entries()) {
|
|
86
|
-
const edit = group.edits[resultIndex];
|
|
87
|
-
resultByIndex.set(edit.index, {
|
|
88
|
-
oldValueString: result.oldValueStrings[0],
|
|
89
|
-
logLine: result.logLine,
|
|
90
|
-
removedProps: result.removedProps,
|
|
91
|
-
formatted,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
249
|
}
|
|
95
250
|
const undoMessage = `↩️ ${undoLabel}`;
|
|
96
251
|
const redoMessage = `↪️ ${redoLabel}`;
|
|
@@ -130,6 +285,35 @@ const saveSequencePropsHandler = ({ input: { edits, clientId, undoLabel, redoLab
|
|
|
130
285
|
});
|
|
131
286
|
}
|
|
132
287
|
}
|
|
288
|
+
for (const log of sequenceKeyframeLogs) {
|
|
289
|
+
(0, log_update_1.logUpdate)({
|
|
290
|
+
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
291
|
+
line: log.line,
|
|
292
|
+
key: log.key,
|
|
293
|
+
oldValueString: log.oldValueString,
|
|
294
|
+
newValueString: log.newValueString,
|
|
295
|
+
defaultValueString: null,
|
|
296
|
+
formatted: log.formatted,
|
|
297
|
+
logLevel,
|
|
298
|
+
removedProps: [],
|
|
299
|
+
addedProps: [],
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
for (const log of effectKeyframeLogs) {
|
|
303
|
+
(0, log_effect_update_1.logEffectUpdate)({
|
|
304
|
+
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
305
|
+
line: log.line,
|
|
306
|
+
effectName: log.effectName,
|
|
307
|
+
propKey: log.propKey,
|
|
308
|
+
oldValueString: log.oldValueString,
|
|
309
|
+
newValueString: log.newValueString,
|
|
310
|
+
defaultValueString: null,
|
|
311
|
+
formatted: log.formatted,
|
|
312
|
+
logLevel,
|
|
313
|
+
removedProps: [],
|
|
314
|
+
addedProps: [],
|
|
315
|
+
});
|
|
316
|
+
}
|
|
133
317
|
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
134
318
|
const results = edits.map((edit) => {
|
|
135
319
|
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
@@ -3,7 +3,7 @@ export interface UndoEntryDescription {
|
|
|
3
3
|
undoMessage: string;
|
|
4
4
|
redoMessage: string;
|
|
5
5
|
}
|
|
6
|
-
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-add' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'duplicate-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'split-jsx-sequence' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'new-composition' | 'duplicate-composition' | 'delete-folder' | 'rename-folder';
|
|
6
|
+
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-add' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'duplicate-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'split-jsx-sequence' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'new-composition' | 'duplicate-composition' | 'move-composition-to-folder' | 'new-folder' | 'delete-folder' | 'rename-folder';
|
|
7
7
|
type UndoEntrySnapshot = {
|
|
8
8
|
filePath: string;
|
|
9
9
|
oldContents: string | null;
|
|
@@ -59,6 +59,10 @@ type UndoEntry = {
|
|
|
59
59
|
entryType: 'new-composition';
|
|
60
60
|
} | {
|
|
61
61
|
entryType: 'duplicate-composition';
|
|
62
|
+
} | {
|
|
63
|
+
entryType: 'move-composition-to-folder';
|
|
64
|
+
} | {
|
|
65
|
+
entryType: 'new-folder';
|
|
62
66
|
} | {
|
|
63
67
|
entryType: 'delete-folder';
|
|
64
68
|
} | {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio-server"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/studio-server",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.486",
|
|
7
7
|
"description": "Run a Remotion Studio with a server backend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"scripts": {
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@babel/parser": "7.24.1",
|
|
28
28
|
"semver": "7.5.3",
|
|
29
29
|
"prettier": "3.8.1",
|
|
30
|
-
"remotion": "4.0.
|
|
30
|
+
"remotion": "4.0.486",
|
|
31
31
|
"recast": "0.23.11",
|
|
32
|
-
"@remotion/bundler": "4.0.
|
|
33
|
-
"@remotion/renderer": "4.0.
|
|
34
|
-
"@remotion/studio-shared": "4.0.
|
|
32
|
+
"@remotion/bundler": "4.0.486",
|
|
33
|
+
"@remotion/renderer": "4.0.486",
|
|
34
|
+
"@remotion/studio-shared": "4.0.486",
|
|
35
35
|
"memfs": "3.4.3",
|
|
36
36
|
"open": "8.4.2"
|
|
37
37
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ast-types": "0.16.1",
|
|
40
40
|
"react": "19.2.3",
|
|
41
41
|
"@types/semver": "7.5.3",
|
|
42
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
42
|
+
"@remotion/eslint-config-internal": "4.0.486",
|
|
43
43
|
"eslint": "9.19.0",
|
|
44
44
|
"@types/node": "20.12.14",
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|