@remotion/studio-server 4.0.476 → 4.0.478
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-effect.d.ts +26 -0
- package/dist/codemods/duplicate-effect.js +92 -0
- package/dist/helpers/resolve-composition-component.js +30 -9
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/jsx-component-identity.d.ts +12 -0
- package/dist/preview-server/jsx-component-identity.js +126 -0
- package/dist/preview-server/routes/add-sequence-keyframe.js +1 -0
- package/dist/preview-server/routes/can-update-sequence-props.d.ts +6 -3
- package/dist/preview-server/routes/can-update-sequence-props.js +31 -3
- package/dist/preview-server/routes/delete-keyframes.js +1 -0
- package/dist/preview-server/routes/download-remote-asset.js +8 -2
- package/dist/preview-server/routes/duplicate-effect.d.ts +3 -0
- package/dist/preview-server/routes/duplicate-effect.js +98 -0
- package/dist/preview-server/routes/insert-jsx-element.js +12 -0
- package/dist/preview-server/routes/save-sequence-props.js +1 -0
- package/dist/preview-server/routes/subscribe-to-sequence-props.js +2 -1
- package/dist/preview-server/routes/update-sequence-keyframe-settings.js +1 -0
- package/dist/preview-server/sequence-props-watchers.d.ts +2 -1
- package/dist/preview-server/sequence-props-watchers.js +53 -27
- package/dist/preview-server/undo-stack.d.ts +3 -1
- package/package.json +6 -6
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SequenceNodePath } from 'remotion';
|
|
2
|
+
export type EffectDuplicationTarget = {
|
|
3
|
+
sequenceNodePath: SequenceNodePath;
|
|
4
|
+
effectIndex: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const duplicateEffects: ({ input, effects, prettierConfigOverride, }: {
|
|
7
|
+
input: string;
|
|
8
|
+
effects: EffectDuplicationTarget[];
|
|
9
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
output: string;
|
|
12
|
+
formatted: boolean;
|
|
13
|
+
effectLabels: string[];
|
|
14
|
+
logLines: number[];
|
|
15
|
+
}>;
|
|
16
|
+
export declare const duplicateEffect: ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }: {
|
|
17
|
+
input: string;
|
|
18
|
+
sequenceNodePath: SequenceNodePath;
|
|
19
|
+
effectIndex: number;
|
|
20
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
21
|
+
}) => Promise<{
|
|
22
|
+
output: string;
|
|
23
|
+
formatted: boolean;
|
|
24
|
+
effectLabel: string;
|
|
25
|
+
logLine: number;
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.duplicateEffect = exports.duplicateEffects = void 0;
|
|
4
|
+
const types_1 = require("@babel/types");
|
|
5
|
+
const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
|
|
6
|
+
const format_file_content_1 = require("./format-file-content");
|
|
7
|
+
const parse_ast_1 = require("./parse-ast");
|
|
8
|
+
const update_effect_props_1 = require("./update-effect-props/update-effect-props");
|
|
9
|
+
const getEffectsArray = (attr) => {
|
|
10
|
+
if (!attr.value || attr.value.type !== 'JSXExpressionContainer') {
|
|
11
|
+
throw new Error('Cannot duplicate effect: effects prop is not an array');
|
|
12
|
+
}
|
|
13
|
+
const expr = attr.value.expression;
|
|
14
|
+
if (expr.type !== 'ArrayExpression') {
|
|
15
|
+
throw new Error('Cannot duplicate effect: effects prop is not an array');
|
|
16
|
+
}
|
|
17
|
+
return expr;
|
|
18
|
+
};
|
|
19
|
+
const duplicateEffects = async ({ input, effects, prettierConfigOverride, }) => {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
var _c, _d, _e;
|
|
22
|
+
if (effects.length === 0) {
|
|
23
|
+
throw new Error('No effects were specified for duplication');
|
|
24
|
+
}
|
|
25
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
26
|
+
const duplicationsByAttr = new Map();
|
|
27
|
+
for (const effect of effects) {
|
|
28
|
+
const { sequenceNodePath, effectIndex } = effect;
|
|
29
|
+
const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, sequenceNodePath);
|
|
30
|
+
if (!jsx) {
|
|
31
|
+
throw new Error('Could not find a JSX element at the specified location to duplicate effect');
|
|
32
|
+
}
|
|
33
|
+
const attr = (0, update_effect_props_1.findEffectsAttr)((_c = jsx.attributes) !== null && _c !== void 0 ? _c : []);
|
|
34
|
+
if (!attr) {
|
|
35
|
+
throw new Error('Could not find effects on the target JSX element');
|
|
36
|
+
}
|
|
37
|
+
const effectsArray = getEffectsArray(attr);
|
|
38
|
+
const existingDuplication = duplicationsByAttr.get(attr);
|
|
39
|
+
const duplication = existingDuplication !== null && existingDuplication !== void 0 ? existingDuplication : {
|
|
40
|
+
effectsArray,
|
|
41
|
+
effectIndices: new Set(),
|
|
42
|
+
effectLabels: [],
|
|
43
|
+
logLines: [],
|
|
44
|
+
};
|
|
45
|
+
duplicationsByAttr.set(attr, duplication);
|
|
46
|
+
if (duplication.effectIndices.has(effectIndex)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const found = (0, update_effect_props_1.findEffectCallExpression)({ attr, effectIndex });
|
|
50
|
+
if (found.kind === 'error') {
|
|
51
|
+
throw new Error(`Cannot duplicate effect: ${found.reason}`);
|
|
52
|
+
}
|
|
53
|
+
duplication.effectIndices.add(effectIndex);
|
|
54
|
+
duplication.effectLabels.push(`${found.callee}()`);
|
|
55
|
+
duplication.logLines.push((_e = (_d = (_a = found.call.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _d !== void 0 ? _d : (_b = jsx.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _e !== void 0 ? _e : 1);
|
|
56
|
+
}
|
|
57
|
+
for (const duplication of duplicationsByAttr.values()) {
|
|
58
|
+
for (const effectIndex of [...duplication.effectIndices].sort((a, b) => b - a)) {
|
|
59
|
+
const effect = duplication.effectsArray.elements[effectIndex];
|
|
60
|
+
if (!effect || effect.type !== 'CallExpression') {
|
|
61
|
+
throw new Error('Cannot duplicate effect: not-call-expression');
|
|
62
|
+
}
|
|
63
|
+
duplication.effectsArray.elements.splice(effectIndex + 1, 0, (0, types_1.cloneNode)(effect, true));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
67
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
68
|
+
input: finalFile,
|
|
69
|
+
prettierConfigOverride,
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
output,
|
|
73
|
+
formatted,
|
|
74
|
+
effectLabels: [...duplicationsByAttr.values()].flatMap((duplication) => duplication.effectLabels),
|
|
75
|
+
logLines: [...duplicationsByAttr.values()].flatMap((duplication) => duplication.logLines),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
exports.duplicateEffects = duplicateEffects;
|
|
79
|
+
const duplicateEffect = async ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }) => {
|
|
80
|
+
const { output, formatted, effectLabels, logLines } = await (0, exports.duplicateEffects)({
|
|
81
|
+
input,
|
|
82
|
+
effects: [{ sequenceNodePath, effectIndex }],
|
|
83
|
+
prettierConfigOverride,
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
output,
|
|
87
|
+
formatted,
|
|
88
|
+
effectLabel: effectLabels[0],
|
|
89
|
+
logLine: logLines[0],
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
exports.duplicateEffect = duplicateEffect;
|
|
@@ -515,10 +515,15 @@ const createStringAttribute = (name, value) => {
|
|
|
515
515
|
const createBooleanAttribute = (name, value) => {
|
|
516
516
|
return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.jsxExpressionContainer(recast.types.builders.booleanLiteral(value)));
|
|
517
517
|
};
|
|
518
|
-
const
|
|
519
|
-
|
|
518
|
+
const formatTranslateValue = ({ x, y }) => `${x}px ${y}px`;
|
|
519
|
+
const createPositionAbsoluteStyleAttribute = (position) => {
|
|
520
|
+
const properties = [
|
|
520
521
|
recast.types.builders.objectProperty(recast.types.builders.identifier('position'), recast.types.builders.stringLiteral('absolute')),
|
|
521
|
-
]
|
|
522
|
+
];
|
|
523
|
+
if (position) {
|
|
524
|
+
properties.push(recast.types.builders.objectProperty(recast.types.builders.identifier('translate'), recast.types.builders.stringLiteral(formatTranslateValue(position))));
|
|
525
|
+
}
|
|
526
|
+
return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('style'), recast.types.builders.jsxExpressionContainer(recast.types.builders.objectExpression(properties)));
|
|
522
527
|
};
|
|
523
528
|
const createStaticFileSrcAttribute = ({ staticFileLocalName, src, }) => {
|
|
524
529
|
return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('src'), recast.types.builders.jsxExpressionContainer(recast.types.builders.callExpression(recast.types.builders.identifier(staticFileLocalName), [recast.types.builders.stringLiteral(src)])));
|
|
@@ -535,25 +540,27 @@ const createComponentProp = ({ name, value, }) => {
|
|
|
535
540
|
const createStringSrcAttribute = (src) => {
|
|
536
541
|
return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier('src'), recast.types.builders.stringLiteral(src));
|
|
537
542
|
};
|
|
538
|
-
const createSolidElement = ({ localName, width, height, }) => {
|
|
543
|
+
const createSolidElement = ({ localName, width, height, position, }) => {
|
|
539
544
|
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
540
545
|
createNumberAttribute('width', width),
|
|
541
546
|
createNumberAttribute('height', height),
|
|
542
|
-
createPositionAbsoluteStyleAttribute(),
|
|
547
|
+
createPositionAbsoluteStyleAttribute(position),
|
|
543
548
|
], true), null, []);
|
|
544
549
|
};
|
|
545
|
-
const createComponentElement = ({ localName, props, }) => {
|
|
550
|
+
const createComponentElement = ({ localName, props, position, }) => {
|
|
546
551
|
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
547
552
|
...props.map(createComponentProp),
|
|
548
|
-
createPositionAbsoluteStyleAttribute(),
|
|
553
|
+
createPositionAbsoluteStyleAttribute(position),
|
|
549
554
|
], true), null, []);
|
|
550
555
|
};
|
|
551
|
-
const createAssetElement = ({ addPositionStyle, localName, staticFileLocalName, src, dimensions, }) => {
|
|
556
|
+
const createAssetElement = ({ addPositionStyle, localName, staticFileLocalName, src, dimensions, position, }) => {
|
|
552
557
|
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
553
558
|
staticFileLocalName === null
|
|
554
559
|
? createStringSrcAttribute(src)
|
|
555
560
|
: createStaticFileSrcAttribute({ staticFileLocalName, src }),
|
|
556
|
-
...(addPositionStyle
|
|
561
|
+
...(addPositionStyle
|
|
562
|
+
? [createPositionAbsoluteStyleAttribute(position)]
|
|
563
|
+
: []),
|
|
557
564
|
...(dimensions
|
|
558
565
|
? [
|
|
559
566
|
createNumberAttribute('width', dimensions.width),
|
|
@@ -728,6 +735,14 @@ const ensureImgImport = (ast) => {
|
|
|
728
735
|
label: '<Img>',
|
|
729
736
|
});
|
|
730
737
|
};
|
|
738
|
+
const ensureAnimatedImageImport = (ast) => {
|
|
739
|
+
return ensureOfficialNamedImport({
|
|
740
|
+
ast,
|
|
741
|
+
importedName: 'AnimatedImage',
|
|
742
|
+
sourcePath: 'remotion',
|
|
743
|
+
label: '<AnimatedImage>',
|
|
744
|
+
});
|
|
745
|
+
};
|
|
731
746
|
const ensureVideoImport = (ast) => {
|
|
732
747
|
return ensureOfficialNamedImport({
|
|
733
748
|
ast,
|
|
@@ -1007,6 +1022,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
1007
1022
|
localName: solidLocalName,
|
|
1008
1023
|
width: element.width,
|
|
1009
1024
|
height: element.height,
|
|
1025
|
+
position: element.position,
|
|
1010
1026
|
});
|
|
1011
1027
|
}
|
|
1012
1028
|
if (element.type === 'component') {
|
|
@@ -1019,6 +1035,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
1019
1035
|
return createComponentElement({
|
|
1020
1036
|
localName: componentLocalName,
|
|
1021
1037
|
props: element.props,
|
|
1038
|
+
position: element.position,
|
|
1022
1039
|
});
|
|
1023
1040
|
}
|
|
1024
1041
|
if (element.type === 'asset') {
|
|
@@ -1036,6 +1053,9 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
1036
1053
|
else if (element.assetType === 'gif') {
|
|
1037
1054
|
localName = ensureGifImport(ast);
|
|
1038
1055
|
}
|
|
1056
|
+
else if (element.assetType === 'animated-image') {
|
|
1057
|
+
localName = ensureAnimatedImageImport(ast);
|
|
1058
|
+
}
|
|
1039
1059
|
else if (element.assetType === 'audio') {
|
|
1040
1060
|
localName = ensureAudioImport(ast);
|
|
1041
1061
|
}
|
|
@@ -1048,6 +1068,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
1048
1068
|
staticFileLocalName,
|
|
1049
1069
|
src: element.src,
|
|
1050
1070
|
dimensions: element.dimensions,
|
|
1071
|
+
position: element.position,
|
|
1051
1072
|
});
|
|
1052
1073
|
}
|
|
1053
1074
|
throw new Error('Unsupported element type');
|
|
@@ -15,6 +15,7 @@ const delete_jsx_node_1 = require("./routes/delete-jsx-node");
|
|
|
15
15
|
const delete_keyframes_1 = require("./routes/delete-keyframes");
|
|
16
16
|
const delete_static_file_1 = require("./routes/delete-static-file");
|
|
17
17
|
const download_remote_asset_1 = require("./routes/download-remote-asset");
|
|
18
|
+
const duplicate_effect_1 = require("./routes/duplicate-effect");
|
|
18
19
|
const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
|
|
19
20
|
const insert_jsx_element_1 = require("./routes/insert-jsx-element");
|
|
20
21
|
const install_dependency_1 = require("./routes/install-dependency");
|
|
@@ -67,6 +68,7 @@ exports.allApiRoutes = {
|
|
|
67
68
|
'/api/save-effect-props': save_effect_props_1.saveEffectPropsHandler,
|
|
68
69
|
'/api/add-effect': add_effect_1.addEffectHandler,
|
|
69
70
|
'/api/reorder-effect': reorder_effect_1.reorderEffectHandler,
|
|
71
|
+
'/api/duplicate-effect': duplicate_effect_1.duplicateEffectHandler,
|
|
70
72
|
'/api/reorder-sequence': reorder_sequence_1.reorderSequenceHandler,
|
|
71
73
|
'/api/delete-keyframes': delete_keyframes_1.deleteKeyframesHandler,
|
|
72
74
|
'/api/move-keyframes': move_keyframes_1.moveKeyframesHandler,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { File, JSXOpeningElement } from '@babel/types';
|
|
2
|
+
export declare class JsxElementIdentityMismatchError extends Error {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
export declare const getJsxComponentIdentity: ({ ast, jsxElement, }: {
|
|
6
|
+
ast: File;
|
|
7
|
+
jsxElement: JSXOpeningElement;
|
|
8
|
+
}) => string | null;
|
|
9
|
+
export declare const jsxComponentIdentitiesMatch: ({ expected, actual, }: {
|
|
10
|
+
expected: string | null;
|
|
11
|
+
actual: string | null;
|
|
12
|
+
}) => boolean;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsxComponentIdentitiesMatch = exports.getJsxComponentIdentity = exports.JsxElementIdentityMismatchError = void 0;
|
|
4
|
+
const imports_1 = require("../helpers/imports");
|
|
5
|
+
class JsxElementIdentityMismatchError extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('JSX element identity changed');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.JsxElementIdentityMismatchError = JsxElementIdentityMismatchError;
|
|
11
|
+
const jsxMemberToString = (expr) => {
|
|
12
|
+
if (expr.type === 'JSXIdentifier') {
|
|
13
|
+
return expr.name;
|
|
14
|
+
}
|
|
15
|
+
return `${jsxMemberToString(expr.object)}.${expr.property.name}`;
|
|
16
|
+
};
|
|
17
|
+
const getJsxRootIdentifier = (expr) => {
|
|
18
|
+
if (expr.type === 'JSXIdentifier') {
|
|
19
|
+
return expr;
|
|
20
|
+
}
|
|
21
|
+
return getJsxRootIdentifier(expr.object);
|
|
22
|
+
};
|
|
23
|
+
const getTagName = (node) => {
|
|
24
|
+
if (node.name.type === 'JSXIdentifier') {
|
|
25
|
+
return node.name.name;
|
|
26
|
+
}
|
|
27
|
+
if (node.name.type === 'JSXMemberExpression') {
|
|
28
|
+
return jsxMemberToString(node.name);
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
const getMemberPath = (tagName) => {
|
|
33
|
+
const dotIndex = tagName.indexOf('.');
|
|
34
|
+
return dotIndex === -1 ? '' : tagName.slice(dotIndex + 1);
|
|
35
|
+
};
|
|
36
|
+
const getMemberPathAfterImportName = ({ tagName, importName, }) => {
|
|
37
|
+
const parts = tagName.split('.');
|
|
38
|
+
const importNameIndex = parts.indexOf(importName);
|
|
39
|
+
if (importNameIndex === -1) {
|
|
40
|
+
return getMemberPath(tagName);
|
|
41
|
+
}
|
|
42
|
+
return parts.slice(importNameIndex + 1).join('.');
|
|
43
|
+
};
|
|
44
|
+
const sourcePathToIdentityPrefix = (sourcePath) => {
|
|
45
|
+
if (sourcePath === 'remotion') {
|
|
46
|
+
return 'dev.remotion.remotion';
|
|
47
|
+
}
|
|
48
|
+
if (sourcePath.startsWith('@remotion/')) {
|
|
49
|
+
const packageName = sourcePath
|
|
50
|
+
.slice('@remotion/'.length)
|
|
51
|
+
.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
52
|
+
return `dev.remotion.${packageName}`;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
};
|
|
56
|
+
const makeImportedIdentity = ({ sourcePath, importName, memberPath, }) => {
|
|
57
|
+
const prefix = sourcePathToIdentityPrefix(sourcePath);
|
|
58
|
+
if (prefix === null) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return [prefix, importName, memberPath].filter(Boolean).join('.');
|
|
62
|
+
};
|
|
63
|
+
const getJsxComponentIdentity = ({ ast, jsxElement, }) => {
|
|
64
|
+
var _a;
|
|
65
|
+
const tagName = getTagName(jsxElement);
|
|
66
|
+
if (tagName === null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const rootIdentifier = jsxElement.name.type === 'JSXIdentifier'
|
|
70
|
+
? jsxElement.name
|
|
71
|
+
: jsxElement.name.type === 'JSXMemberExpression'
|
|
72
|
+
? getJsxRootIdentifier(jsxElement.name)
|
|
73
|
+
: null;
|
|
74
|
+
if (rootIdentifier === null) {
|
|
75
|
+
return tagName;
|
|
76
|
+
}
|
|
77
|
+
for (const node of ast.program.body) {
|
|
78
|
+
if (node.type !== 'ImportDeclaration') {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const sourcePath = String(node.source.value);
|
|
82
|
+
for (const specifier of node.specifiers) {
|
|
83
|
+
if (specifier.type === 'ImportSpecifier' &&
|
|
84
|
+
((_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) === rootIdentifier.name) {
|
|
85
|
+
const importName = (0, imports_1.getImportedName)(specifier);
|
|
86
|
+
return makeImportedIdentity({
|
|
87
|
+
sourcePath,
|
|
88
|
+
importName,
|
|
89
|
+
memberPath: getMemberPath(tagName),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (specifier.type === 'ImportNamespaceSpecifier' &&
|
|
93
|
+
specifier.local.name === rootIdentifier.name) {
|
|
94
|
+
const [importName, ...members] = getMemberPath(tagName).split('.');
|
|
95
|
+
if (!importName) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return makeImportedIdentity({
|
|
99
|
+
sourcePath,
|
|
100
|
+
importName,
|
|
101
|
+
memberPath: members.join('.'),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (specifier.type === 'ImportDefaultSpecifier' &&
|
|
105
|
+
specifier.local.name === rootIdentifier.name) {
|
|
106
|
+
return makeImportedIdentity({
|
|
107
|
+
sourcePath,
|
|
108
|
+
importName: 'default',
|
|
109
|
+
memberPath: getMemberPathAfterImportName({
|
|
110
|
+
tagName,
|
|
111
|
+
importName: rootIdentifier.name,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return tagName;
|
|
118
|
+
};
|
|
119
|
+
exports.getJsxComponentIdentity = getJsxComponentIdentity;
|
|
120
|
+
const jsxComponentIdentitiesMatch = ({ expected, actual, }) => {
|
|
121
|
+
if (expected === null) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return expected === actual;
|
|
125
|
+
};
|
|
126
|
+
exports.jsxComponentIdentitiesMatch = jsxComponentIdentitiesMatch;
|
|
@@ -74,6 +74,7 @@ const addSequenceKeyframeHandler = ({ input: { fileName, nodePath, key, frame, v
|
|
|
74
74
|
fileContents: output,
|
|
75
75
|
keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
|
|
76
76
|
nodePath: updatedNodePath,
|
|
77
|
+
componentIdentity: null,
|
|
77
78
|
effects: [],
|
|
78
79
|
});
|
|
79
80
|
const updatedSubscriptionKey = { ...nodePath, nodePath: updatedNodePath };
|
|
@@ -10,22 +10,25 @@ export declare const getComputedStatus: (node: Expression, ast: File) => CanUpda
|
|
|
10
10
|
export declare const findJsxElementAtNodePath: (ast: File, nodePath: SequenceNodePath) => JSXOpeningElement | null;
|
|
11
11
|
export declare const findNodePathForJsxElement: (ast: File, target: JSXOpeningElement) => SequenceNodePath | null;
|
|
12
12
|
export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
|
|
13
|
-
export declare const computeSequencePropsStatusFromContent: ({ fileContents, nodePath, keys, effects, }: {
|
|
13
|
+
export declare const computeSequencePropsStatusFromContent: ({ fileContents, nodePath, componentIdentity, keys, effects, }: {
|
|
14
14
|
fileContents: string;
|
|
15
15
|
nodePath: SequenceNodePath;
|
|
16
|
+
componentIdentity: string | null;
|
|
16
17
|
keys: string[];
|
|
17
18
|
effects: string[][];
|
|
18
19
|
}) => CanUpdateSequencePropsResponseTrue;
|
|
19
|
-
export declare const computeSequencePropsStatus: ({ fileName, nodePath, keys, effects, remotionRoot, }: {
|
|
20
|
+
export declare const computeSequencePropsStatus: ({ fileName, nodePath, componentIdentity, keys, effects, remotionRoot, }: {
|
|
20
21
|
fileName: string;
|
|
21
22
|
nodePath: SequenceNodePath;
|
|
23
|
+
componentIdentity: string | null;
|
|
22
24
|
keys: string[];
|
|
23
25
|
effects: string[][];
|
|
24
26
|
remotionRoot: string;
|
|
25
27
|
}) => CanUpdateSequencePropsResponseTrue;
|
|
26
|
-
export declare const computeSequencePropsStatusFromFilenameByLine: ({ fileName, line, keys, effects, remotionRoot, logLevel, }: {
|
|
28
|
+
export declare const computeSequencePropsStatusFromFilenameByLine: ({ fileName, line, componentIdentity, keys, effects, remotionRoot, logLevel, }: {
|
|
27
29
|
fileName: string;
|
|
28
30
|
line: number;
|
|
31
|
+
componentIdentity: string | null;
|
|
29
32
|
keys: string[];
|
|
30
33
|
effects: string[][];
|
|
31
34
|
remotionRoot: string;
|
|
@@ -43,6 +43,7 @@ const parse_ast_1 = require("../../codemods/parse-ast");
|
|
|
43
43
|
const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
|
|
44
44
|
const import_agnostic_node_path_1 = require("../../helpers/import-agnostic-node-path");
|
|
45
45
|
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
46
|
+
const jsx_component_identity_1 = require("../jsx-component-identity");
|
|
46
47
|
const jsx_element_not_found_at_location_error_1 = require("../jsx-element-not-found-at-location-error");
|
|
47
48
|
const can_update_effect_props_1 = require("./can-update-effect-props");
|
|
48
49
|
const staticStatus = (codeValue) => ({
|
|
@@ -353,6 +354,25 @@ const getInterpolationKeyframes = (node, ast) => {
|
|
|
353
354
|
if (node.type === 'TSAsExpression') {
|
|
354
355
|
return getInterpolationKeyframes(node.expression, ast);
|
|
355
356
|
}
|
|
357
|
+
if (node.type === 'CallExpression' &&
|
|
358
|
+
node.callee.type === 'Identifier' &&
|
|
359
|
+
node.callee.name === 'String' &&
|
|
360
|
+
node.arguments.length === 1 &&
|
|
361
|
+
node.arguments[0].type !== 'ArgumentPlaceholder' &&
|
|
362
|
+
node.arguments[0].type !== 'JSXNamespacedName' &&
|
|
363
|
+
node.arguments[0].type !== 'SpreadElement') {
|
|
364
|
+
const interpolation = getInterpolationKeyframes(node.arguments[0], ast);
|
|
365
|
+
if (!interpolation) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
...interpolation,
|
|
370
|
+
keyframes: interpolation.keyframes.map((keyframe) => ({
|
|
371
|
+
...keyframe,
|
|
372
|
+
value: String(keyframe.value),
|
|
373
|
+
})),
|
|
374
|
+
};
|
|
375
|
+
}
|
|
356
376
|
if (node.type !== 'CallExpression') {
|
|
357
377
|
return undefined;
|
|
358
378
|
}
|
|
@@ -627,12 +647,18 @@ const computeSequenceOnlyPropsRecord = ({ jsxElement, ast, keys, }) => {
|
|
|
627
647
|
}
|
|
628
648
|
return filteredProps;
|
|
629
649
|
};
|
|
630
|
-
const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, keys, effects, }) => {
|
|
650
|
+
const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, effects, }) => {
|
|
631
651
|
const ast = (0, parse_ast_1.parseAst)(fileContents);
|
|
632
652
|
const jsxElement = (0, exports.findJsxElementAtNodePath)(ast, nodePath);
|
|
633
653
|
if (!jsxElement) {
|
|
634
654
|
throw new jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError();
|
|
635
655
|
}
|
|
656
|
+
if (!(0, jsx_component_identity_1.jsxComponentIdentitiesMatch)({
|
|
657
|
+
expected: componentIdentity,
|
|
658
|
+
actual: (0, jsx_component_identity_1.getJsxComponentIdentity)({ ast, jsxElement }),
|
|
659
|
+
})) {
|
|
660
|
+
throw new jsx_component_identity_1.JsxElementIdentityMismatchError();
|
|
661
|
+
}
|
|
636
662
|
const filteredProps = computeSequenceOnlyPropsRecord({ jsxElement, ast, keys });
|
|
637
663
|
const effectsStatuses = computeEffectsForJsx({ ast, jsxElement, effects });
|
|
638
664
|
return {
|
|
@@ -642,7 +668,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, keys, e
|
|
|
642
668
|
};
|
|
643
669
|
};
|
|
644
670
|
exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
|
|
645
|
-
const computeSequencePropsStatus = ({ fileName, nodePath, keys, effects, remotionRoot, }) => {
|
|
671
|
+
const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, keys, effects, remotionRoot, }) => {
|
|
646
672
|
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
647
673
|
remotionRoot,
|
|
648
674
|
fileName,
|
|
@@ -652,12 +678,13 @@ const computeSequencePropsStatus = ({ fileName, nodePath, keys, effects, remotio
|
|
|
652
678
|
return (0, exports.computeSequencePropsStatusFromContent)({
|
|
653
679
|
fileContents,
|
|
654
680
|
nodePath,
|
|
681
|
+
componentIdentity,
|
|
655
682
|
keys,
|
|
656
683
|
effects,
|
|
657
684
|
});
|
|
658
685
|
};
|
|
659
686
|
exports.computeSequencePropsStatus = computeSequencePropsStatus;
|
|
660
|
-
const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, keys, effects, remotionRoot, logLevel, }) => {
|
|
687
|
+
const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, componentIdentity, keys, effects, remotionRoot, logLevel, }) => {
|
|
661
688
|
try {
|
|
662
689
|
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
663
690
|
remotionRoot,
|
|
@@ -680,6 +707,7 @@ const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, keys, ef
|
|
|
680
707
|
status: (0, exports.computeSequencePropsStatus)({
|
|
681
708
|
fileName,
|
|
682
709
|
nodePath: resolvedNodePath,
|
|
710
|
+
componentIdentity,
|
|
683
711
|
keys,
|
|
684
712
|
effects,
|
|
685
713
|
remotionRoot,
|
|
@@ -215,6 +215,7 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
|
|
|
215
215
|
fileContents: output,
|
|
216
216
|
keys: (0, studio_shared_1.getAllSchemaKeys)(keyframe.schema),
|
|
217
217
|
nodePath: keyframe.nodePath.nodePath,
|
|
218
|
+
componentIdentity: null,
|
|
218
219
|
effects: [],
|
|
219
220
|
});
|
|
220
221
|
return {
|
|
@@ -13,9 +13,10 @@ const validate_same_origin_1 = require("../validate-same-origin");
|
|
|
13
13
|
const maxRemoteAssetSize = 50 * 1024 * 1024;
|
|
14
14
|
const remoteAssetDownloadTimeout = 15000;
|
|
15
15
|
const maxRemoteAssetRedirects = 5;
|
|
16
|
-
const remoteAssetAcceptHeader = 'image/png,image/jpeg,image/webp,image/bmp,image/gif';
|
|
16
|
+
const remoteAssetAcceptHeader = 'image/png,image/apng,image/jpeg,image/webp,image/bmp,image/gif';
|
|
17
17
|
const extensionsForFileType = {
|
|
18
18
|
png: ['png'],
|
|
19
|
+
apng: ['png', 'apng'],
|
|
19
20
|
jpeg: ['jpg', 'jpeg'],
|
|
20
21
|
webp: ['webp'],
|
|
21
22
|
bmp: ['bmp'],
|
|
@@ -253,10 +254,15 @@ const downloadRemoteAssetHandler = async ({ input, publicDir, request }) => {
|
|
|
253
254
|
}
|
|
254
255
|
const element = {
|
|
255
256
|
type: 'asset',
|
|
256
|
-
assetType: fileType.type === 'gif'
|
|
257
|
+
assetType: fileType.type === 'gif'
|
|
258
|
+
? 'gif'
|
|
259
|
+
: fileType.type === 'apng'
|
|
260
|
+
? 'animated-image'
|
|
261
|
+
: 'image',
|
|
257
262
|
src: assetPath,
|
|
258
263
|
srcType: 'static',
|
|
259
264
|
dimensions: fileType.dimensions,
|
|
265
|
+
position: null,
|
|
260
266
|
};
|
|
261
267
|
return {
|
|
262
268
|
assetPath,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.duplicateEffectHandler = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const renderer_1 = require("@remotion/renderer");
|
|
6
|
+
const duplicate_effect_1 = require("../../codemods/duplicate-effect");
|
|
7
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
8
|
+
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
9
|
+
const format_log_file_location_1 = require("../format-log-file-location");
|
|
10
|
+
const undo_stack_1 = require("../undo-stack");
|
|
11
|
+
const formatting_1 = require("./log-updates/formatting");
|
|
12
|
+
const log_update_1 = require("./log-updates/log-update");
|
|
13
|
+
const getDuplicatedEffectDescription = (effectLabels) => {
|
|
14
|
+
if (effectLabels.length === 1) {
|
|
15
|
+
return effectLabels[0];
|
|
16
|
+
}
|
|
17
|
+
return `${effectLabels.length} effects`;
|
|
18
|
+
};
|
|
19
|
+
const duplicateEffectHandler = async ({ input: effects, remotionRoot, logLevel }) => {
|
|
20
|
+
var _a;
|
|
21
|
+
try {
|
|
22
|
+
if (effects.length === 0) {
|
|
23
|
+
throw new Error('No effects were specified for duplication');
|
|
24
|
+
}
|
|
25
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[duplicate-effect] Received request to duplicate ${effects.length} effect target${effects.length === 1 ? '' : 's'}`);
|
|
26
|
+
const itemsByFileName = new Map();
|
|
27
|
+
for (const item of effects) {
|
|
28
|
+
const fileItems = (_a = itemsByFileName.get(item.fileName)) !== null && _a !== void 0 ? _a : [];
|
|
29
|
+
fileItems.push(item);
|
|
30
|
+
itemsByFileName.set(item.fileName, fileItems);
|
|
31
|
+
}
|
|
32
|
+
const updates = await Promise.all([...itemsByFileName.entries()].map(async ([fileName, fileItems]) => {
|
|
33
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
34
|
+
remotionRoot,
|
|
35
|
+
fileName,
|
|
36
|
+
action: 'modify',
|
|
37
|
+
});
|
|
38
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
39
|
+
const { output, formatted, effectLabels, logLines } = await (0, duplicate_effect_1.duplicateEffects)({
|
|
40
|
+
input: fileContents,
|
|
41
|
+
effects: fileItems.map((item) => ({
|
|
42
|
+
sequenceNodePath: item.sequenceNodePath.nodePath,
|
|
43
|
+
effectIndex: item.effectIndex,
|
|
44
|
+
})),
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
absolutePath,
|
|
48
|
+
fileRelativeToRoot,
|
|
49
|
+
fileContents,
|
|
50
|
+
output,
|
|
51
|
+
formatted,
|
|
52
|
+
effectLabels,
|
|
53
|
+
logLine: Math.min(...logLines),
|
|
54
|
+
};
|
|
55
|
+
}));
|
|
56
|
+
for (const update of updates) {
|
|
57
|
+
const duplicatedEffectDescription = getDuplicatedEffectDescription(update.effectLabels);
|
|
58
|
+
(0, undo_stack_1.pushToUndoStack)({
|
|
59
|
+
filePath: update.absolutePath,
|
|
60
|
+
oldContents: update.fileContents,
|
|
61
|
+
newContents: null,
|
|
62
|
+
logLevel,
|
|
63
|
+
remotionRoot,
|
|
64
|
+
logLine: update.logLine,
|
|
65
|
+
description: {
|
|
66
|
+
undoMessage: `↩️ Duplication of ${duplicatedEffectDescription}`,
|
|
67
|
+
redoMessage: `↪️ Duplication of ${duplicatedEffectDescription}`,
|
|
68
|
+
},
|
|
69
|
+
entryType: 'duplicate-effect',
|
|
70
|
+
suppressHmrOnFileRestore: false,
|
|
71
|
+
});
|
|
72
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(update.absolutePath);
|
|
73
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(update.absolutePath, update.output, undefined);
|
|
74
|
+
const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
|
|
75
|
+
remotionRoot,
|
|
76
|
+
absolutePath: update.absolutePath,
|
|
77
|
+
line: update.logLine,
|
|
78
|
+
});
|
|
79
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${(0, formatting_1.attrName)(duplicatedEffectDescription)}`);
|
|
80
|
+
if (!update.formatted) {
|
|
81
|
+
(0, log_update_1.warnAboutPrettierOnce)(logLevel);
|
|
82
|
+
}
|
|
83
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[duplicate-effect] Wrote ${update.fileRelativeToRoot}${update.formatted ? ' (formatted)' : ''}`);
|
|
84
|
+
}
|
|
85
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
86
|
+
return {
|
|
87
|
+
success: true,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
reason: err.message,
|
|
94
|
+
stack: err.stack,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
exports.duplicateEffectHandler = duplicateEffectHandler;
|
|
@@ -14,7 +14,16 @@ const validateDimension = (name, value) => {
|
|
|
14
14
|
throw new Error(`${name} must be a positive number`);
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
+
const validatePosition = (position) => {
|
|
18
|
+
if (position === null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!Number.isFinite(position.x) || !Number.isFinite(position.y)) {
|
|
22
|
+
throw new Error('Position must be finite');
|
|
23
|
+
}
|
|
24
|
+
};
|
|
17
25
|
const validateElement = (element) => {
|
|
26
|
+
validatePosition(element.position);
|
|
18
27
|
if (element.type === 'solid') {
|
|
19
28
|
validateDimension('width', element.width);
|
|
20
29
|
validateDimension('height', element.height);
|
|
@@ -66,6 +75,9 @@ const getElementLabel = (element) => {
|
|
|
66
75
|
if (element.assetType === 'gif') {
|
|
67
76
|
return '<Gif>';
|
|
68
77
|
}
|
|
78
|
+
if (element.assetType === 'animated-image') {
|
|
79
|
+
return '<AnimatedImage>';
|
|
80
|
+
}
|
|
69
81
|
if (element.assetType === 'audio') {
|
|
70
82
|
return '<Audio>';
|
|
71
83
|
}
|
|
@@ -145,6 +145,7 @@ const saveSequencePropsHandler = ({ input: { edits, clientId, undoLabel, redoLab
|
|
|
145
145
|
fileContents: output,
|
|
146
146
|
keys: (0, studio_shared_1.getAllSchemaKeys)(edit.schema),
|
|
147
147
|
nodePath: edit.nodePath.nodePath,
|
|
148
|
+
componentIdentity: null,
|
|
148
149
|
effects: [],
|
|
149
150
|
});
|
|
150
151
|
return {
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.subscribeToSequenceProps = void 0;
|
|
4
4
|
const sequence_props_watchers_1 = require("../sequence-props-watchers");
|
|
5
|
-
const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, keys, effects, clientId }, remotionRoot, logLevel, }) => {
|
|
5
|
+
const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, componentIdentity, keys, effects, clientId, }, remotionRoot, logLevel, }) => {
|
|
6
6
|
const result = (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
|
|
7
7
|
fileName,
|
|
8
8
|
line,
|
|
9
9
|
column,
|
|
10
10
|
nodePath,
|
|
11
|
+
componentIdentity,
|
|
11
12
|
keys,
|
|
12
13
|
effects,
|
|
13
14
|
remotionRoot,
|
|
@@ -77,6 +77,7 @@ const updateSequenceKeyframeSettingsHandler = ({ input: { fileName, nodePath, ke
|
|
|
77
77
|
fileContents: output,
|
|
78
78
|
keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
|
|
79
79
|
nodePath: updatedNodePath,
|
|
80
|
+
componentIdentity: null,
|
|
80
81
|
effects: [],
|
|
81
82
|
});
|
|
82
83
|
const updatedSubscriptionKey = { ...nodePath, nodePath: updatedNodePath };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
|
|
2
2
|
import type { SequenceNodePath } from 'remotion';
|
|
3
|
-
export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, keys, effects, remotionRoot, clientId, logLevel, }: {
|
|
3
|
+
export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, effects, remotionRoot, clientId, logLevel, }: {
|
|
4
4
|
fileName: string;
|
|
5
5
|
line: number;
|
|
6
6
|
column: number;
|
|
7
7
|
nodePath: SequenceNodePath | null;
|
|
8
|
+
componentIdentity: string | null;
|
|
8
9
|
keys: string[];
|
|
9
10
|
effects: string[][];
|
|
10
11
|
remotionRoot: string;
|
|
@@ -8,42 +8,64 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
8
8
|
const renderer_1 = require("@remotion/renderer");
|
|
9
9
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
10
10
|
const file_watcher_1 = require("../file-watcher");
|
|
11
|
+
const jsx_component_identity_1 = require("./jsx-component-identity");
|
|
11
12
|
const jsx_element_not_found_at_location_error_1 = require("./jsx-element-not-found-at-location-error");
|
|
12
13
|
const live_events_1 = require("./live-events");
|
|
13
14
|
const node_path_cache_1 = require("./node-path-cache");
|
|
14
15
|
const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
|
|
15
16
|
const sequencePropsWatchers = {};
|
|
16
|
-
const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, keys, effects, remotionRoot, logLevel, }) => {
|
|
17
|
+
const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, componentIdentity, keys, effects, remotionRoot, logLevel, }) => {
|
|
17
18
|
if (preferredNodePath) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
keys,
|
|
22
|
-
effects,
|
|
23
|
-
remotionRoot,
|
|
24
|
-
});
|
|
25
|
-
return {
|
|
26
|
-
status: fromNodePath,
|
|
27
|
-
nodePath: {
|
|
28
|
-
absolutePath: node_path_1.default.resolve(remotionRoot, fileName),
|
|
19
|
+
try {
|
|
20
|
+
const fromNodePath = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
|
|
21
|
+
fileName,
|
|
29
22
|
nodePath: preferredNodePath,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
componentIdentity,
|
|
24
|
+
keys,
|
|
25
|
+
effects,
|
|
26
|
+
remotionRoot,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
status: fromNodePath,
|
|
30
|
+
nodePath: {
|
|
31
|
+
absolutePath: node_path_1.default.resolve(remotionRoot, fileName),
|
|
32
|
+
nodePath: preferredNodePath,
|
|
33
|
+
sequenceKeys: keys,
|
|
34
|
+
effectKeys: effects,
|
|
35
|
+
},
|
|
36
|
+
success: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (!(error instanceof jsx_component_identity_1.JsxElementIdentityMismatchError ||
|
|
41
|
+
error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError)) {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
46
|
// Try cached nodePath first (handles stale source maps after suppressed rebuilds)
|
|
37
47
|
const cachedNodePath = (0, node_path_cache_1.getCachedNodePath)(fileName, line, column);
|
|
38
48
|
if (cachedNodePath) {
|
|
39
|
-
const cachedResult = (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
const cachedResult = (() => {
|
|
50
|
+
try {
|
|
51
|
+
return (0, can_update_sequence_props_1.computeSequencePropsStatus)({
|
|
52
|
+
fileName,
|
|
53
|
+
nodePath: cachedNodePath,
|
|
54
|
+
componentIdentity,
|
|
55
|
+
keys,
|
|
56
|
+
effects,
|
|
57
|
+
remotionRoot,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (error instanceof jsx_component_identity_1.JsxElementIdentityMismatchError ||
|
|
62
|
+
error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
})();
|
|
68
|
+
if (cachedResult === null || cachedResult === void 0 ? void 0 : cachedResult.canUpdate) {
|
|
47
69
|
return {
|
|
48
70
|
status: cachedResult,
|
|
49
71
|
nodePath: {
|
|
@@ -59,6 +81,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, key
|
|
|
59
81
|
const status = (0, can_update_sequence_props_1.computeSequencePropsStatusFromFilenameByLine)({
|
|
60
82
|
fileName,
|
|
61
83
|
line,
|
|
84
|
+
componentIdentity,
|
|
62
85
|
keys,
|
|
63
86
|
effects,
|
|
64
87
|
remotionRoot,
|
|
@@ -66,13 +89,14 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, key
|
|
|
66
89
|
});
|
|
67
90
|
return status;
|
|
68
91
|
};
|
|
69
|
-
const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, keys, effects, remotionRoot, clientId, logLevel, }) => {
|
|
92
|
+
const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, effects, remotionRoot, clientId, logLevel, }) => {
|
|
70
93
|
var _a;
|
|
71
94
|
const initialResult = getSequencePropsStatus({
|
|
72
95
|
fileName,
|
|
73
96
|
line,
|
|
74
97
|
column,
|
|
75
98
|
preferredNodePath,
|
|
99
|
+
componentIdentity,
|
|
76
100
|
keys,
|
|
77
101
|
effects,
|
|
78
102
|
remotionRoot,
|
|
@@ -105,6 +129,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
|
|
|
105
129
|
const result = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
|
|
106
130
|
fileContents: event.content,
|
|
107
131
|
nodePath: nodePath.nodePath,
|
|
132
|
+
componentIdentity,
|
|
108
133
|
keys,
|
|
109
134
|
effects,
|
|
110
135
|
});
|
|
@@ -125,7 +150,8 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
|
|
|
125
150
|
});
|
|
126
151
|
}
|
|
127
152
|
catch (error) {
|
|
128
|
-
if (error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError
|
|
153
|
+
if (error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError ||
|
|
154
|
+
error instanceof jsx_component_identity_1.JsxElementIdentityMismatchError) {
|
|
129
155
|
(0, live_events_1.waitForLiveEventsListener)().then((listener) => {
|
|
130
156
|
listener.sendEventToClientId(clientId, {
|
|
131
157
|
type: 'lost-node-path',
|
|
@@ -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' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'insert-jsx-element' | 'delete-composition' | 'rename-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' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'duplicate-composition' | 'delete-folder' | 'rename-folder';
|
|
7
7
|
type UndoEntrySnapshot = {
|
|
8
8
|
filePath: string;
|
|
9
9
|
oldContents: string;
|
|
@@ -35,6 +35,8 @@ type UndoEntry = {
|
|
|
35
35
|
entryType: 'add-effect';
|
|
36
36
|
} | {
|
|
37
37
|
entryType: 'delete-effect';
|
|
38
|
+
} | {
|
|
39
|
+
entryType: 'duplicate-effect';
|
|
38
40
|
} | {
|
|
39
41
|
entryType: 'paste-effects';
|
|
40
42
|
} | {
|
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.478",
|
|
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.478",
|
|
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.478",
|
|
33
|
+
"@remotion/renderer": "4.0.478",
|
|
34
|
+
"@remotion/studio-shared": "4.0.478",
|
|
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.478",
|
|
43
43
|
"eslint": "9.19.0",
|
|
44
44
|
"@types/node": "20.12.14",
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|