@remotion/studio-server 4.0.465 → 4.0.467
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-effect-props/update-effect-props.d.ts +11 -3
- package/dist/codemods/update-effect-props/update-effect-props.js +43 -3
- package/dist/helpers/resolve-composition-component.d.ts +11 -0
- package/dist/helpers/resolve-composition-component.js +691 -0
- package/dist/preview-server/routes/add-render.js +1 -0
- package/dist/preview-server/routes/can-update-effect-props.js +1 -1
- package/dist/preview-server/routes/can-update-sequence-props.d.ts +2 -3
- package/dist/preview-server/routes/can-update-sequence-props.js +77 -4
- package/dist/preview-server/routes/log-updates/formatting.js +3 -1
- package/dist/preview-server/routes/save-effect-props.js +9 -4
- package/dist/routes.js +39 -0
- package/package.json +6 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ArrayExpression, CallExpression, JSXAttribute } from '@babel/types';
|
|
2
|
-
import type { SequenceNodePath } from 'remotion';
|
|
2
|
+
import type { SequenceNodePath, SequenceSchema } from 'remotion';
|
|
3
3
|
export type EffectPropUpdate = {
|
|
4
4
|
key: string;
|
|
5
5
|
value: unknown;
|
|
@@ -11,6 +11,11 @@ export type UpdateEffectPropsResult = {
|
|
|
11
11
|
oldValueString: string;
|
|
12
12
|
logLine: number;
|
|
13
13
|
effectCallee: string;
|
|
14
|
+
removedProps: PropDelta[];
|
|
15
|
+
};
|
|
16
|
+
export type PropDelta = {
|
|
17
|
+
key: string;
|
|
18
|
+
valueString: string;
|
|
14
19
|
};
|
|
15
20
|
export declare const findEffectsAttr: (attrs: readonly unknown[]) => JSXAttribute | null;
|
|
16
21
|
export type EffectArrayElement = {
|
|
@@ -33,21 +38,24 @@ export declare const findEffectCallExpression: ({ attr, effectIndex, }: {
|
|
|
33
38
|
kind: "error";
|
|
34
39
|
reason: "not-call-expression" | "not-found";
|
|
35
40
|
};
|
|
36
|
-
export declare const updateEffectPropsAst: ({ input, sequenceNodePath, effectIndex, update, }: {
|
|
41
|
+
export declare const updateEffectPropsAst: ({ input, sequenceNodePath, effectIndex, update, schema, }: {
|
|
37
42
|
input: string;
|
|
38
43
|
sequenceNodePath: SequenceNodePath;
|
|
39
44
|
effectIndex: number;
|
|
40
45
|
update: EffectPropUpdate;
|
|
46
|
+
schema: SequenceSchema;
|
|
41
47
|
}) => {
|
|
42
48
|
serialized: string;
|
|
43
49
|
oldValueString: string;
|
|
44
50
|
logLine: number;
|
|
45
51
|
effectCallee: string;
|
|
52
|
+
removedProps: PropDelta[];
|
|
46
53
|
};
|
|
47
|
-
export declare const updateEffectProps: ({ input, sequenceNodePath, effectIndex, update, prettierConfigOverride, }: {
|
|
54
|
+
export declare const updateEffectProps: ({ input, sequenceNodePath, effectIndex, update, schema, prettierConfigOverride, }: {
|
|
48
55
|
input: string;
|
|
49
56
|
sequenceNodePath: SequenceNodePath;
|
|
50
57
|
effectIndex: number;
|
|
51
58
|
update: EffectPropUpdate;
|
|
59
|
+
schema: SequenceSchema;
|
|
52
60
|
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
53
61
|
}) => Promise<UpdateEffectPropsResult>;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.updateEffectProps = exports.updateEffectPropsAst = exports.findEffectCallExpression = exports.enumerateEffectArrayElements = exports.findEffectsAttr = void 0;
|
|
37
37
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
38
38
|
const recast = __importStar(require("recast"));
|
|
39
|
+
const no_react_1 = require("remotion/no-react");
|
|
39
40
|
const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
|
|
40
41
|
const format_file_content_1 = require("../format-file-content");
|
|
41
42
|
const parse_ast_1 = require("../parse-ast");
|
|
@@ -132,7 +133,24 @@ const findObjectProperty = (objExpr, propertyName) => {
|
|
|
132
133
|
: undefined,
|
|
133
134
|
};
|
|
134
135
|
};
|
|
135
|
-
const
|
|
136
|
+
const printObjectPropertyValue = (prop) => recast
|
|
137
|
+
.print(prop.value)
|
|
138
|
+
.code.replace(/[\n\r\t]+/g, ' ')
|
|
139
|
+
.replace(/,(\s*[}\]])/g, '$1')
|
|
140
|
+
.trim();
|
|
141
|
+
const removeObjectProperty = ({ objExpr, propertyName, }) => {
|
|
142
|
+
const { propIndex, prop } = findObjectProperty(objExpr, propertyName);
|
|
143
|
+
if (!prop || propIndex === -1) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const valueString = printObjectPropertyValue(prop);
|
|
147
|
+
objExpr.properties.splice(propIndex, 1);
|
|
148
|
+
return {
|
|
149
|
+
key: propertyName,
|
|
150
|
+
valueString,
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, schema, }) => {
|
|
136
154
|
var _a, _b, _c, _d;
|
|
137
155
|
var _e, _f, _g, _h, _j;
|
|
138
156
|
const ast = (0, parse_ast_1.parseAst)(input);
|
|
@@ -162,6 +180,7 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
|
|
|
162
180
|
oldValueString: '',
|
|
163
181
|
logLine: (_g = (_f = (_a = call.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _f !== void 0 ? _f : (_b = jsx.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _g !== void 0 ? _g : 1,
|
|
164
182
|
effectCallee,
|
|
183
|
+
removedProps: [],
|
|
165
184
|
};
|
|
166
185
|
}
|
|
167
186
|
objExpr = b.objectExpression([]);
|
|
@@ -174,6 +193,7 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
|
|
|
174
193
|
objExpr = call.arguments[0];
|
|
175
194
|
}
|
|
176
195
|
const { prop } = findObjectProperty(objExpr, update.key);
|
|
196
|
+
const removedProps = [];
|
|
177
197
|
let oldValueString = '';
|
|
178
198
|
if (prop) {
|
|
179
199
|
oldValueString = recast.print(prop.value).code;
|
|
@@ -198,21 +218,40 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
|
|
|
198
218
|
objExpr.properties.push(b.objectProperty(b.identifier(update.key), newValueExpr));
|
|
199
219
|
}
|
|
200
220
|
}
|
|
221
|
+
const fieldSchema = schema[update.key];
|
|
222
|
+
if (fieldSchema && fieldSchema.type === 'enum') {
|
|
223
|
+
const propsToDelete = no_react_1.NoReactInternals.findPropsToDelete({
|
|
224
|
+
schema,
|
|
225
|
+
key: update.key,
|
|
226
|
+
value: update.value,
|
|
227
|
+
});
|
|
228
|
+
for (const propToDelete of propsToDelete) {
|
|
229
|
+
const removed = removeObjectProperty({
|
|
230
|
+
objExpr,
|
|
231
|
+
propertyName: propToDelete,
|
|
232
|
+
});
|
|
233
|
+
if (removed) {
|
|
234
|
+
removedProps.push(removed);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
201
238
|
const logLine = (_j = (_h = (_c = call.loc) === null || _c === void 0 ? void 0 : _c.start.line) !== null && _h !== void 0 ? _h : (_d = jsx.loc) === null || _d === void 0 ? void 0 : _d.start.line) !== null && _j !== void 0 ? _j : 1;
|
|
202
239
|
return {
|
|
203
240
|
serialized: (0, parse_ast_1.serializeAst)(ast),
|
|
204
241
|
oldValueString,
|
|
205
242
|
logLine,
|
|
206
243
|
effectCallee,
|
|
244
|
+
removedProps,
|
|
207
245
|
};
|
|
208
246
|
};
|
|
209
247
|
exports.updateEffectPropsAst = updateEffectPropsAst;
|
|
210
|
-
const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update, prettierConfigOverride, }) => {
|
|
211
|
-
const { serialized, oldValueString, logLine, effectCallee } = (0, exports.updateEffectPropsAst)({
|
|
248
|
+
const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update, schema, prettierConfigOverride, }) => {
|
|
249
|
+
const { serialized, oldValueString, logLine, effectCallee, removedProps } = (0, exports.updateEffectPropsAst)({
|
|
212
250
|
input,
|
|
213
251
|
sequenceNodePath,
|
|
214
252
|
effectIndex,
|
|
215
253
|
update,
|
|
254
|
+
schema,
|
|
216
255
|
});
|
|
217
256
|
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
218
257
|
input: serialized,
|
|
@@ -224,6 +263,7 @@ const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update,
|
|
|
224
263
|
formatted,
|
|
225
264
|
logLine,
|
|
226
265
|
effectCallee,
|
|
266
|
+
removedProps,
|
|
227
267
|
};
|
|
228
268
|
};
|
|
229
269
|
exports.updateEffectProps = updateEffectProps;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ResolvedCompositionComponent = {
|
|
2
|
+
source: string;
|
|
3
|
+
line: number;
|
|
4
|
+
column: number;
|
|
5
|
+
canAddSequence: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare const resolveCompositionComponent: ({ remotionRoot, compositionFile, compositionId, }: {
|
|
8
|
+
remotionRoot: string;
|
|
9
|
+
compositionFile: string;
|
|
10
|
+
compositionId: string;
|
|
11
|
+
}) => Promise<ResolvedCompositionComponent>;
|
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.resolveCompositionComponent = void 0;
|
|
40
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
41
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
42
|
+
const recast = __importStar(require("recast"));
|
|
43
|
+
const parse_ast_1 = require("../codemods/parse-ast");
|
|
44
|
+
const allowedFileExtensions = new Set(['.tsx', '.ts', '.jsx', '.js']);
|
|
45
|
+
const extensionsToProbe = ['.tsx', '.ts', '.jsx', '.js'];
|
|
46
|
+
const isInRemotionRoot = ({ remotionRoot, fileName, }) => {
|
|
47
|
+
const relativePath = node_path_1.default.relative(remotionRoot, fileName);
|
|
48
|
+
return !relativePath.startsWith('..') && !node_path_1.default.isAbsolute(relativePath);
|
|
49
|
+
};
|
|
50
|
+
const readSourceFile = ({ remotionRoot, fileName, }) => {
|
|
51
|
+
const resolved = node_path_1.default.resolve(remotionRoot, fileName);
|
|
52
|
+
if (!isInRemotionRoot({ remotionRoot, fileName: resolved })) {
|
|
53
|
+
throw new Error(`Not allowed to open ${fileName}`);
|
|
54
|
+
}
|
|
55
|
+
if (!allowedFileExtensions.has(node_path_1.default.extname(resolved))) {
|
|
56
|
+
throw new Error(`Not allowed to open ${fileName}`);
|
|
57
|
+
}
|
|
58
|
+
return node_fs_1.default.promises.readFile(resolved, 'utf-8');
|
|
59
|
+
};
|
|
60
|
+
const getAttributeName = (attribute) => {
|
|
61
|
+
if (attribute.name.type !== 'JSXIdentifier') {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return attribute.name.name;
|
|
65
|
+
};
|
|
66
|
+
const findAttribute = (element, name) => {
|
|
67
|
+
return element.openingElement.attributes.find((attribute) => {
|
|
68
|
+
if (attribute.type !== 'JSXAttribute') {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return getAttributeName(attribute) === name;
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const getStringAttributeValue = (element, name) => {
|
|
75
|
+
const attribute = findAttribute(element, name);
|
|
76
|
+
if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (attribute.value.type === 'StringLiteral') {
|
|
80
|
+
return attribute.value.value;
|
|
81
|
+
}
|
|
82
|
+
if (attribute.value.type === 'JSXExpressionContainer' &&
|
|
83
|
+
attribute.value.expression.type === 'StringLiteral') {
|
|
84
|
+
return attribute.value.expression.value;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
};
|
|
88
|
+
const findCompositionElement = ({ ast, compositionId, }) => {
|
|
89
|
+
let found = null;
|
|
90
|
+
recast.types.visit(ast, {
|
|
91
|
+
visitJSXElement(astPath) {
|
|
92
|
+
if (found) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const node = astPath.node;
|
|
96
|
+
const openingName = node.openingElement.name;
|
|
97
|
+
if (openingName.type === 'JSXIdentifier' &&
|
|
98
|
+
(openingName.name === 'Composition' || openingName.name === 'Still') &&
|
|
99
|
+
getStringAttributeValue(node, 'id') === compositionId) {
|
|
100
|
+
found = node;
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
this.traverse(astPath);
|
|
104
|
+
return undefined;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
return found;
|
|
108
|
+
};
|
|
109
|
+
const getComponentIdentifier = (element) => {
|
|
110
|
+
const attribute = findAttribute(element, 'component');
|
|
111
|
+
if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value) ||
|
|
112
|
+
attribute.value.type !== 'JSXExpressionContainer' ||
|
|
113
|
+
attribute.value.expression.type !== 'Identifier') {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return attribute.value.expression.name;
|
|
117
|
+
};
|
|
118
|
+
const isRecord = (value) => {
|
|
119
|
+
return typeof value === 'object' && value !== null;
|
|
120
|
+
};
|
|
121
|
+
const findDynamicImportPath = (value) => {
|
|
122
|
+
if (!isRecord(value)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if (value.type === 'CallExpression' &&
|
|
126
|
+
isRecord(value.callee) &&
|
|
127
|
+
value.callee.type === 'Import' &&
|
|
128
|
+
Array.isArray(value.arguments) &&
|
|
129
|
+
isRecord(value.arguments[0]) &&
|
|
130
|
+
value.arguments[0].type === 'StringLiteral' &&
|
|
131
|
+
typeof value.arguments[0].value === 'string') {
|
|
132
|
+
return value.arguments[0].value;
|
|
133
|
+
}
|
|
134
|
+
for (const [key, child] of Object.entries(value)) {
|
|
135
|
+
if (key === 'loc' ||
|
|
136
|
+
key === 'start' ||
|
|
137
|
+
key === 'end' ||
|
|
138
|
+
key === 'comments' ||
|
|
139
|
+
key === 'leadingComments' ||
|
|
140
|
+
key === 'trailingComments' ||
|
|
141
|
+
key === 'innerComments' ||
|
|
142
|
+
key === 'extra' ||
|
|
143
|
+
key === 'original') {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(child)) {
|
|
147
|
+
for (const item of child) {
|
|
148
|
+
const nestedResult = findDynamicImportPath(item);
|
|
149
|
+
if (nestedResult) {
|
|
150
|
+
return nestedResult;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const childResult = findDynamicImportPath(child);
|
|
156
|
+
if (childResult) {
|
|
157
|
+
return childResult;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
};
|
|
162
|
+
const getLazyImportPath = (element) => {
|
|
163
|
+
const attribute = findAttribute(element, 'lazyComponent');
|
|
164
|
+
if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value) || attribute.value.type !== 'JSXExpressionContainer') {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return findDynamicImportPath(attribute.value.expression);
|
|
168
|
+
};
|
|
169
|
+
const findImportTarget = ({ ast, componentName, }) => {
|
|
170
|
+
let found = null;
|
|
171
|
+
recast.types.visit(ast, {
|
|
172
|
+
visitImportDeclaration(astPath) {
|
|
173
|
+
var _a;
|
|
174
|
+
if (found) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
const node = astPath.node;
|
|
178
|
+
if (typeof node.source.value !== 'string') {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
const matchingSpecifier = (_a = node.specifiers) === null || _a === void 0 ? void 0 : _a.find((specifier) => {
|
|
182
|
+
var _a;
|
|
183
|
+
return ((_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) === componentName;
|
|
184
|
+
});
|
|
185
|
+
if (!matchingSpecifier) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (matchingSpecifier.type === 'ImportDefaultSpecifier') {
|
|
189
|
+
found = {
|
|
190
|
+
importPath: node.source.value,
|
|
191
|
+
exportName: 'default',
|
|
192
|
+
};
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (matchingSpecifier.type === 'ImportSpecifier' &&
|
|
196
|
+
matchingSpecifier.imported.type === 'Identifier') {
|
|
197
|
+
found = {
|
|
198
|
+
importPath: node.source.value,
|
|
199
|
+
exportName: matchingSpecifier.imported.name,
|
|
200
|
+
};
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (matchingSpecifier.type === 'ImportSpecifier' &&
|
|
204
|
+
matchingSpecifier.imported.type === 'StringLiteral') {
|
|
205
|
+
found = {
|
|
206
|
+
importPath: node.source.value,
|
|
207
|
+
exportName: matchingSpecifier.imported.value,
|
|
208
|
+
};
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
return found;
|
|
215
|
+
};
|
|
216
|
+
const getExportedName = (exported) => {
|
|
217
|
+
if (!exported) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
if (!isRecord(exported)) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
if (exported.type === 'Identifier' && typeof exported.name === 'string') {
|
|
224
|
+
return exported.name;
|
|
225
|
+
}
|
|
226
|
+
if (exported.type === 'StringLiteral' && typeof exported.value === 'string') {
|
|
227
|
+
return exported.value;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
};
|
|
231
|
+
const getSpecifierLocalName = (specifier) => {
|
|
232
|
+
if (specifier.local.type === 'Identifier') {
|
|
233
|
+
return specifier.local.name;
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
};
|
|
237
|
+
const findReExportTargets = ({ ast, exportName, }) => {
|
|
238
|
+
const targets = [];
|
|
239
|
+
recast.types.visit(ast, {
|
|
240
|
+
visitExportNamedDeclaration(astPath) {
|
|
241
|
+
var _a;
|
|
242
|
+
const node = astPath.node;
|
|
243
|
+
if (typeof ((_a = node.source) === null || _a === void 0 ? void 0 : _a.value) !== 'string') {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
for (const specifier of node.specifiers) {
|
|
247
|
+
if (specifier.type !== 'ExportSpecifier') {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const exportedName = getExportedName(specifier.exported);
|
|
251
|
+
if (exportedName !== exportName) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const localName = getSpecifierLocalName(specifier);
|
|
255
|
+
if (!localName) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
targets.push({
|
|
259
|
+
importPath: node.source.value,
|
|
260
|
+
exportName: localName === 'default' ? 'default' : localName,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
},
|
|
265
|
+
visitExportAllDeclaration(astPath) {
|
|
266
|
+
const node = astPath.node;
|
|
267
|
+
if (typeof node.source.value !== 'string') {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
targets.push({
|
|
271
|
+
importPath: node.source.value,
|
|
272
|
+
exportName,
|
|
273
|
+
});
|
|
274
|
+
return false;
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
return targets;
|
|
278
|
+
};
|
|
279
|
+
const resolveImportPath = ({ importPath, fromFile, }) => {
|
|
280
|
+
if (!importPath.startsWith('.')) {
|
|
281
|
+
throw new Error(`Cannot resolve non-relative import ${importPath}`);
|
|
282
|
+
}
|
|
283
|
+
const basePath = node_path_1.default.resolve(node_path_1.default.dirname(fromFile), importPath);
|
|
284
|
+
const candidates = node_path_1.default.extname(basePath)
|
|
285
|
+
? [basePath]
|
|
286
|
+
: [
|
|
287
|
+
...extensionsToProbe.map((extension) => `${basePath}${extension}`),
|
|
288
|
+
...extensionsToProbe.map((extension) => node_path_1.default.join(basePath, `index${extension}`)),
|
|
289
|
+
];
|
|
290
|
+
const existingFile = candidates.find((candidate) => {
|
|
291
|
+
return node_fs_1.default.existsSync(candidate) && node_fs_1.default.statSync(candidate).isFile();
|
|
292
|
+
});
|
|
293
|
+
if (!existingFile) {
|
|
294
|
+
throw new Error(`Could not find imported component file ${importPath}`);
|
|
295
|
+
}
|
|
296
|
+
return existingFile;
|
|
297
|
+
};
|
|
298
|
+
const locationFromNode = (node) => {
|
|
299
|
+
if (!node.loc) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
line: node.loc.start.line,
|
|
304
|
+
column: node.loc.start.column,
|
|
305
|
+
};
|
|
306
|
+
};
|
|
307
|
+
const findLocalSymbolLocation = ({ ast, name, }) => {
|
|
308
|
+
let location = null;
|
|
309
|
+
recast.types.visit(ast, {
|
|
310
|
+
visitVariableDeclarator(astPath) {
|
|
311
|
+
if (location) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
const { node } = astPath;
|
|
315
|
+
if (node.id.type === 'Identifier' && node.id.name === name) {
|
|
316
|
+
location = locationFromNode(node);
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
this.traverse(astPath);
|
|
320
|
+
return undefined;
|
|
321
|
+
},
|
|
322
|
+
visitFunctionDeclaration(astPath) {
|
|
323
|
+
var _a;
|
|
324
|
+
if (location) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
const { node } = astPath;
|
|
328
|
+
if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
|
|
329
|
+
location = locationFromNode(node);
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
this.traverse(astPath);
|
|
333
|
+
return undefined;
|
|
334
|
+
},
|
|
335
|
+
visitClassDeclaration(astPath) {
|
|
336
|
+
var _a;
|
|
337
|
+
if (location) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
const { node } = astPath;
|
|
341
|
+
if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
|
|
342
|
+
location = locationFromNode(node);
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
this.traverse(astPath);
|
|
346
|
+
return undefined;
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
return location;
|
|
350
|
+
};
|
|
351
|
+
const findDefaultExportLocation = (ast) => {
|
|
352
|
+
let location = null;
|
|
353
|
+
let exportedIdentifier = null;
|
|
354
|
+
recast.types.visit(ast, {
|
|
355
|
+
visitExportDefaultDeclaration(astPath) {
|
|
356
|
+
var _a;
|
|
357
|
+
if (location || exportedIdentifier) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
const { node } = astPath;
|
|
361
|
+
if (node.declaration.type === 'Identifier') {
|
|
362
|
+
exportedIdentifier = node.declaration.name;
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
location = (_a = locationFromNode(node.declaration)) !== null && _a !== void 0 ? _a : locationFromNode(node);
|
|
366
|
+
return false;
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
if (exportedIdentifier) {
|
|
370
|
+
return findLocalSymbolLocation({ ast, name: exportedIdentifier });
|
|
371
|
+
}
|
|
372
|
+
return location;
|
|
373
|
+
};
|
|
374
|
+
const findLocalComponentDeclaration = ({ ast, name, }) => {
|
|
375
|
+
let declaration = null;
|
|
376
|
+
recast.types.visit(ast, {
|
|
377
|
+
visitVariableDeclarator(astPath) {
|
|
378
|
+
if (declaration) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
const { node } = astPath;
|
|
382
|
+
if (node.id.type === 'Identifier' && node.id.name === name) {
|
|
383
|
+
declaration = node;
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
this.traverse(astPath);
|
|
387
|
+
return undefined;
|
|
388
|
+
},
|
|
389
|
+
visitFunctionDeclaration(astPath) {
|
|
390
|
+
var _a;
|
|
391
|
+
if (declaration) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
const { node } = astPath;
|
|
395
|
+
if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
|
|
396
|
+
declaration = node;
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
this.traverse(astPath);
|
|
400
|
+
return undefined;
|
|
401
|
+
},
|
|
402
|
+
visitClassDeclaration(astPath) {
|
|
403
|
+
var _a;
|
|
404
|
+
if (declaration) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
const { node } = astPath;
|
|
408
|
+
if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
|
|
409
|
+
declaration = node;
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
this.traverse(astPath);
|
|
413
|
+
return undefined;
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
return declaration;
|
|
417
|
+
};
|
|
418
|
+
const getTopLevelReturnStatement = (statements) => {
|
|
419
|
+
const returnStatements = [];
|
|
420
|
+
for (const statement of statements) {
|
|
421
|
+
if (recast.types.namedTypes.ReturnStatement.check(statement)) {
|
|
422
|
+
returnStatements.push(statement);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (returnStatements.length !== 1) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
const singleReturn = returnStatements[0];
|
|
429
|
+
const finalStatement = statements.at(-1);
|
|
430
|
+
if (singleReturn !== finalStatement) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
return singleReturn;
|
|
434
|
+
};
|
|
435
|
+
const getReturnedJsxFromFunction = (fn) => {
|
|
436
|
+
if (fn.type === 'ArrowFunctionExpression') {
|
|
437
|
+
if (fn.body.type === 'JSXElement' || fn.body.type === 'JSXFragment') {
|
|
438
|
+
return fn.body;
|
|
439
|
+
}
|
|
440
|
+
if (fn.body.type !== 'BlockStatement') {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
const arrowReturnStatement = getTopLevelReturnStatement(fn.body.body);
|
|
444
|
+
if (!(arrowReturnStatement === null || arrowReturnStatement === void 0 ? void 0 : arrowReturnStatement.argument)) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
return arrowReturnStatement.argument.type === 'JSXElement' ||
|
|
448
|
+
arrowReturnStatement.argument.type === 'JSXFragment'
|
|
449
|
+
? arrowReturnStatement.argument
|
|
450
|
+
: null;
|
|
451
|
+
}
|
|
452
|
+
if (fn.body.type !== 'BlockStatement') {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
const returnStatement = getTopLevelReturnStatement(fn.body.body);
|
|
456
|
+
if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument)) {
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
return returnStatement.argument.type === 'JSXElement' ||
|
|
460
|
+
returnStatement.argument.type === 'JSXFragment'
|
|
461
|
+
? returnStatement.argument
|
|
462
|
+
: null;
|
|
463
|
+
};
|
|
464
|
+
const findRenderMethod = (declaration) => {
|
|
465
|
+
const renderMethod = declaration.body.body.find((member) => {
|
|
466
|
+
return (member.type === 'ClassMethod' &&
|
|
467
|
+
member.kind === 'method' &&
|
|
468
|
+
member.key.type === 'Identifier' &&
|
|
469
|
+
member.key.name === 'render');
|
|
470
|
+
});
|
|
471
|
+
return (renderMethod === null || renderMethod === void 0 ? void 0 : renderMethod.type) === 'ClassMethod' ? renderMethod : null;
|
|
472
|
+
};
|
|
473
|
+
const getComponentRootNode = (declaration) => {
|
|
474
|
+
if (declaration.type === 'VariableDeclarator') {
|
|
475
|
+
if (!declaration.init ||
|
|
476
|
+
(declaration.init.type !== 'ArrowFunctionExpression' &&
|
|
477
|
+
declaration.init.type !== 'FunctionExpression')) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
return getReturnedJsxFromFunction(declaration.init);
|
|
481
|
+
}
|
|
482
|
+
if (declaration.type === 'ArrowFunctionExpression' ||
|
|
483
|
+
declaration.type === 'FunctionExpression' ||
|
|
484
|
+
declaration.type === 'FunctionDeclaration') {
|
|
485
|
+
return getReturnedJsxFromFunction(declaration);
|
|
486
|
+
}
|
|
487
|
+
if (declaration.type !== 'ClassDeclaration') {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
const renderMethod = findRenderMethod(declaration);
|
|
491
|
+
if (!renderMethod) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
const returnStatement = getTopLevelReturnStatement(renderMethod.body.body);
|
|
495
|
+
if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument)) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
return returnStatement.argument.type === 'JSXElement' ||
|
|
499
|
+
returnStatement.argument.type === 'JSXFragment'
|
|
500
|
+
? returnStatement.argument
|
|
501
|
+
: null;
|
|
502
|
+
};
|
|
503
|
+
const createSequenceElement = () => {
|
|
504
|
+
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier('Sequence'), []), recast.types.builders.jsxClosingElement(recast.types.builders.jsxIdentifier('Sequence')), []);
|
|
505
|
+
};
|
|
506
|
+
const getDefaultExportDeclaration = (ast) => {
|
|
507
|
+
let declaration = null;
|
|
508
|
+
let identifierName = null;
|
|
509
|
+
recast.types.visit(ast, {
|
|
510
|
+
visitExportDefaultDeclaration(astPath) {
|
|
511
|
+
if (declaration || identifierName) {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
const { node } = astPath;
|
|
515
|
+
if (node.declaration.type === 'Identifier') {
|
|
516
|
+
identifierName = node.declaration.name;
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
declaration = node.declaration;
|
|
520
|
+
return false;
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
if (identifierName) {
|
|
524
|
+
return findLocalComponentDeclaration({ ast, name: identifierName });
|
|
525
|
+
}
|
|
526
|
+
return declaration;
|
|
527
|
+
};
|
|
528
|
+
const getDeclarationByExportName = ({ ast, exportName, }) => {
|
|
529
|
+
if (exportName === 'default') {
|
|
530
|
+
return getDefaultExportDeclaration(ast);
|
|
531
|
+
}
|
|
532
|
+
return findLocalComponentDeclaration({ ast, name: exportName });
|
|
533
|
+
};
|
|
534
|
+
const canAddSequenceToComponent = ({ ast, exportName, }) => {
|
|
535
|
+
const declaration = getDeclarationByExportName({ ast, exportName });
|
|
536
|
+
if (!declaration) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
const rootNode = getComponentRootNode(declaration);
|
|
540
|
+
if (!rootNode) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
if (rootNode.type === 'JSXElement') {
|
|
544
|
+
if (rootNode.openingElement.selfClosing) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
if (!rootNode.children) {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
rootNode.children.push(createSequenceElement());
|
|
551
|
+
try {
|
|
552
|
+
recast.print(ast);
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
catch (_a) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (!rootNode.children) {
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
rootNode.children.push(createSequenceElement());
|
|
563
|
+
try {
|
|
564
|
+
recast.print(ast);
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
catch (_b) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
const getComponentLocationInFile = async ({ remotionRoot, fileName, exportName, }) => {
|
|
572
|
+
var _a, _b;
|
|
573
|
+
const input = await readSourceFile({ remotionRoot, fileName });
|
|
574
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
575
|
+
const astForSequenceSimulation = (0, parse_ast_1.parseAst)(input);
|
|
576
|
+
const location = exportName === 'default'
|
|
577
|
+
? findDefaultExportLocation(ast)
|
|
578
|
+
: findLocalSymbolLocation({ ast, name: exportName });
|
|
579
|
+
const canAddSequence = canAddSequenceToComponent({
|
|
580
|
+
ast: astForSequenceSimulation,
|
|
581
|
+
exportName,
|
|
582
|
+
});
|
|
583
|
+
return {
|
|
584
|
+
source: node_path_1.default.relative(remotionRoot, fileName),
|
|
585
|
+
line: (_a = location === null || location === void 0 ? void 0 : location.line) !== null && _a !== void 0 ? _a : 1,
|
|
586
|
+
column: (_b = location === null || location === void 0 ? void 0 : location.column) !== null && _b !== void 0 ? _b : 0,
|
|
587
|
+
canAddSequence,
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
const getComponentLocationRecursively = async ({ remotionRoot, fileName, exportName, visited, }) => {
|
|
591
|
+
const key = `${fileName}:${exportName}`;
|
|
592
|
+
if (visited.has(key)) {
|
|
593
|
+
throw new Error(`Could not resolve component export "${exportName}" in ${node_path_1.default.relative(remotionRoot, fileName)}`);
|
|
594
|
+
}
|
|
595
|
+
visited.add(key);
|
|
596
|
+
try {
|
|
597
|
+
const input = await readSourceFile({ remotionRoot, fileName });
|
|
598
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
599
|
+
const localDeclaration = getDeclarationByExportName({
|
|
600
|
+
ast,
|
|
601
|
+
exportName,
|
|
602
|
+
});
|
|
603
|
+
if (localDeclaration) {
|
|
604
|
+
return await getComponentLocationInFile({
|
|
605
|
+
remotionRoot,
|
|
606
|
+
fileName,
|
|
607
|
+
exportName,
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
const reExportTargets = findReExportTargets({
|
|
611
|
+
ast,
|
|
612
|
+
exportName,
|
|
613
|
+
});
|
|
614
|
+
for (const target of reExportTargets) {
|
|
615
|
+
try {
|
|
616
|
+
const resolvedImportPath = resolveImportPath({
|
|
617
|
+
importPath: target.importPath,
|
|
618
|
+
fromFile: fileName,
|
|
619
|
+
});
|
|
620
|
+
return await getComponentLocationRecursively({
|
|
621
|
+
remotionRoot,
|
|
622
|
+
fileName: resolvedImportPath,
|
|
623
|
+
exportName: target.exportName,
|
|
624
|
+
visited,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
catch (_a) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (reExportTargets.length > 0) {
|
|
632
|
+
throw new Error(`Could not resolve component export "${exportName}" in ${node_path_1.default.relative(remotionRoot, fileName)}`);
|
|
633
|
+
}
|
|
634
|
+
return await getComponentLocationInFile({
|
|
635
|
+
remotionRoot,
|
|
636
|
+
fileName,
|
|
637
|
+
exportName,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
finally {
|
|
641
|
+
visited.delete(key);
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
const resolveCompositionComponent = async ({ remotionRoot, compositionFile, compositionId, }) => {
|
|
645
|
+
const compositionFileName = node_path_1.default.resolve(remotionRoot, compositionFile);
|
|
646
|
+
const input = await readSourceFile({
|
|
647
|
+
remotionRoot,
|
|
648
|
+
fileName: compositionFileName,
|
|
649
|
+
});
|
|
650
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
651
|
+
const compositionElement = findCompositionElement({ ast, compositionId });
|
|
652
|
+
if (!compositionElement) {
|
|
653
|
+
throw new Error(`Could not find composition "${compositionId}"`);
|
|
654
|
+
}
|
|
655
|
+
const lazyImportPath = getLazyImportPath(compositionElement);
|
|
656
|
+
if (lazyImportPath) {
|
|
657
|
+
const lazyComponentFile = resolveImportPath({
|
|
658
|
+
importPath: lazyImportPath,
|
|
659
|
+
fromFile: compositionFileName,
|
|
660
|
+
});
|
|
661
|
+
return getComponentLocationRecursively({
|
|
662
|
+
remotionRoot,
|
|
663
|
+
fileName: lazyComponentFile,
|
|
664
|
+
exportName: 'default',
|
|
665
|
+
visited: new Set(),
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
const componentName = getComponentIdentifier(compositionElement);
|
|
669
|
+
if (!componentName) {
|
|
670
|
+
throw new Error(`Could not find a component prop for composition "${compositionId}"`);
|
|
671
|
+
}
|
|
672
|
+
const importTarget = findImportTarget({ ast, componentName });
|
|
673
|
+
if (!importTarget) {
|
|
674
|
+
return getComponentLocationInFile({
|
|
675
|
+
remotionRoot,
|
|
676
|
+
fileName: compositionFileName,
|
|
677
|
+
exportName: componentName,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
const importedComponentFile = resolveImportPath({
|
|
681
|
+
importPath: importTarget.importPath,
|
|
682
|
+
fromFile: compositionFileName,
|
|
683
|
+
});
|
|
684
|
+
return getComponentLocationRecursively({
|
|
685
|
+
remotionRoot,
|
|
686
|
+
fileName: importedComponentFile,
|
|
687
|
+
exportName: importTarget.exportName,
|
|
688
|
+
visited: new Set(),
|
|
689
|
+
});
|
|
690
|
+
};
|
|
691
|
+
exports.resolveCompositionComponent = resolveCompositionComponent;
|
|
@@ -26,6 +26,7 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, logLevel, binariesDi
|
|
|
26
26
|
cancelToken: (0, renderer_1.makeCancelSignal)(),
|
|
27
27
|
concurrency: input.concurrency,
|
|
28
28
|
crf: input.crf,
|
|
29
|
+
gopSize: input.gopSize,
|
|
29
30
|
endFrame: input.endFrame,
|
|
30
31
|
startFrame: input.startFrame,
|
|
31
32
|
muted: input.muted,
|
|
@@ -43,7 +43,7 @@ const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
|
|
|
43
43
|
}
|
|
44
44
|
const valueExpr = prop.value;
|
|
45
45
|
if (!(0, can_update_sequence_props_1.isStaticValue)(valueExpr)) {
|
|
46
|
-
out[key] =
|
|
46
|
+
out[key] = (0, can_update_sequence_props_1.getComputedStatus)(valueExpr);
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
49
|
out[key] = {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { Expression, File, JSXOpeningElement } from '@babel/types';
|
|
2
2
|
import type { SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
|
|
3
|
-
import type { CanUpdateSequencePropsResponseTrue } from 'remotion';
|
|
4
|
-
import type { SequenceNodePath } from 'remotion';
|
|
5
|
-
import type { CanUpdateSequencePropStatus } from 'remotion';
|
|
3
|
+
import type { CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, SequenceNodePath } from 'remotion';
|
|
6
4
|
export declare const isStaticValue: (node: Expression) => boolean;
|
|
7
5
|
export declare const extractStaticValue: (node: Expression) => unknown;
|
|
6
|
+
export declare const getComputedStatus: (node: Expression) => CanUpdateSequencePropStatus;
|
|
8
7
|
export declare const findJsxElementAtNodePath: (ast: File, nodePath: SequenceNodePath) => JSXOpeningElement | null;
|
|
9
8
|
export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
|
|
10
9
|
export declare const computeSequencePropsOnlyStatus: ({ fileName, nodePath, keys, remotionRoot, }: {
|
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.computeSequencePropsStatusFromFilenameByLine = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsOnlyStatus = exports.lineColumnToNodePath = exports.findJsxElementAtNodePath = exports.extractStaticValue = exports.isStaticValue = void 0;
|
|
39
|
+
exports.computeSequencePropsStatusFromFilenameByLine = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsOnlyStatus = exports.lineColumnToNodePath = exports.findJsxElementAtNodePath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = void 0;
|
|
40
40
|
const node_fs_1 = require("node:fs");
|
|
41
41
|
const node_path_1 = __importDefault(require("node:path"));
|
|
42
42
|
const renderer_1 = require("@remotion/renderer");
|
|
@@ -117,6 +117,76 @@ const extractStaticValue = (node) => {
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
exports.extractStaticValue = extractStaticValue;
|
|
120
|
+
const getNumericValue = (node) => {
|
|
121
|
+
if (node.type === 'NumericLiteral') {
|
|
122
|
+
return node.value;
|
|
123
|
+
}
|
|
124
|
+
if (node.type === 'UnaryExpression' &&
|
|
125
|
+
(node.operator === '-' || node.operator === '+') &&
|
|
126
|
+
node.argument.type === 'NumericLiteral') {
|
|
127
|
+
return node.operator === '-' ? -node.argument.value : node.argument.value;
|
|
128
|
+
}
|
|
129
|
+
if (node.type === 'TSAsExpression') {
|
|
130
|
+
return getNumericValue(node.expression);
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
};
|
|
134
|
+
const getInterpolateKeyframes = (node) => {
|
|
135
|
+
if (node.type === 'TSAsExpression') {
|
|
136
|
+
return getInterpolateKeyframes(node.expression);
|
|
137
|
+
}
|
|
138
|
+
if (node.type !== 'CallExpression') {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const callExpression = node;
|
|
142
|
+
if (callExpression.callee.type !== 'Identifier' ||
|
|
143
|
+
callExpression.callee.name !== 'interpolate') {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
const inputArg = callExpression.arguments[1];
|
|
147
|
+
const outputArg = callExpression.arguments[2];
|
|
148
|
+
if (!inputArg ||
|
|
149
|
+
!outputArg ||
|
|
150
|
+
inputArg.type !== 'ArrayExpression' ||
|
|
151
|
+
outputArg.type !== 'ArrayExpression') {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
if (inputArg.elements.length !== outputArg.elements.length) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
const keyframes = [];
|
|
158
|
+
for (let i = 0; i < inputArg.elements.length; i++) {
|
|
159
|
+
const inputElement = inputArg.elements[i];
|
|
160
|
+
const outputElement = outputArg.elements[i];
|
|
161
|
+
if (!inputElement ||
|
|
162
|
+
!outputElement ||
|
|
163
|
+
inputElement.type === 'SpreadElement' ||
|
|
164
|
+
outputElement.type === 'SpreadElement') {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
const frame = getNumericValue(inputElement);
|
|
168
|
+
if (frame === null || !(0, exports.isStaticValue)(outputElement)) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
keyframes.push({
|
|
172
|
+
frame,
|
|
173
|
+
value: (0, exports.extractStaticValue)(outputElement),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return keyframes.length > 0 ? keyframes : undefined;
|
|
177
|
+
};
|
|
178
|
+
const getComputedStatus = (node) => {
|
|
179
|
+
const keyframes = getInterpolateKeyframes(node);
|
|
180
|
+
if (!keyframes) {
|
|
181
|
+
return { canUpdate: false, reason: 'computed' };
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
canUpdate: false,
|
|
185
|
+
reason: 'computed',
|
|
186
|
+
keyframes,
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
exports.getComputedStatus = getComputedStatus;
|
|
120
190
|
const getPropsStatus = (jsxElement) => {
|
|
121
191
|
const props = {};
|
|
122
192
|
for (const attr of jsxElement.attributes) {
|
|
@@ -144,11 +214,14 @@ const getPropsStatus = (jsxElement) => {
|
|
|
144
214
|
}
|
|
145
215
|
if (value.type === 'JSXExpressionContainer') {
|
|
146
216
|
const { expression } = value;
|
|
147
|
-
if (expression.type === 'JSXEmptyExpression'
|
|
148
|
-
!(0, exports.isStaticValue)(expression)) {
|
|
217
|
+
if (expression.type === 'JSXEmptyExpression') {
|
|
149
218
|
props[name] = { canUpdate: false, reason: 'computed' };
|
|
150
219
|
continue;
|
|
151
220
|
}
|
|
221
|
+
if (!(0, exports.isStaticValue)(expression)) {
|
|
222
|
+
props[name] = (0, exports.getComputedStatus)(expression);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
152
225
|
props[name] = {
|
|
153
226
|
canUpdate: true,
|
|
154
227
|
codeValue: (0, exports.extractStaticValue)(expression),
|
|
@@ -242,7 +315,7 @@ const getNestedPropStatus = (jsxElement, parentKey, childKey) => {
|
|
|
242
315
|
}
|
|
243
316
|
const propValue = prop.value;
|
|
244
317
|
if (!(0, exports.isStaticValue)(propValue)) {
|
|
245
|
-
return
|
|
318
|
+
return (0, exports.getComputedStatus)(propValue);
|
|
246
319
|
}
|
|
247
320
|
const codeValue = (0, exports.extractStaticValue)(propValue);
|
|
248
321
|
if (!validateStyleValue(childKey, codeValue)) {
|
|
@@ -27,7 +27,9 @@ const attrName = (str) => (0, exports.fg)(166, 226, 46, str);
|
|
|
27
27
|
exports.attrName = attrName;
|
|
28
28
|
const equals = (str) => (0, exports.fg)(249, 38, 114, str);
|
|
29
29
|
exports.equals = equals;
|
|
30
|
-
|
|
30
|
+
// Use the terminal's default foreground color so punctuation is visible in both
|
|
31
|
+
// light and dark terminal themes.
|
|
32
|
+
const punctuation = (str) => str;
|
|
31
33
|
exports.punctuation = punctuation;
|
|
32
34
|
const stringValue = (str) => (0, exports.fg)(230, 219, 116, str);
|
|
33
35
|
exports.stringValue = stringValue;
|
|
@@ -28,7 +28,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
|
|
|
28
28
|
}
|
|
29
29
|
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
30
30
|
const parsedDefault = defaultValue !== null ? JSON.parse(defaultValue) : null;
|
|
31
|
-
const { output, oldValueString, formatted, logLine, effectCallee } = await (0, update_effect_props_1.updateEffectProps)({
|
|
31
|
+
const { output, oldValueString, formatted, logLine, effectCallee, removedProps, } = await (0, update_effect_props_1.updateEffectProps)({
|
|
32
32
|
input: fileContents,
|
|
33
33
|
sequenceNodePath: sequenceNodePath.nodePath,
|
|
34
34
|
effectIndex,
|
|
@@ -37,11 +37,16 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
|
|
|
37
37
|
value: JSON.parse(value),
|
|
38
38
|
defaultValue: parsedDefault,
|
|
39
39
|
},
|
|
40
|
+
schema,
|
|
40
41
|
});
|
|
41
42
|
const defaultValueString = parsedDefault !== null ? JSON.stringify(parsedDefault) : null;
|
|
42
43
|
const normalizedOld = (0, log_update_1.normalizeQuotes)(oldValueString);
|
|
43
44
|
const normalizedNew = (0, log_update_1.normalizeQuotes)(value);
|
|
44
45
|
const normalizedDefault = defaultValueString !== null ? (0, log_update_1.normalizeQuotes)(defaultValueString) : null;
|
|
46
|
+
const normalizedRemovedProps = removedProps.map((prop) => ({
|
|
47
|
+
...prop,
|
|
48
|
+
valueString: (0, log_update_1.normalizeQuotes)(prop.valueString),
|
|
49
|
+
}));
|
|
45
50
|
const undoPropChange = (0, format_effect_prop_change_1.formatEffectPropChange)({
|
|
46
51
|
effectName: effectCallee,
|
|
47
52
|
key,
|
|
@@ -49,7 +54,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
|
|
|
49
54
|
newValueString: normalizedOld,
|
|
50
55
|
defaultValueString: normalizedDefault,
|
|
51
56
|
removedProps: [],
|
|
52
|
-
addedProps:
|
|
57
|
+
addedProps: normalizedRemovedProps,
|
|
53
58
|
});
|
|
54
59
|
const redoPropChange = (0, format_effect_prop_change_1.formatEffectPropChange)({
|
|
55
60
|
effectName: effectCallee,
|
|
@@ -57,7 +62,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
|
|
|
57
62
|
oldValueString: normalizedOld,
|
|
58
63
|
newValueString: normalizedNew,
|
|
59
64
|
defaultValueString: normalizedDefault,
|
|
60
|
-
removedProps:
|
|
65
|
+
removedProps: normalizedRemovedProps,
|
|
61
66
|
addedProps: [],
|
|
62
67
|
});
|
|
63
68
|
(0, undo_stack_1.pushToUndoStack)({
|
|
@@ -86,7 +91,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
|
|
|
86
91
|
defaultValueString,
|
|
87
92
|
formatted,
|
|
88
93
|
logLevel,
|
|
89
|
-
removedProps
|
|
94
|
+
removedProps,
|
|
90
95
|
addedProps: [],
|
|
91
96
|
});
|
|
92
97
|
(0, undo_stack_1.printUndoHint)(logLevel);
|
package/dist/routes.js
CHANGED
|
@@ -45,6 +45,7 @@ const client_render_queue_1 = require("./client-render-queue");
|
|
|
45
45
|
const get_file_source_1 = require("./helpers/get-file-source");
|
|
46
46
|
const get_installed_installable_packages_1 = require("./helpers/get-installed-installable-packages");
|
|
47
47
|
const open_in_editor_1 = require("./helpers/open-in-editor");
|
|
48
|
+
const resolve_composition_component_1 = require("./helpers/resolve-composition-component");
|
|
48
49
|
const resolve_output_path_1 = require("./helpers/resolve-output-path");
|
|
49
50
|
const api_routes_1 = require("./preview-server/api-routes");
|
|
50
51
|
const get_package_manager_1 = require("./preview-server/get-package-manager");
|
|
@@ -201,6 +202,41 @@ const handleOpenInEditor = async (remotionRoot, req, res, logLevel) => {
|
|
|
201
202
|
}));
|
|
202
203
|
}
|
|
203
204
|
};
|
|
205
|
+
const handleGetCompositionComponentInfo = async (remotionRoot, req, res) => {
|
|
206
|
+
if (req.method === 'OPTIONS') {
|
|
207
|
+
res.statusCode = 200;
|
|
208
|
+
res.end();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
res.setHeader('content-type', 'application/json');
|
|
212
|
+
try {
|
|
213
|
+
const body = (await (0, parse_body_1.parseRequestBody)(req));
|
|
214
|
+
if (typeof body.compositionFile !== 'string') {
|
|
215
|
+
throw new TypeError('Need to pass compositionFile');
|
|
216
|
+
}
|
|
217
|
+
if (typeof body.compositionId !== 'string') {
|
|
218
|
+
throw new TypeError('Need to pass compositionId');
|
|
219
|
+
}
|
|
220
|
+
const location = await (0, resolve_composition_component_1.resolveCompositionComponent)({
|
|
221
|
+
remotionRoot,
|
|
222
|
+
compositionFile: body.compositionFile,
|
|
223
|
+
compositionId: body.compositionId,
|
|
224
|
+
});
|
|
225
|
+
res.writeHead(200);
|
|
226
|
+
res.end(JSON.stringify({
|
|
227
|
+
success: true,
|
|
228
|
+
location,
|
|
229
|
+
canAddSequence: location.canAddSequence,
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
res.writeHead(200);
|
|
234
|
+
res.end(JSON.stringify({
|
|
235
|
+
success: false,
|
|
236
|
+
error: err.message,
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
};
|
|
204
240
|
const validateSameOrigin = (req) => {
|
|
205
241
|
const { origin, host } = req.headers;
|
|
206
242
|
if (origin) {
|
|
@@ -330,6 +366,9 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
|
|
|
330
366
|
if (url.pathname === '/api/open-in-editor') {
|
|
331
367
|
return handleOpenInEditor(remotionRoot, request, response, logLevel);
|
|
332
368
|
}
|
|
369
|
+
if (url.pathname === '/api/composition-component-info') {
|
|
370
|
+
return handleGetCompositionComponentInfo(remotionRoot, request, response);
|
|
371
|
+
}
|
|
333
372
|
if (url.pathname === `${staticHash}/api/add-asset`) {
|
|
334
373
|
return handleAddAsset({
|
|
335
374
|
req: request,
|
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.467",
|
|
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.467",
|
|
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.467",
|
|
33
|
+
"@remotion/renderer": "4.0.467",
|
|
34
|
+
"@remotion/studio-shared": "4.0.467",
|
|
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.467",
|
|
43
43
|
"eslint": "9.19.0",
|
|
44
44
|
"@types/node": "20.12.14",
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|