@remotion/studio-server 4.0.499 → 4.0.501
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/update-inline-caption-patches.d.ts +11 -0
- package/dist/codemods/update-inline-caption-patches.js +186 -0
- package/dist/codemods/update-sequence-props/update-sequence-props.js +6 -4
- package/dist/helpers/css-shorthand-properties.d.ts +9 -3
- package/dist/helpers/css-shorthand-properties.js +16 -2
- package/dist/helpers/parse-border-radius-shorthand.d.ts +7 -0
- package/dist/helpers/parse-border-radius-shorthand.js +53 -0
- package/dist/helpers/resolve-composition-component.js +62 -46
- package/dist/preview-server/api-routes.js +4 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +79 -3
- package/dist/preview-server/routes/find-in-file.d.ts +4 -0
- package/dist/preview-server/routes/find-in-file.js +22 -0
- package/dist/preview-server/routes/insert-element.js +35 -15
- package/dist/preview-server/routes/save-multiple-effect-props.d.ts +3 -0
- package/dist/preview-server/routes/save-multiple-effect-props.js +171 -0
- package/dist/preview-server/routes/save-sequence-props.js +73 -8
- package/package.json +8 -7
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CaptionPatch } from '@remotion/studio-shared';
|
|
2
|
+
import type { SequenceNodePath } from 'remotion';
|
|
3
|
+
export declare const updateInlineCaptionPatches: ({ input, nodePath, patches, }: {
|
|
4
|
+
input: string;
|
|
5
|
+
nodePath: SequenceNodePath;
|
|
6
|
+
patches: CaptionPatch[];
|
|
7
|
+
}) => {
|
|
8
|
+
output: string;
|
|
9
|
+
logLine: number;
|
|
10
|
+
changedFields: string[][];
|
|
11
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateInlineCaptionPatches = void 0;
|
|
4
|
+
const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
|
|
5
|
+
const parse_ast_1 = require("./parse-ast");
|
|
6
|
+
const captionKeys = [
|
|
7
|
+
'text',
|
|
8
|
+
'startMs',
|
|
9
|
+
'endMs',
|
|
10
|
+
'timestampMs',
|
|
11
|
+
'confidence',
|
|
12
|
+
];
|
|
13
|
+
const getPropertyKey = (property) => {
|
|
14
|
+
if (property.key.type === 'Identifier') {
|
|
15
|
+
return property.key.name;
|
|
16
|
+
}
|
|
17
|
+
if (property.key.type === 'StringLiteral') {
|
|
18
|
+
return property.key.value;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
const getStaticValue = (value) => {
|
|
23
|
+
if (value.type === 'StringLiteral' || value.type === 'NumericLiteral') {
|
|
24
|
+
return value.value;
|
|
25
|
+
}
|
|
26
|
+
if (value.type === 'NullLiteral') {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
throw new Error('Captions must use static literal values to be edited');
|
|
30
|
+
};
|
|
31
|
+
const getStaticCaption = (expression) => {
|
|
32
|
+
const values = new Map();
|
|
33
|
+
for (const property of expression.properties) {
|
|
34
|
+
if (property.type !== 'ObjectProperty' || property.computed) {
|
|
35
|
+
throw new Error('Captions must use static object properties to be edited');
|
|
36
|
+
}
|
|
37
|
+
const key = getPropertyKey(property);
|
|
38
|
+
if (key !== null && captionKeys.includes(key)) {
|
|
39
|
+
values.set(key, getStaticValue(property.value));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const text = values.get('text');
|
|
43
|
+
const startMs = values.get('startMs');
|
|
44
|
+
const endMs = values.get('endMs');
|
|
45
|
+
const timestampMs = values.get('timestampMs');
|
|
46
|
+
const confidence = values.get('confidence');
|
|
47
|
+
if (typeof text !== 'string' ||
|
|
48
|
+
typeof startMs !== 'number' ||
|
|
49
|
+
typeof endMs !== 'number' ||
|
|
50
|
+
(timestampMs !== null && typeof timestampMs !== 'number') ||
|
|
51
|
+
(confidence !== null && typeof confidence !== 'number')) {
|
|
52
|
+
throw new Error('Captions must have the standard static caption shape to edit');
|
|
53
|
+
}
|
|
54
|
+
return { text, startMs, endMs, timestampMs, confidence };
|
|
55
|
+
};
|
|
56
|
+
const isCaptionKey = (key) => captionKeys.includes(key);
|
|
57
|
+
const getReplacementValue = ({ value, previous, }) => {
|
|
58
|
+
var _a;
|
|
59
|
+
if (value === null || typeof value === 'number') {
|
|
60
|
+
return String(value);
|
|
61
|
+
}
|
|
62
|
+
if (previous.type === 'StringLiteral' &&
|
|
63
|
+
typeof ((_a = previous.extra) === null || _a === void 0 ? void 0 : _a.raw) === 'string' &&
|
|
64
|
+
previous.extra.raw.startsWith("'")) {
|
|
65
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
66
|
+
}
|
|
67
|
+
return JSON.stringify(value);
|
|
68
|
+
};
|
|
69
|
+
const getSourceValueRange = ({ input, property, key, }) => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const line = (_a = property.loc) === null || _a === void 0 ? void 0 : _a.start.line;
|
|
72
|
+
if (line === null || line === undefined) {
|
|
73
|
+
throw new Error(`Could not locate caption ${key} in the source file`);
|
|
74
|
+
}
|
|
75
|
+
const lines = input.split('\n');
|
|
76
|
+
const lineStart = lines
|
|
77
|
+
.slice(0, line - 1)
|
|
78
|
+
.reduce((length, current) => length + current.length + 1, 0);
|
|
79
|
+
const sourceLine = lines[line - 1];
|
|
80
|
+
if (sourceLine === undefined) {
|
|
81
|
+
throw new Error(`Could not locate caption ${key} in the source file`);
|
|
82
|
+
}
|
|
83
|
+
const keyStart = sourceLine.indexOf(key);
|
|
84
|
+
const valueStart = sourceLine.indexOf(':', keyStart) + 1;
|
|
85
|
+
const rawValue = property.value.type === 'StringLiteral' &&
|
|
86
|
+
typeof ((_b = property.value.extra) === null || _b === void 0 ? void 0 : _b.raw) === 'string'
|
|
87
|
+
? property.value.extra.raw
|
|
88
|
+
: property.value.type === 'StringLiteral'
|
|
89
|
+
? JSON.stringify(property.value.value)
|
|
90
|
+
: String(getStaticValue(property.value));
|
|
91
|
+
const valueOffset = sourceLine.indexOf(rawValue, valueStart);
|
|
92
|
+
if (keyStart === -1 || valueOffset === -1) {
|
|
93
|
+
throw new Error(`Could not locate caption ${key} in the source file`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
start: lineStart + valueOffset,
|
|
97
|
+
end: lineStart + valueOffset + rawValue.length,
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
const updateCaption = ({ input, caption, patch, }) => {
|
|
101
|
+
const current = getStaticCaption(caption);
|
|
102
|
+
if (!captionKeys.every((key) => current[key] === patch.before[key])) {
|
|
103
|
+
throw new Error(`Caption ${patch.index} changed in the source file before this edit could be saved`);
|
|
104
|
+
}
|
|
105
|
+
const changedKeys = Object.keys(patch.changes);
|
|
106
|
+
if (changedKeys.length === 0 || !changedKeys.every(isCaptionKey)) {
|
|
107
|
+
throw new Error('Caption patches must change at least one caption field');
|
|
108
|
+
}
|
|
109
|
+
const replacements = [];
|
|
110
|
+
for (const key of changedKeys) {
|
|
111
|
+
const value = patch.changes[key];
|
|
112
|
+
if ((key === 'text' && typeof value !== 'string') ||
|
|
113
|
+
((key === 'startMs' || key === 'endMs') &&
|
|
114
|
+
(typeof value !== 'number' || !Number.isFinite(value))) ||
|
|
115
|
+
((key === 'timestampMs' || key === 'confidence') &&
|
|
116
|
+
value !== null &&
|
|
117
|
+
(typeof value !== 'number' || !Number.isFinite(value)))) {
|
|
118
|
+
throw new Error(`Caption ${key} has an invalid value`);
|
|
119
|
+
}
|
|
120
|
+
const property = caption.properties.find((candidate) => {
|
|
121
|
+
return (candidate.type === 'ObjectProperty' &&
|
|
122
|
+
!candidate.computed &&
|
|
123
|
+
getPropertyKey(candidate) === key);
|
|
124
|
+
});
|
|
125
|
+
if (!property || property.type !== 'ObjectProperty') {
|
|
126
|
+
throw new Error(`Caption ${patch.index} is missing ${key}`);
|
|
127
|
+
}
|
|
128
|
+
const { start, end } = getSourceValueRange({ input, property, key });
|
|
129
|
+
replacements.push({
|
|
130
|
+
start,
|
|
131
|
+
end,
|
|
132
|
+
value: getReplacementValue({
|
|
133
|
+
value: value,
|
|
134
|
+
previous: property.value,
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return { changedFields: changedKeys, replacements };
|
|
139
|
+
};
|
|
140
|
+
const updateInlineCaptionPatches = ({ input, nodePath, patches, }) => {
|
|
141
|
+
var _a, _b, _c;
|
|
142
|
+
var _d;
|
|
143
|
+
if (patches.length === 0) {
|
|
144
|
+
throw new Error('Expected at least one caption patch');
|
|
145
|
+
}
|
|
146
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
147
|
+
const jsxElement = (0, can_update_sequence_props_1.findJsxElementNodeAtNodePath)(ast, nodePath);
|
|
148
|
+
if (!jsxElement) {
|
|
149
|
+
throw new Error('Could not find a JSX element at the specified line to update');
|
|
150
|
+
}
|
|
151
|
+
const captionsAttribute = (_a = jsxElement.openingElement.attributes) === null || _a === void 0 ? void 0 : _a.find((attribute) => attribute.type === 'JSXAttribute' &&
|
|
152
|
+
attribute.name.type === 'JSXIdentifier' &&
|
|
153
|
+
attribute.name.name === 'captions');
|
|
154
|
+
if (!captionsAttribute ||
|
|
155
|
+
captionsAttribute.type !== 'JSXAttribute' ||
|
|
156
|
+
((_b = captionsAttribute.value) === null || _b === void 0 ? void 0 : _b.type) !== 'JSXExpressionContainer' ||
|
|
157
|
+
captionsAttribute.value.expression.type !== 'ArrayExpression') {
|
|
158
|
+
throw new Error('Captions must be an inline JSX array to edit them');
|
|
159
|
+
}
|
|
160
|
+
const captions = captionsAttribute.value.expression.elements;
|
|
161
|
+
const changedFields = [];
|
|
162
|
+
const replacements = [];
|
|
163
|
+
for (const patch of patches) {
|
|
164
|
+
if (!Number.isInteger(patch.index) || patch.index < 0) {
|
|
165
|
+
throw new Error('Caption patch index must be a non-negative integer');
|
|
166
|
+
}
|
|
167
|
+
const caption = captions[patch.index];
|
|
168
|
+
if (!caption || caption.type !== 'ObjectExpression') {
|
|
169
|
+
throw new Error(`Could not find inline caption ${patch.index}`);
|
|
170
|
+
}
|
|
171
|
+
const result = updateCaption({ input, caption, patch });
|
|
172
|
+
changedFields.push(result.changedFields);
|
|
173
|
+
replacements.push(...result.replacements);
|
|
174
|
+
}
|
|
175
|
+
const output = replacements
|
|
176
|
+
.sort((a, b) => b.start - a.start)
|
|
177
|
+
.reduce((current, replacement) => current.slice(0, replacement.start) +
|
|
178
|
+
replacement.value +
|
|
179
|
+
current.slice(replacement.end), input);
|
|
180
|
+
return {
|
|
181
|
+
output,
|
|
182
|
+
logLine: (_d = (_c = jsxElement.openingElement.loc) === null || _c === void 0 ? void 0 : _c.start.line) !== null && _d !== void 0 ? _d : 1,
|
|
183
|
+
changedFields,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
exports.updateInlineCaptionPatches = updateInlineCaptionPatches;
|
|
@@ -498,10 +498,12 @@ const migrateCssShorthand = ({ node, cssShorthand, }) => {
|
|
|
498
498
|
}
|
|
499
499
|
const shorthandValue = property.value.type === 'StringLiteral'
|
|
500
500
|
? property.value.value
|
|
501
|
-
: property.value.type === '
|
|
502
|
-
property.value.
|
|
503
|
-
|
|
504
|
-
|
|
501
|
+
: property.value.type === 'NumericLiteral'
|
|
502
|
+
? property.value.value
|
|
503
|
+
: property.value.type === 'TemplateLiteral' &&
|
|
504
|
+
property.value.expressions.length === 0
|
|
505
|
+
? ((_d = (_c = property.value.quasis[0]) === null || _c === void 0 ? void 0 : _c.value.cooked) !== null && _d !== void 0 ? _d : null)
|
|
506
|
+
: null;
|
|
505
507
|
if (shorthandValue === null) {
|
|
506
508
|
continue;
|
|
507
509
|
}
|
|
@@ -3,20 +3,26 @@ export type CssShorthandProperty = {
|
|
|
3
3
|
readonly parentKey: string;
|
|
4
4
|
readonly shorthand: string;
|
|
5
5
|
readonly longhands: readonly string[];
|
|
6
|
-
readonly parse: (value:
|
|
6
|
+
readonly parse: (value: unknown) => ParsedCssShorthand | null;
|
|
7
7
|
readonly isUnsupportedProperty: (propertyName: string) => boolean;
|
|
8
8
|
};
|
|
9
9
|
export declare const cssShorthandProperties: readonly [{
|
|
10
10
|
readonly parentKey: "style";
|
|
11
11
|
readonly shorthand: "background";
|
|
12
12
|
readonly longhands: readonly ["backgroundColor", "backgroundImage", "backgroundPosition", "backgroundSize", "backgroundRepeat", "backgroundOrigin", "backgroundClip", "backgroundAttachment"];
|
|
13
|
-
readonly parse: (value:
|
|
13
|
+
readonly parse: (value: unknown) => import("./parse-background-shorthand").ParsedBackgroundShorthand | null;
|
|
14
14
|
readonly isUnsupportedProperty: () => false;
|
|
15
15
|
}, {
|
|
16
16
|
readonly parentKey: "style";
|
|
17
17
|
readonly shorthand: "border";
|
|
18
18
|
readonly longhands: readonly ["borderWidth", "borderStyle", "borderColor"];
|
|
19
|
-
readonly parse: (value:
|
|
19
|
+
readonly parse: (value: unknown) => import("./parse-border-shorthand").ParsedBorderShorthand | null;
|
|
20
|
+
readonly isUnsupportedProperty: (propertyName: string) => boolean;
|
|
21
|
+
}, {
|
|
22
|
+
readonly parentKey: "style";
|
|
23
|
+
readonly shorthand: "borderRadius";
|
|
24
|
+
readonly longhands: readonly ["borderTopLeftRadius", "borderTopRightRadius", "borderBottomRightRadius", "borderBottomLeftRadius"];
|
|
25
|
+
readonly parse: (value: unknown) => import("./parse-border-radius-shorthand").ParsedBorderRadiusShorthand | null;
|
|
20
26
|
readonly isUnsupportedProperty: (propertyName: string) => boolean;
|
|
21
27
|
}];
|
|
22
28
|
export declare const getCssShorthandForLonghand: ({ parentKey, longhand, }: {
|
|
@@ -2,15 +2,28 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCssShorthandsForUpdates = exports.getCssShorthandForLonghand = exports.cssShorthandProperties = void 0;
|
|
4
4
|
const parse_background_shorthand_1 = require("./parse-background-shorthand");
|
|
5
|
+
const parse_border_radius_shorthand_1 = require("./parse-border-radius-shorthand");
|
|
5
6
|
const parse_border_shorthand_1 = require("./parse-border-shorthand");
|
|
6
7
|
const borderSidePropertyRegex = /^border(?:Top|Right|Bottom|Left)(?:Width|Style|Color)?$/;
|
|
7
8
|
const borderShorthand = {
|
|
8
9
|
parentKey: 'style',
|
|
9
10
|
shorthand: 'border',
|
|
10
11
|
longhands: ['borderWidth', 'borderStyle', 'borderColor'],
|
|
11
|
-
parse: parse_border_shorthand_1.parseBorderShorthand,
|
|
12
|
+
parse: (value) => typeof value === 'string' ? (0, parse_border_shorthand_1.parseBorderShorthand)(value) : null,
|
|
12
13
|
isUnsupportedProperty: (propertyName) => borderSidePropertyRegex.test(propertyName),
|
|
13
14
|
};
|
|
15
|
+
const borderRadiusShorthand = {
|
|
16
|
+
parentKey: 'style',
|
|
17
|
+
shorthand: 'borderRadius',
|
|
18
|
+
longhands: [
|
|
19
|
+
'borderTopLeftRadius',
|
|
20
|
+
'borderTopRightRadius',
|
|
21
|
+
'borderBottomRightRadius',
|
|
22
|
+
'borderBottomLeftRadius',
|
|
23
|
+
],
|
|
24
|
+
parse: parse_border_radius_shorthand_1.parseBorderRadiusShorthand,
|
|
25
|
+
isUnsupportedProperty: (propertyName) => /^border(?:StartStart|StartEnd|EndStart|EndEnd)Radius$/.test(propertyName),
|
|
26
|
+
};
|
|
14
27
|
const backgroundShorthand = {
|
|
15
28
|
parentKey: 'style',
|
|
16
29
|
shorthand: 'background',
|
|
@@ -24,12 +37,13 @@ const backgroundShorthand = {
|
|
|
24
37
|
'backgroundClip',
|
|
25
38
|
'backgroundAttachment',
|
|
26
39
|
],
|
|
27
|
-
parse: parse_background_shorthand_1.parseBackgroundShorthand,
|
|
40
|
+
parse: (value) => typeof value === 'string' ? (0, parse_background_shorthand_1.parseBackgroundShorthand)(value) : null,
|
|
28
41
|
isUnsupportedProperty: () => false,
|
|
29
42
|
};
|
|
30
43
|
exports.cssShorthandProperties = [
|
|
31
44
|
backgroundShorthand,
|
|
32
45
|
borderShorthand,
|
|
46
|
+
borderRadiusShorthand,
|
|
33
47
|
];
|
|
34
48
|
const getCssShorthandForLonghand = ({ parentKey, longhand, }) => {
|
|
35
49
|
var _a;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ParsedBorderRadiusShorthand = {
|
|
2
|
+
borderTopLeftRadius: number;
|
|
3
|
+
borderTopRightRadius: number;
|
|
4
|
+
borderBottomRightRadius: number;
|
|
5
|
+
borderBottomLeftRadius: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const parseBorderRadiusShorthand: (value: unknown) => ParsedBorderRadiusShorthand | null;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseBorderRadiusShorthand = void 0;
|
|
4
|
+
const parsePixelRadius = (value) => {
|
|
5
|
+
if (value === '0') {
|
|
6
|
+
return 0;
|
|
7
|
+
}
|
|
8
|
+
const match = value.match(/^(\d+(?:\.\d+)?|\.\d+)px$/i);
|
|
9
|
+
return match ? Number(match[1]) : null;
|
|
10
|
+
};
|
|
11
|
+
const expandBorderRadius = (values) => {
|
|
12
|
+
if (values.length === 1) {
|
|
13
|
+
return [values[0], values[0], values[0], values[0]];
|
|
14
|
+
}
|
|
15
|
+
if (values.length === 2) {
|
|
16
|
+
return [values[0], values[1], values[0], values[1]];
|
|
17
|
+
}
|
|
18
|
+
if (values.length === 3) {
|
|
19
|
+
return [values[0], values[1], values[2], values[1]];
|
|
20
|
+
}
|
|
21
|
+
return [values[0], values[1], values[2], values[3]];
|
|
22
|
+
};
|
|
23
|
+
const parseBorderRadiusShorthand = (value) => {
|
|
24
|
+
let values;
|
|
25
|
+
if (typeof value === 'number') {
|
|
26
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
values = [value];
|
|
30
|
+
}
|
|
31
|
+
else if (typeof value === 'string') {
|
|
32
|
+
const tokens = value.trim().split(/\s+/);
|
|
33
|
+
if (tokens.length < 1 || tokens.length > 4) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const parsed = tokens.map(parsePixelRadius);
|
|
37
|
+
if (parsed.some((radius) => radius === null)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
values = parsed;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const [topLeft, topRight, bottomRight, bottomLeft] = expandBorderRadius(values);
|
|
46
|
+
return {
|
|
47
|
+
borderTopLeftRadius: topLeft,
|
|
48
|
+
borderTopRightRadius: topRight,
|
|
49
|
+
borderBottomRightRadius: bottomRight,
|
|
50
|
+
borderBottomLeftRadius: bottomLeft,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
exports.parseBorderRadiusShorthand = parseBorderRadiusShorthand;
|
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.insertJsxElementIntoComposition = exports.resolveCompositionComponent = exports.resolveCompositionComponentWithFile = 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_codemods_1 = require("@remotion/studio-codemods");
|
|
42
43
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
43
44
|
const recast = __importStar(require("recast"));
|
|
44
45
|
const no_react_1 = require("remotion/no-react");
|
|
@@ -1427,56 +1428,71 @@ const insertJsxElementIntoComposition = async ({ remotionRoot, compositionFile,
|
|
|
1427
1428
|
remotionRoot,
|
|
1428
1429
|
fileName: location.fileName,
|
|
1429
1430
|
});
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
? {
|
|
1437
|
-
dimensions: { width: element.width, height: element.height },
|
|
1438
|
-
durationInFrames: element.durationInFrames,
|
|
1439
|
-
name: element.compositionId,
|
|
1431
|
+
let finalFile;
|
|
1432
|
+
let logLine;
|
|
1433
|
+
if (element.type === 'solid' && from === null && wrapInSequence === null) {
|
|
1434
|
+
const inserted = (0, studio_codemods_1.insertSolidIntoSource)({
|
|
1435
|
+
exportName: location.exportName,
|
|
1436
|
+
height: element.height,
|
|
1440
1437
|
position: element.position,
|
|
1441
|
-
|
|
1438
|
+
source: input,
|
|
1439
|
+
width: element.width,
|
|
1440
|
+
});
|
|
1441
|
+
finalFile = inserted.output;
|
|
1442
|
+
logLine = inserted.line;
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
1446
|
+
if (element.type === 'composition' &&
|
|
1447
|
+
element.compositionId === compositionId) {
|
|
1448
|
+
throw new Error('Cannot insert a composition into itself');
|
|
1442
1449
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
: {
|
|
1449
|
-
dimensions: null,
|
|
1450
|
-
durationInFrames: null,
|
|
1451
|
-
name: null,
|
|
1450
|
+
const sequenceWrapper = element.type === 'composition'
|
|
1451
|
+
? {
|
|
1452
|
+
dimensions: { width: element.width, height: element.height },
|
|
1453
|
+
durationInFrames: element.durationInFrames,
|
|
1454
|
+
name: element.compositionId,
|
|
1452
1455
|
position: element.position,
|
|
1453
1456
|
from,
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1457
|
+
}
|
|
1458
|
+
: from === null ||
|
|
1459
|
+
element.type === 'asset' ||
|
|
1460
|
+
element.type === 'svg' ||
|
|
1461
|
+
element.type === 'component'
|
|
1462
|
+
? wrapInSequence
|
|
1463
|
+
: {
|
|
1464
|
+
dimensions: null,
|
|
1465
|
+
durationInFrames: null,
|
|
1466
|
+
name: null,
|
|
1467
|
+
position: element.position,
|
|
1468
|
+
from,
|
|
1469
|
+
};
|
|
1470
|
+
const elementToInsert = await createInsertableJsxElement({
|
|
1471
|
+
addPositionStyleToComponent: sequenceWrapper === null,
|
|
1472
|
+
ast,
|
|
1473
|
+
destinationFileName: location.fileName,
|
|
1474
|
+
element,
|
|
1475
|
+
from,
|
|
1476
|
+
remotionRoot,
|
|
1477
|
+
});
|
|
1478
|
+
const finalElementToInsert = sequenceWrapper
|
|
1479
|
+
? createSequenceWrappedElement({
|
|
1480
|
+
child: elementToInsert,
|
|
1481
|
+
dimensions: sequenceWrapper.dimensions,
|
|
1482
|
+
durationInFrames: (_a = sequenceWrapper.durationInFrames) !== null && _a !== void 0 ? _a : null,
|
|
1483
|
+
from: sequenceWrapper.from,
|
|
1484
|
+
name: sequenceWrapper.name,
|
|
1485
|
+
position: sequenceWrapper.position,
|
|
1486
|
+
sequenceLocalName: ensureSequenceImport(ast),
|
|
1487
|
+
})
|
|
1488
|
+
: elementToInsert;
|
|
1489
|
+
logLine = addElementToComponentRoot({
|
|
1490
|
+
ast,
|
|
1491
|
+
exportName: location.exportName,
|
|
1492
|
+
element: finalElementToInsert,
|
|
1493
|
+
});
|
|
1494
|
+
finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
1495
|
+
}
|
|
1480
1496
|
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
1481
1497
|
input: finalFile,
|
|
1482
1498
|
prettierConfigOverride,
|
|
@@ -19,6 +19,7 @@ const delete_static_file_1 = require("./routes/delete-static-file");
|
|
|
19
19
|
const download_remote_asset_1 = require("./routes/download-remote-asset");
|
|
20
20
|
const duplicate_effect_1 = require("./routes/duplicate-effect");
|
|
21
21
|
const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
|
|
22
|
+
const find_in_file_1 = require("./routes/find-in-file");
|
|
22
23
|
const insert_element_1 = require("./routes/insert-element");
|
|
23
24
|
const insert_jsx_element_1 = require("./routes/insert-jsx-element");
|
|
24
25
|
const install_dependency_1 = require("./routes/install-dependency");
|
|
@@ -36,6 +37,7 @@ const reorder_effect_1 = require("./routes/reorder-effect");
|
|
|
36
37
|
const reorder_sequence_1 = require("./routes/reorder-sequence");
|
|
37
38
|
const restart_studio_1 = require("./routes/restart-studio");
|
|
38
39
|
const save_effect_props_1 = require("./routes/save-effect-props");
|
|
40
|
+
const save_multiple_effect_props_1 = require("./routes/save-multiple-effect-props");
|
|
39
41
|
const save_sequence_props_1 = require("./routes/save-sequence-props");
|
|
40
42
|
const split_jsx_sequence_1 = require("./routes/split-jsx-sequence");
|
|
41
43
|
const subscribe_to_default_props_1 = require("./routes/subscribe-to-default-props");
|
|
@@ -61,6 +63,7 @@ exports.allApiRoutes = {
|
|
|
61
63
|
'/api/subscribe-to-file-existence': subscribe_to_file_existence_1.subscribeToFileExistence,
|
|
62
64
|
'/api/remove-render': remove_render_1.handleRemoveRender,
|
|
63
65
|
'/api/open-in-editor': open_in_editor_1.openInEditorHandler,
|
|
66
|
+
'/api/find-in-file': find_in_file_1.findInFileHandler,
|
|
64
67
|
'/api/open-in-file-explorer': open_in_file_explorer_1.handleOpenInFileExplorer,
|
|
65
68
|
'/api/register-client-render': register_client_render_1.registerClientRenderHandler,
|
|
66
69
|
'/api/unregister-client-render': unregister_client_render_1.unregisterClientRenderHandler,
|
|
@@ -73,6 +76,7 @@ exports.allApiRoutes = {
|
|
|
73
76
|
'/api/unsubscribe-from-sequence-props': unsubscribe_from_sequence_props_1.unsubscribeFromSequenceProps,
|
|
74
77
|
'/api/save-sequence-props': save_sequence_props_1.saveSequencePropsHandler,
|
|
75
78
|
'/api/save-effect-props': save_effect_props_1.saveEffectPropsHandler,
|
|
79
|
+
'/api/save-multiple-effect-props': save_multiple_effect_props_1.saveMultipleEffectPropsHandler,
|
|
76
80
|
'/api/add-effect': add_effect_1.addEffectHandler,
|
|
77
81
|
'/api/reorder-effect': reorder_effect_1.reorderEffectHandler,
|
|
78
82
|
'/api/duplicate-effect': duplicate_effect_1.duplicateEffectHandler,
|
|
@@ -43,6 +43,7 @@ const parse_ast_1 = require("../../codemods/parse-ast");
|
|
|
43
43
|
const css_shorthand_properties_1 = require("../../helpers/css-shorthand-properties");
|
|
44
44
|
const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
|
|
45
45
|
const import_agnostic_node_path_1 = require("../../helpers/import-agnostic-node-path");
|
|
46
|
+
const parse_border_radius_shorthand_1 = require("../../helpers/parse-border-radius-shorthand");
|
|
46
47
|
const parse_keyframe_easing_expression_1 = require("../../helpers/parse-keyframe-easing-expression");
|
|
47
48
|
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
48
49
|
const video_config_numeric_expression_1 = require("../../helpers/video-config-numeric-expression");
|
|
@@ -679,6 +680,70 @@ const getObjectPropertyName = (property) => {
|
|
|
679
680
|
}
|
|
680
681
|
return null;
|
|
681
682
|
};
|
|
683
|
+
const BORDER_RADIUS_SHORTHAND = 'borderRadius';
|
|
684
|
+
const BORDER_RADIUS_LONGHANDS = [
|
|
685
|
+
'borderTopLeftRadius',
|
|
686
|
+
'borderTopRightRadius',
|
|
687
|
+
'borderBottomRightRadius',
|
|
688
|
+
'borderBottomLeftRadius',
|
|
689
|
+
];
|
|
690
|
+
const BORDER_RADIUS_PROPERTIES = new Set([
|
|
691
|
+
BORDER_RADIUS_SHORTHAND,
|
|
692
|
+
...BORDER_RADIUS_LONGHANDS,
|
|
693
|
+
]);
|
|
694
|
+
const hasMixedBorderRadiusRepresentation = (jsxElement) => {
|
|
695
|
+
var _a;
|
|
696
|
+
const style = jsxElement.attributes.find((attribute) => attribute.type === 'JSXAttribute' &&
|
|
697
|
+
attribute.name.type !== 'JSXNamespacedName' &&
|
|
698
|
+
attribute.name.name === 'style');
|
|
699
|
+
if (!style ||
|
|
700
|
+
style.type !== 'JSXAttribute' ||
|
|
701
|
+
((_a = style.value) === null || _a === void 0 ? void 0 : _a.type) !== 'JSXExpressionContainer' ||
|
|
702
|
+
style.value.expression.type !== 'ObjectExpression') {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
let hasShorthand = false;
|
|
706
|
+
let hasLonghand = false;
|
|
707
|
+
for (const property of style.value.expression.properties) {
|
|
708
|
+
if (property.type !== 'ObjectProperty') {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const name = getObjectPropertyName(property);
|
|
712
|
+
hasShorthand || (hasShorthand = name === BORDER_RADIUS_SHORTHAND);
|
|
713
|
+
hasLonghand || (hasLonghand = BORDER_RADIUS_LONGHANDS.some((longhand) => longhand === name));
|
|
714
|
+
}
|
|
715
|
+
return hasShorthand && hasLonghand;
|
|
716
|
+
};
|
|
717
|
+
const getUniformBorderRadius = (value) => {
|
|
718
|
+
const parsed = (0, parse_border_radius_shorthand_1.parseBorderRadiusShorthand)(value);
|
|
719
|
+
if (!parsed) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
const values = Object.values(parsed);
|
|
723
|
+
return values.every((radius) => radius === values[0]) ? values[0] : null;
|
|
724
|
+
};
|
|
725
|
+
const getBorderRadiusShorthandStatus = ({ propValue, ast, videoConfigValues, }) => {
|
|
726
|
+
if ((0, exports.isStaticValue)(propValue)) {
|
|
727
|
+
const uniform = getUniformBorderRadius((0, exports.extractStaticValue)(propValue));
|
|
728
|
+
return uniform === null ? computedStatus() : staticStatus(uniform, null);
|
|
729
|
+
}
|
|
730
|
+
const numericExpression = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
|
|
731
|
+
node: propValue,
|
|
732
|
+
videoConfigValues,
|
|
733
|
+
});
|
|
734
|
+
if (numericExpression !== null && numericExpression.value >= 0) {
|
|
735
|
+
return staticStatus(numericExpression.value, numericExpression);
|
|
736
|
+
}
|
|
737
|
+
const computed = (0, exports.getComputedStatus)(propValue, ast, videoConfigValues);
|
|
738
|
+
if (computed.status === 'keyframed' &&
|
|
739
|
+
computed.interpolationFunction === 'interpolate' &&
|
|
740
|
+
computed.keyframes.every((keyframe) => typeof keyframe.value === 'number' &&
|
|
741
|
+
Number.isFinite(keyframe.value) &&
|
|
742
|
+
keyframe.value >= 0)) {
|
|
743
|
+
return computed;
|
|
744
|
+
}
|
|
745
|
+
return computedStatus();
|
|
746
|
+
};
|
|
682
747
|
const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfigValues, allowSpecialValues, }) => {
|
|
683
748
|
const attr = jsxElement.attributes.find((a) => a.type !== 'JSXSpreadAttribute' &&
|
|
684
749
|
a.name.type !== 'JSXNamespacedName' &&
|
|
@@ -735,9 +800,6 @@ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfig
|
|
|
735
800
|
const staticShorthandValue = (0, exports.extractStaticValue)(shorthandValue, {
|
|
736
801
|
allowSpecialValues: false,
|
|
737
802
|
});
|
|
738
|
-
if (typeof staticShorthandValue !== 'string') {
|
|
739
|
-
return computedStatus();
|
|
740
|
-
}
|
|
741
803
|
const parsed = cssShorthand.parse(staticShorthandValue);
|
|
742
804
|
return parsed ? staticStatus(parsed[childKey], null) : computedStatus();
|
|
743
805
|
}
|
|
@@ -746,6 +808,13 @@ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfig
|
|
|
746
808
|
return staticStatus(undefined, null);
|
|
747
809
|
}
|
|
748
810
|
const propValue = prop.value;
|
|
811
|
+
if (parentKey === 'style' && childKey === BORDER_RADIUS_SHORTHAND) {
|
|
812
|
+
return getBorderRadiusShorthandStatus({
|
|
813
|
+
propValue,
|
|
814
|
+
ast,
|
|
815
|
+
videoConfigValues,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
749
818
|
const staticValueOptions = { allowSpecialValues };
|
|
750
819
|
if (!(0, exports.isStaticValue)(propValue, staticValueOptions)) {
|
|
751
820
|
const numericExpression = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
|
|
@@ -774,7 +843,14 @@ const computeEffectsForJsx = ({ ast, jsxElement, effects, videoConfigValues, })
|
|
|
774
843
|
const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys, assetKeys, videoConfigValues, }) => {
|
|
775
844
|
const allProps = getPropsStatus(jsxElement, ast, videoConfigValues, assetKeys);
|
|
776
845
|
const filteredProps = {};
|
|
846
|
+
const mixedBorderRadius = hasMixedBorderRadiusRepresentation(jsxElement);
|
|
777
847
|
for (const key of keys) {
|
|
848
|
+
if (mixedBorderRadius &&
|
|
849
|
+
key.startsWith('style.') &&
|
|
850
|
+
BORDER_RADIUS_PROPERTIES.has(key.slice('style.'.length))) {
|
|
851
|
+
filteredProps[key] = computedStatus();
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
778
854
|
if (key === 'children') {
|
|
779
855
|
const staticChildrenAttribute = (0, exports.getStaticJsxChildrenAttribute)(jsxElement);
|
|
780
856
|
if (staticChildrenAttribute) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FindInFileRequest, FindInFileResponse } from '@remotion/studio-shared';
|
|
2
|
+
import type { ApiHandler } from '../api-types';
|
|
3
|
+
export { findSearchPosition } from '@remotion/studio-codemods';
|
|
4
|
+
export declare const findInFileHandler: ApiHandler<FindInFileRequest, FindInFileResponse>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findInFileHandler = exports.findSearchPosition = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const studio_codemods_1 = require("@remotion/studio-codemods");
|
|
10
|
+
const studio_codemods_2 = require("@remotion/studio-codemods");
|
|
11
|
+
Object.defineProperty(exports, "findSearchPosition", { enumerable: true, get: function () { return studio_codemods_2.findSearchPosition; } });
|
|
12
|
+
const findInFileHandler = async ({ input, remotionRoot }) => {
|
|
13
|
+
const { fileName, lineNumber, columnNumber, search } = input;
|
|
14
|
+
const contents = await node_fs_1.default.promises.readFile(node_path_1.default.resolve(remotionRoot, fileName), 'utf-8');
|
|
15
|
+
return (0, studio_codemods_1.findSearchPosition)({
|
|
16
|
+
contents,
|
|
17
|
+
lineNumber,
|
|
18
|
+
columnNumber,
|
|
19
|
+
search,
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.findInFileHandler = findInFileHandler;
|
|
@@ -69,7 +69,7 @@ const validateElement = (element) => {
|
|
|
69
69
|
}
|
|
70
70
|
validateDimensions(element.dimensions);
|
|
71
71
|
};
|
|
72
|
-
const insertElementHandler = ({ input: { compositionFile, compositionId, element, from, position }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
72
|
+
const insertElementHandler = ({ input: { compositionFile, compositionId, element, from, position, overwriteExisting, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
73
73
|
try {
|
|
74
74
|
validateElement(element);
|
|
75
75
|
validatePosition(position);
|
|
@@ -99,13 +99,27 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
99
99
|
throw new Error('Element file must stay inside the Remotion project');
|
|
100
100
|
}
|
|
101
101
|
const elementFileExists = (0, node_fs_1.existsSync)(elementFileName);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
const existingElementSource = elementFileExists
|
|
103
|
+
? (0, node_fs_1.readFileSync)(elementFileName, 'utf-8')
|
|
104
|
+
: null;
|
|
105
|
+
const elementSourcesDiffer = existingElementSource !== null &&
|
|
106
|
+
normalizeSourceForComparison(existingElementSource) !==
|
|
107
|
+
normalizeSourceForComparison(element.sourceCode);
|
|
108
|
+
if (elementSourcesDiffer && !overwriteExisting) {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
type: 'file-conflict',
|
|
112
|
+
conflict: {
|
|
113
|
+
filePath: node_path_1.default
|
|
114
|
+
.relative(remotionRoot, elementFileName)
|
|
115
|
+
.split(node_path_1.default.sep)
|
|
116
|
+
.join('/'),
|
|
117
|
+
existingSource: existingElementSource,
|
|
118
|
+
incomingSource: element.sourceCode,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
108
121
|
}
|
|
122
|
+
const shouldWriteElementFile = !elementFileExists || elementSourcesDiffer;
|
|
109
123
|
const importPath = makeRelativeImportPath({
|
|
110
124
|
fromFile: location.fileName,
|
|
111
125
|
toFile: elementFileName,
|
|
@@ -133,16 +147,16 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
133
147
|
});
|
|
134
148
|
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
135
149
|
snapshots: [
|
|
136
|
-
...(
|
|
137
|
-
? [
|
|
138
|
-
: [
|
|
150
|
+
...(shouldWriteElementFile
|
|
151
|
+
? [
|
|
139
152
|
{
|
|
140
153
|
filePath: elementFileName,
|
|
141
|
-
oldContents:
|
|
154
|
+
oldContents: existingElementSource,
|
|
142
155
|
newContents: element.sourceCode,
|
|
143
156
|
logLine: 1,
|
|
144
157
|
},
|
|
145
|
-
]
|
|
158
|
+
]
|
|
159
|
+
: []),
|
|
146
160
|
{
|
|
147
161
|
filePath: inserted.fileName,
|
|
148
162
|
oldContents: inserted.oldContents,
|
|
@@ -159,11 +173,11 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
159
173
|
entryType: 'insert-jsx-element',
|
|
160
174
|
suppressHmrOnFileRestore: false,
|
|
161
175
|
});
|
|
162
|
-
if (
|
|
176
|
+
if (shouldWriteElementFile) {
|
|
163
177
|
(0, undo_stack_1.suppressUndoStackInvalidation)(elementFileName);
|
|
164
178
|
}
|
|
165
179
|
(0, undo_stack_1.suppressUndoStackInvalidation)(inserted.fileName);
|
|
166
|
-
if (
|
|
180
|
+
if (shouldWriteElementFile) {
|
|
167
181
|
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(elementFileName, element.sourceCode, undefined);
|
|
168
182
|
}
|
|
169
183
|
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(inserted.fileName, inserted.output, undefined);
|
|
@@ -177,7 +191,12 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
177
191
|
absolutePath: elementFileName,
|
|
178
192
|
line: 1,
|
|
179
193
|
});
|
|
180
|
-
|
|
194
|
+
const elementFileAction = elementSourcesDiffer
|
|
195
|
+
? 'Overwrote existing Element source'
|
|
196
|
+
: elementFileExists
|
|
197
|
+
? 'Reused existing Element source'
|
|
198
|
+
: 'Created Element source';
|
|
199
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(elementLocationLabel)} ${elementFileAction}`);
|
|
181
200
|
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(compositionLocationLabel)} Added <${componentName}>`);
|
|
182
201
|
if (!inserted.formatted) {
|
|
183
202
|
(0, log_update_1.warnAboutPrettierOnce)(logLevel);
|
|
@@ -190,6 +209,7 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
190
209
|
catch (err) {
|
|
191
210
|
return {
|
|
192
211
|
success: false,
|
|
212
|
+
type: 'error',
|
|
193
213
|
reason: err.message,
|
|
194
214
|
stack: err.stack,
|
|
195
215
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SaveMultipleEffectPropsRequest, SaveMultipleEffectPropsResponse } from '@remotion/studio-shared';
|
|
2
|
+
import type { ApiHandler } from '../api-types';
|
|
3
|
+
export declare const saveMultipleEffectPropsHandler: ApiHandler<SaveMultipleEffectPropsRequest, SaveMultipleEffectPropsResponse>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.saveMultipleEffectPropsHandler = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const renderer_1 = require("@remotion/renderer");
|
|
6
|
+
const studio_shared_1 = require("@remotion/studio-shared");
|
|
7
|
+
const parse_ast_1 = require("../../codemods/parse-ast");
|
|
8
|
+
const update_effect_props_1 = require("../../codemods/update-effect-props/update-effect-props");
|
|
9
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
10
|
+
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
11
|
+
const video_config_values_1 = require("../../helpers/video-config-values");
|
|
12
|
+
const undo_stack_1 = require("../undo-stack");
|
|
13
|
+
const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
14
|
+
const can_update_effect_props_1 = require("./can-update-effect-props");
|
|
15
|
+
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
16
|
+
const log_effect_update_1 = require("./log-updates/log-effect-update");
|
|
17
|
+
const source_file_write_queue_1 = require("./source-file-write-queue");
|
|
18
|
+
const resolveEdit = ({ edit, index, }) => {
|
|
19
|
+
const defaultValue = edit.defaultValue === null ? null : JSON.parse(edit.defaultValue);
|
|
20
|
+
const update = edit.type === 'value'
|
|
21
|
+
? {
|
|
22
|
+
key: edit.key,
|
|
23
|
+
value: JSON.parse(edit.value),
|
|
24
|
+
defaultValue,
|
|
25
|
+
}
|
|
26
|
+
: {
|
|
27
|
+
key: edit.key,
|
|
28
|
+
effectParam: edit.effectParam,
|
|
29
|
+
defaultValue,
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
index,
|
|
33
|
+
edit,
|
|
34
|
+
update,
|
|
35
|
+
defaultValueString: defaultValue === null ? null : JSON.stringify(defaultValue),
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const saveMultipleEffectPropsHandler = ({ input: { edits, clientId, undoLabel, redoLabel }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
39
|
+
var _a;
|
|
40
|
+
if (edits.length === 0) {
|
|
41
|
+
throw new Error('No effect prop edits to save');
|
|
42
|
+
}
|
|
43
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-multiple-effect-props] Received request with ${edits.length} edit(s)`);
|
|
44
|
+
const editGroups = new Map();
|
|
45
|
+
for (const [index, edit] of edits.entries()) {
|
|
46
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
47
|
+
remotionRoot,
|
|
48
|
+
fileName: edit.fileName,
|
|
49
|
+
action: 'modify',
|
|
50
|
+
});
|
|
51
|
+
const group = (_a = editGroups.get(absolutePath)) !== null && _a !== void 0 ? _a : {
|
|
52
|
+
fileRelativeToRoot,
|
|
53
|
+
edits: [],
|
|
54
|
+
};
|
|
55
|
+
group.edits.push(resolveEdit({ edit, index }));
|
|
56
|
+
editGroups.set(absolutePath, group);
|
|
57
|
+
}
|
|
58
|
+
const snapshots = [];
|
|
59
|
+
const outputByPath = new Map();
|
|
60
|
+
const resultByIndex = new Map();
|
|
61
|
+
for (const [absolutePath, group] of editGroups) {
|
|
62
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
63
|
+
let output = fileContents;
|
|
64
|
+
let firstLogLine = Number.POSITIVE_INFINITY;
|
|
65
|
+
for (const edit of group.edits) {
|
|
66
|
+
const result = await (0, update_effect_props_1.updateEffectProps)({
|
|
67
|
+
input: output,
|
|
68
|
+
sequenceNodePath: edit.edit.sequenceNodePath.nodePath,
|
|
69
|
+
effectIndex: edit.edit.effectIndex,
|
|
70
|
+
update: edit.update,
|
|
71
|
+
schema: edit.edit.schema,
|
|
72
|
+
});
|
|
73
|
+
output = result.output;
|
|
74
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
75
|
+
resultByIndex.set(edit.index, {
|
|
76
|
+
...result,
|
|
77
|
+
edit,
|
|
78
|
+
fileRelativeToRoot: group.fileRelativeToRoot,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
outputByPath.set(absolutePath, output);
|
|
82
|
+
snapshots.push({
|
|
83
|
+
filePath: absolutePath,
|
|
84
|
+
oldContents: fileContents,
|
|
85
|
+
newContents: output,
|
|
86
|
+
logLine: Number.isFinite(firstLogLine) ? firstLogLine : 1,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
90
|
+
snapshots,
|
|
91
|
+
logLevel,
|
|
92
|
+
remotionRoot,
|
|
93
|
+
description: {
|
|
94
|
+
undoMessage: `↩️ ${undoLabel}`,
|
|
95
|
+
redoMessage: `↪️ ${redoLabel}`,
|
|
96
|
+
},
|
|
97
|
+
entryType: 'effect-props',
|
|
98
|
+
suppressHmrOnFileRestore: true,
|
|
99
|
+
});
|
|
100
|
+
for (const [absolutePath, output] of outputByPath) {
|
|
101
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
|
|
102
|
+
(0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
|
|
103
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
|
|
104
|
+
}
|
|
105
|
+
for (const index of edits.keys()) {
|
|
106
|
+
const result = resultByIndex.get(index);
|
|
107
|
+
if (!result) {
|
|
108
|
+
throw new Error('Could not compute effect prop edit result');
|
|
109
|
+
}
|
|
110
|
+
(0, log_effect_update_1.logEffectUpdate)({
|
|
111
|
+
fileRelativeToRoot: result.fileRelativeToRoot,
|
|
112
|
+
line: result.logLine,
|
|
113
|
+
effectName: result.effectCallee,
|
|
114
|
+
propKey: result.edit.edit.key,
|
|
115
|
+
oldValueString: result.oldValueString,
|
|
116
|
+
newValueString: result.newValueString,
|
|
117
|
+
defaultValueString: result.edit.defaultValueString,
|
|
118
|
+
formatted: result.formatted,
|
|
119
|
+
logLevel,
|
|
120
|
+
removedProps: result.removedProps,
|
|
121
|
+
addedProps: [],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
125
|
+
const statusTargets = [
|
|
126
|
+
...new Map(edits.map((edit) => [
|
|
127
|
+
JSON.stringify([
|
|
128
|
+
edit.fileName,
|
|
129
|
+
edit.sequenceNodePath.nodePath,
|
|
130
|
+
edit.effectIndex,
|
|
131
|
+
]),
|
|
132
|
+
edit,
|
|
133
|
+
])).values(),
|
|
134
|
+
];
|
|
135
|
+
const results = statusTargets.map((edit) => {
|
|
136
|
+
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
137
|
+
remotionRoot,
|
|
138
|
+
fileName: edit.fileName,
|
|
139
|
+
action: 'modify',
|
|
140
|
+
});
|
|
141
|
+
const output = outputByPath.get(absolutePath);
|
|
142
|
+
if (!output) {
|
|
143
|
+
throw new Error('Could not compute effect prop edit status');
|
|
144
|
+
}
|
|
145
|
+
const ast = (0, parse_ast_1.parseAst)(output);
|
|
146
|
+
const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, edit.sequenceNodePath.nodePath);
|
|
147
|
+
const status = jsx
|
|
148
|
+
? (0, can_update_effect_props_1.computeEffectPropStatus)({
|
|
149
|
+
ast,
|
|
150
|
+
jsx,
|
|
151
|
+
effectIndex: edit.effectIndex,
|
|
152
|
+
keys: (0, studio_shared_1.getAllSchemaKeys)(edit.schema),
|
|
153
|
+
videoConfigValues: (0, video_config_values_1.getVideoConfigIdentifierValues)({
|
|
154
|
+
ast,
|
|
155
|
+
videoConfigValues: edit.sequenceNodePath.videoConfigValues,
|
|
156
|
+
}),
|
|
157
|
+
})
|
|
158
|
+
: {
|
|
159
|
+
canUpdate: false,
|
|
160
|
+
effectIndex: edit.effectIndex,
|
|
161
|
+
reason: 'not-found',
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
fileName: edit.fileName,
|
|
165
|
+
sequenceNodePath: edit.sequenceNodePath,
|
|
166
|
+
status,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
return { results };
|
|
170
|
+
});
|
|
171
|
+
exports.saveMultipleEffectPropsHandler = saveMultipleEffectPropsHandler;
|
|
@@ -4,6 +4,7 @@ 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_inline_caption_patches_1 = require("../../codemods/update-inline-caption-patches");
|
|
7
8
|
const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
|
|
8
9
|
const update_sequence_props_1 = require("../../codemods/update-sequence-props/update-sequence-props");
|
|
9
10
|
const file_watcher_1 = require("../../file-watcher");
|
|
@@ -59,8 +60,8 @@ const shouldSuppressHmrForSequencePropEdits = (edits) => {
|
|
|
59
60
|
(edit.sourceEdit === null || edit.sourceEdit === undefined));
|
|
60
61
|
};
|
|
61
62
|
exports.shouldSuppressHmrForSequencePropEdits = shouldSuppressHmrForSequencePropEdits;
|
|
62
|
-
const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyframes, clientId, undoLabel, redoLabel, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
63
|
-
var _a, _b, _c, _d;
|
|
63
|
+
const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyframes, captionPatches = [], clientId, undoLabel, redoLabel, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
64
|
+
var _a, _b, _c, _d, _e;
|
|
64
65
|
const keyframesToAdd = addedKeyframes === null ? [] : addedKeyframes;
|
|
65
66
|
const keyframesToMove = movedKeyframes === null
|
|
66
67
|
? { sequenceKeyframes: [], effectKeyframes: [] }
|
|
@@ -68,11 +69,12 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
68
69
|
const totalKeyframeMoves = keyframesToMove.sequenceKeyframes.length +
|
|
69
70
|
keyframesToMove.effectKeyframes.length;
|
|
70
71
|
if (edits.length === 0 &&
|
|
72
|
+
captionPatches.length === 0 &&
|
|
71
73
|
keyframesToAdd.length === 0 &&
|
|
72
74
|
totalKeyframeMoves === 0) {
|
|
73
75
|
throw new Error('No sequence prop edits to save');
|
|
74
76
|
}
|
|
75
|
-
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request with ${edits.length} edit(s), ${keyframesToAdd.length} added keyframe(s), and ${totalKeyframeMoves} moved keyframe(s)`);
|
|
77
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request with ${edits.length} edit(s), ${captionPatches.length} caption patch request(s), ${keyframesToAdd.length} added keyframe(s), and ${totalKeyframeMoves} moved keyframe(s)`);
|
|
76
78
|
const editGroups = new Map();
|
|
77
79
|
for (const [index, edit] of edits.entries()) {
|
|
78
80
|
const parsedValue = parseSequencePropEditValue(edit.value);
|
|
@@ -85,6 +87,7 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
85
87
|
const group = (_a = editGroups.get(absolutePath)) !== null && _a !== void 0 ? _a : {
|
|
86
88
|
fileRelativeToRoot,
|
|
87
89
|
edits: [],
|
|
90
|
+
captionPatches: [],
|
|
88
91
|
addedKeyframes: [],
|
|
89
92
|
movedSequenceKeyframes: [],
|
|
90
93
|
effectKeyframes: [],
|
|
@@ -105,15 +108,33 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
105
108
|
});
|
|
106
109
|
editGroups.set(absolutePath, group);
|
|
107
110
|
}
|
|
111
|
+
for (const captionPatch of captionPatches) {
|
|
112
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
113
|
+
remotionRoot,
|
|
114
|
+
fileName: captionPatch.fileName,
|
|
115
|
+
action: 'modify',
|
|
116
|
+
});
|
|
117
|
+
const group = (_b = editGroups.get(absolutePath)) !== null && _b !== void 0 ? _b : {
|
|
118
|
+
fileRelativeToRoot,
|
|
119
|
+
edits: [],
|
|
120
|
+
captionPatches: [],
|
|
121
|
+
addedKeyframes: [],
|
|
122
|
+
movedSequenceKeyframes: [],
|
|
123
|
+
effectKeyframes: [],
|
|
124
|
+
};
|
|
125
|
+
group.captionPatches.push(captionPatch);
|
|
126
|
+
editGroups.set(absolutePath, group);
|
|
127
|
+
}
|
|
108
128
|
for (const keyframe of keyframesToAdd) {
|
|
109
129
|
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
110
130
|
remotionRoot,
|
|
111
131
|
fileName: keyframe.fileName,
|
|
112
132
|
action: 'modify',
|
|
113
133
|
});
|
|
114
|
-
const group = (
|
|
134
|
+
const group = (_c = editGroups.get(absolutePath)) !== null && _c !== void 0 ? _c : {
|
|
115
135
|
fileRelativeToRoot,
|
|
116
136
|
edits: [],
|
|
137
|
+
captionPatches: [],
|
|
117
138
|
addedKeyframes: [],
|
|
118
139
|
movedSequenceKeyframes: [],
|
|
119
140
|
effectKeyframes: [],
|
|
@@ -127,9 +148,10 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
127
148
|
fileName: keyframe.fileName,
|
|
128
149
|
action: 'modify',
|
|
129
150
|
});
|
|
130
|
-
const group = (
|
|
151
|
+
const group = (_d = editGroups.get(absolutePath)) !== null && _d !== void 0 ? _d : {
|
|
131
152
|
fileRelativeToRoot,
|
|
132
153
|
edits: [],
|
|
154
|
+
captionPatches: [],
|
|
133
155
|
addedKeyframes: [],
|
|
134
156
|
movedSequenceKeyframes: [],
|
|
135
157
|
effectKeyframes: [],
|
|
@@ -143,9 +165,10 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
143
165
|
fileName: keyframe.fileName,
|
|
144
166
|
action: 'modify',
|
|
145
167
|
});
|
|
146
|
-
const group = (
|
|
168
|
+
const group = (_e = editGroups.get(absolutePath)) !== null && _e !== void 0 ? _e : {
|
|
147
169
|
fileRelativeToRoot,
|
|
148
170
|
edits: [],
|
|
171
|
+
captionPatches: [],
|
|
149
172
|
addedKeyframes: [],
|
|
150
173
|
movedSequenceKeyframes: [],
|
|
151
174
|
effectKeyframes: [],
|
|
@@ -157,6 +180,7 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
157
180
|
const outputByPath = new Map();
|
|
158
181
|
const resultByIndex = new Map();
|
|
159
182
|
const sequenceKeyframeLogs = [];
|
|
183
|
+
const captionPatchLogs = [];
|
|
160
184
|
const effectKeyframeLogs = [];
|
|
161
185
|
for (const [absolutePath, group] of editGroups) {
|
|
162
186
|
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
@@ -183,6 +207,32 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
183
207
|
});
|
|
184
208
|
}
|
|
185
209
|
}
|
|
210
|
+
for (const captionPatchRequest of group.captionPatches) {
|
|
211
|
+
const result = (0, update_inline_caption_patches_1.updateInlineCaptionPatches)({
|
|
212
|
+
input: output,
|
|
213
|
+
nodePath: captionPatchRequest.nodePath.nodePath,
|
|
214
|
+
patches: captionPatchRequest.patches,
|
|
215
|
+
});
|
|
216
|
+
output = result.output;
|
|
217
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
218
|
+
for (const [index, patch] of captionPatchRequest.patches.entries()) {
|
|
219
|
+
const changedFields = result.changedFields[index];
|
|
220
|
+
if (!changedFields) {
|
|
221
|
+
throw new Error('Could not determine changed caption fields');
|
|
222
|
+
}
|
|
223
|
+
captionPatchLogs.push({
|
|
224
|
+
fileRelativeToRoot: group.fileRelativeToRoot,
|
|
225
|
+
line: result.logLine,
|
|
226
|
+
index: patch.index,
|
|
227
|
+
oldValueString: changedFields
|
|
228
|
+
.map((field) => `${field}: ${patch.before[field]}`)
|
|
229
|
+
.join(', '),
|
|
230
|
+
newValueString: changedFields
|
|
231
|
+
.map((field) => `${field}: ${patch.changes[field]}`)
|
|
232
|
+
.join(', '),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
186
236
|
for (const keyframeGroup of groupBy(group.addedKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
|
|
187
237
|
const [firstSequenceKeyframe] = keyframeGroup;
|
|
188
238
|
if (!firstSequenceKeyframe) {
|
|
@@ -310,7 +360,8 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
310
360
|
}
|
|
311
361
|
const undoMessage = `↩️ ${undoLabel}`;
|
|
312
362
|
const redoMessage = `↪️ ${redoLabel}`;
|
|
313
|
-
const suppressHmr =
|
|
363
|
+
const suppressHmr = captionPatches.length === 0 &&
|
|
364
|
+
(0, exports.shouldSuppressHmrForSequencePropEdits)(edits);
|
|
314
365
|
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
315
366
|
snapshots,
|
|
316
367
|
logLevel,
|
|
@@ -346,6 +397,20 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
346
397
|
});
|
|
347
398
|
}
|
|
348
399
|
}
|
|
400
|
+
for (const log of captionPatchLogs) {
|
|
401
|
+
(0, log_update_1.logUpdate)({
|
|
402
|
+
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
403
|
+
line: log.line,
|
|
404
|
+
key: `captions[${log.index}]`,
|
|
405
|
+
oldValueString: log.oldValueString,
|
|
406
|
+
newValueString: log.newValueString,
|
|
407
|
+
defaultValueString: null,
|
|
408
|
+
formatted: true,
|
|
409
|
+
logLevel,
|
|
410
|
+
removedProps: [],
|
|
411
|
+
addedProps: [],
|
|
412
|
+
});
|
|
413
|
+
}
|
|
349
414
|
for (const log of sequenceKeyframeLogs) {
|
|
350
415
|
(0, log_update_1.logUpdate)({
|
|
351
416
|
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
@@ -377,7 +442,7 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
377
442
|
}
|
|
378
443
|
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
379
444
|
const statusTargets = [
|
|
380
|
-
...new Map([...edits, ...keyframesToAdd].map((target) => [
|
|
445
|
+
...new Map([...edits, ...captionPatches, ...keyframesToAdd].map((target) => [
|
|
381
446
|
JSON.stringify(target.nodePath),
|
|
382
447
|
target,
|
|
383
448
|
])).values(),
|
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.501",
|
|
7
7
|
"description": "Run a Remotion Studio with a server backend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"scripts": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@remotion/drag-and-drop": "4.0.
|
|
26
|
+
"@remotion/drag-and-drop": "4.0.501",
|
|
27
27
|
"@babel/types": "7.24.0",
|
|
28
28
|
"@babel/parser": "7.24.1",
|
|
29
29
|
"@svgr/core": "8.1.0",
|
|
@@ -31,11 +31,12 @@
|
|
|
31
31
|
"kiwi-schema": "0.5.0",
|
|
32
32
|
"semver": "7.5.3",
|
|
33
33
|
"prettier": "3.8.1",
|
|
34
|
-
"remotion": "4.0.
|
|
34
|
+
"remotion": "4.0.501",
|
|
35
35
|
"recast": "0.23.11",
|
|
36
|
-
"@remotion/bundler": "4.0.
|
|
37
|
-
"@remotion/renderer": "4.0.
|
|
38
|
-
"@remotion/studio-
|
|
36
|
+
"@remotion/bundler": "4.0.501",
|
|
37
|
+
"@remotion/renderer": "4.0.501",
|
|
38
|
+
"@remotion/studio-codemods": "4.0.501",
|
|
39
|
+
"@remotion/studio-shared": "4.0.501",
|
|
39
40
|
"memfs": "3.4.3",
|
|
40
41
|
"open": "8.4.2"
|
|
41
42
|
},
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"ast-types": "0.16.1",
|
|
44
45
|
"react": "19.2.3",
|
|
45
46
|
"@types/semver": "7.5.3",
|
|
46
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
47
|
+
"@remotion/eslint-config-internal": "4.0.501",
|
|
47
48
|
"eslint": "9.19.0",
|
|
48
49
|
"@types/node": "20.12.14",
|
|
49
50
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|