@remotion/studio-server 4.0.511 → 4.0.513
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/format-inline-content.d.ts +2 -1
- package/dist/codemods/format-inline-content.js +18 -9
- package/dist/codemods/parse-ast.d.ts +1 -0
- package/dist/codemods/parse-ast.js +5 -1
- package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +4 -1
- package/dist/codemods/update-sequence-props/update-sequence-props.js +47 -3
- package/dist/helpers/resolve-composition-component.js +6 -6
- package/dist/preview-server/routes/can-update-effect-props.js +3 -0
- package/dist/preview-server/routes/can-update-sequence-props.d.ts +26 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +346 -53
- package/dist/preview-server/routes/default-editor.js +4 -1
- package/dist/preview-server/routes/save-sequence-props.js +27 -4
- package/dist/preview-server/routes/subscribe-to-sequence-props.d.ts +2 -2
- package/dist/preview-server/routes/subscribe-to-sequence-props.js +37 -3
- package/dist/preview-server/sequence-props-watchers.d.ts +2 -1
- package/dist/preview-server/sequence-props-watchers.js +33 -2
- package/package.json +8 -8
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* so prettier makes the same line-breaking decisions as if the content
|
|
12
12
|
* were at its actual column position in the file.
|
|
13
13
|
*/
|
|
14
|
-
export declare const formatInlineContent: ({ inlineContent, linePrefix, endOfLine, }: {
|
|
14
|
+
export declare const formatInlineContent: ({ inlineContent, linePrefix, endOfLine, prettierConfigOverride, }: {
|
|
15
15
|
inlineContent: string;
|
|
16
16
|
linePrefix: string;
|
|
17
17
|
endOfLine: "auto" | "lf";
|
|
18
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
18
19
|
}) => Promise<{
|
|
19
20
|
formatted: string;
|
|
20
21
|
didFormat: boolean;
|
|
@@ -47,7 +47,7 @@ exports.formatInlineContent = void 0;
|
|
|
47
47
|
* so prettier makes the same line-breaking decisions as if the content
|
|
48
48
|
* were at its actual column position in the file.
|
|
49
49
|
*/
|
|
50
|
-
const formatInlineContent = async ({ inlineContent, linePrefix, endOfLine, }) => {
|
|
50
|
+
const formatInlineContent = async ({ inlineContent, linePrefix, endOfLine, prettierConfigOverride, }) => {
|
|
51
51
|
var _a;
|
|
52
52
|
var _b, _c, _d;
|
|
53
53
|
let prettier = null;
|
|
@@ -58,13 +58,19 @@ const formatInlineContent = async ({ inlineContent, linePrefix, endOfLine, }) =>
|
|
|
58
58
|
return { formatted: inlineContent, didFormat: false };
|
|
59
59
|
}
|
|
60
60
|
const { format, resolveConfig, resolveConfigFile } = prettier;
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
61
|
+
let prettierConfig;
|
|
62
|
+
if (prettierConfigOverride !== undefined && prettierConfigOverride !== null) {
|
|
63
|
+
prettierConfig = prettierConfigOverride;
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
else {
|
|
66
|
+
const configFilePath = await resolveConfigFile();
|
|
67
|
+
if (!configFilePath) {
|
|
68
|
+
return { formatted: inlineContent, didFormat: false };
|
|
69
|
+
}
|
|
70
|
+
prettierConfig = await resolveConfig(configFilePath);
|
|
71
|
+
if (!prettierConfig) {
|
|
72
|
+
return { formatted: inlineContent, didFormat: false };
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
const tabWidth = (_b = prettierConfig.tabWidth) !== null && _b !== void 0 ? _b : 2;
|
|
70
76
|
const baseIndent = (_c = (_a = linePrefix.match(/^(\s*)/)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _c !== void 0 ? _c : '';
|
|
@@ -85,13 +91,16 @@ const formatInlineContent = async ({ inlineContent, linePrefix, endOfLine, }) =>
|
|
|
85
91
|
});
|
|
86
92
|
// Extract the formatted value from the wrapper
|
|
87
93
|
const withoutSemicolon = formattedWrapped.replace(/;\s*$/, '');
|
|
94
|
+
const wrappedInParentheses = withoutSemicolon.startsWith(`${wrapperPrefix}(\n`);
|
|
88
95
|
let formattedProps;
|
|
89
|
-
if (withoutSemicolon.startsWith(wrapperPrefix)) {
|
|
96
|
+
if (withoutSemicolon.startsWith(wrapperPrefix) && !wrappedInParentheses) {
|
|
90
97
|
formattedProps = withoutSemicolon.slice(wrapperPrefix.length);
|
|
91
98
|
}
|
|
92
99
|
else {
|
|
93
100
|
// Prettier broke the line after `=` — extract and dedent one level
|
|
94
|
-
const lines = withoutSemicolon
|
|
101
|
+
const lines = withoutSemicolon
|
|
102
|
+
.split('\n')
|
|
103
|
+
.slice(1, wrappedInParentheses ? -1 : undefined);
|
|
95
104
|
const useTabs = prettierConfig.useTabs;
|
|
96
105
|
const oneIndent = useTabs ? '\t' : ' '.repeat(tabWidth);
|
|
97
106
|
formattedProps = lines
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.serializeAst = exports.parseAst = void 0;
|
|
36
|
+
exports.serializeAst = exports.parseAstForReadOnly = exports.parseAst = void 0;
|
|
37
37
|
const recast = __importStar(require("recast"));
|
|
38
38
|
const tsParser = __importStar(require("recast/parsers/babel-ts"));
|
|
39
39
|
const imports_1 = require("../helpers/imports");
|
|
@@ -43,6 +43,10 @@ const parseAst = (input) => {
|
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
45
|
exports.parseAst = parseAst;
|
|
46
|
+
const parseAstForReadOnly = (input) => {
|
|
47
|
+
return tsParser.parse(input);
|
|
48
|
+
};
|
|
49
|
+
exports.parseAstForReadOnly = parseAstForReadOnly;
|
|
46
50
|
const serializeAst = (ast) => {
|
|
47
51
|
const raw = recast.print(ast, {
|
|
48
52
|
parser: tsParser,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { File } from '@babel/types';
|
|
1
2
|
import { type RemovedProp, type SequencePropsNodeUpdate, type SequencePropsNodeUpdateResult, type SequencePropUpdate, updateSequencePropsAst } from '@remotion/studio-codemods';
|
|
2
3
|
import type { InteractivitySchema, SequenceNodePath, VideoConfigValues } from 'remotion';
|
|
3
4
|
export { type RemovedProp, type SequencePropsNodeUpdate, type SequencePropsNodeUpdateResult, type SequencePropUpdate, updateSequencePropsAst, };
|
|
@@ -6,6 +7,7 @@ type UpdateMultipleSequencePropsResult = {
|
|
|
6
7
|
output: string;
|
|
7
8
|
formatted: boolean;
|
|
8
9
|
results: SequencePropsNodeUpdateResult[];
|
|
10
|
+
ast: File;
|
|
9
11
|
};
|
|
10
12
|
type UpdateSequencePropsResult = {
|
|
11
13
|
output: string;
|
|
@@ -14,10 +16,11 @@ type UpdateSequencePropsResult = {
|
|
|
14
16
|
logLine: number;
|
|
15
17
|
removedProps: RemovedProp[];
|
|
16
18
|
};
|
|
17
|
-
export declare const updateMultipleSequenceProps: ({ input, changes, prettierConfigOverride, }: {
|
|
19
|
+
export declare const updateMultipleSequenceProps: ({ input, changes, prettierConfigOverride, ast: providedAst, }: {
|
|
18
20
|
input: string;
|
|
19
21
|
changes: SequencePropsNodeUpdate[];
|
|
20
22
|
prettierConfigOverride: PrettierConfigOverride;
|
|
23
|
+
ast?: File | undefined;
|
|
21
24
|
}) => Promise<UpdateMultipleSequencePropsResult>;
|
|
22
25
|
export declare const updateSequenceProps: ({ input, nodePath, updates, schema, prettierConfigOverride, videoConfigValues, }: {
|
|
23
26
|
input: string;
|
|
@@ -4,13 +4,57 @@ exports.updateSequenceProps = exports.updateMultipleSequenceProps = exports.upda
|
|
|
4
4
|
const studio_codemods_1 = require("@remotion/studio-codemods");
|
|
5
5
|
Object.defineProperty(exports, "updateSequencePropsAst", { enumerable: true, get: function () { return studio_codemods_1.updateSequencePropsAst; } });
|
|
6
6
|
const format_file_content_1 = require("../format-file-content");
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const format_inline_content_1 = require("../format-inline-content");
|
|
8
|
+
const updateMultipleSequenceProps = async ({ input, changes, prettierConfigOverride, ast: providedAst, }) => {
|
|
9
|
+
const { output: unformattedOutput, results, ast, openingElementRanges, } = (0, studio_codemods_1.updateMultipleSequenceProps)({
|
|
10
|
+
input,
|
|
11
|
+
changes,
|
|
12
|
+
ast: providedAst,
|
|
13
|
+
});
|
|
14
|
+
if (unformattedOutput === input) {
|
|
15
|
+
return { output: input, formatted: true, results, ast };
|
|
16
|
+
}
|
|
17
|
+
if ((openingElementRanges === null || openingElementRanges === void 0 ? void 0 : openingElementRanges.length) === 1) {
|
|
18
|
+
const [range] = openingElementRanges;
|
|
19
|
+
const openingElement = unformattedOutput.slice(range.start, range.end);
|
|
20
|
+
const formattableOpeningElement = range.selfClosing
|
|
21
|
+
? openingElement
|
|
22
|
+
: openingElement.slice(0, -1) + ' />';
|
|
23
|
+
const lineStart = unformattedOutput.lastIndexOf('\n', range.start) + 1;
|
|
24
|
+
const linePrefix = unformattedOutput.slice(lineStart, range.start);
|
|
25
|
+
const { formatted: formattedOpeningElement, didFormat } = await (0, format_inline_content_1.formatInlineContent)({
|
|
26
|
+
inlineContent: formattableOpeningElement,
|
|
27
|
+
linePrefix,
|
|
28
|
+
endOfLine: 'lf',
|
|
29
|
+
prettierConfigOverride,
|
|
30
|
+
});
|
|
31
|
+
let finalOpeningElement = formattedOpeningElement;
|
|
32
|
+
if (!range.selfClosing) {
|
|
33
|
+
const slashIndex = finalOpeningElement.lastIndexOf('/>');
|
|
34
|
+
if (slashIndex !== finalOpeningElement.length - 2) {
|
|
35
|
+
throw new Error('Could not format JSX opening element');
|
|
36
|
+
}
|
|
37
|
+
const lastLineStart = finalOpeningElement.lastIndexOf('\n') + 1;
|
|
38
|
+
const beforeSlash = finalOpeningElement.slice(lastLineStart, slashIndex);
|
|
39
|
+
finalOpeningElement =
|
|
40
|
+
beforeSlash.trim().length === 0
|
|
41
|
+
? finalOpeningElement.slice(0, slashIndex) + '>'
|
|
42
|
+
: finalOpeningElement.slice(0, slashIndex).trimEnd() + '>';
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
output: unformattedOutput.slice(0, range.start) +
|
|
46
|
+
finalOpeningElement +
|
|
47
|
+
unformattedOutput.slice(range.end),
|
|
48
|
+
formatted: didFormat,
|
|
49
|
+
results,
|
|
50
|
+
ast,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
9
53
|
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
10
54
|
input: unformattedOutput,
|
|
11
55
|
prettierConfigOverride,
|
|
12
56
|
});
|
|
13
|
-
return { output, formatted, results };
|
|
57
|
+
return { output, formatted, results, ast };
|
|
14
58
|
};
|
|
15
59
|
exports.updateMultipleSequenceProps = updateMultipleSequenceProps;
|
|
16
60
|
const updateSequenceProps = async ({ input, nodePath, updates, schema, prettierConfigOverride, videoConfigValues, }) => {
|
|
@@ -1202,16 +1202,14 @@ const canAddSequenceToComponent = ({ ast, exportName, }) => {
|
|
|
1202
1202
|
return false;
|
|
1203
1203
|
}
|
|
1204
1204
|
};
|
|
1205
|
-
const getComponentLocationInFile = async ({ remotionRoot, fileName, exportName, }) => {
|
|
1205
|
+
const getComponentLocationInFile = async ({ remotionRoot, fileName, exportName, ast: providedAst, }) => {
|
|
1206
1206
|
var _a, _b;
|
|
1207
|
-
const
|
|
1208
|
-
const ast = (0, parse_ast_1.parseAst)(input);
|
|
1209
|
-
const astForSequenceSimulation = (0, parse_ast_1.parseAst)(input);
|
|
1207
|
+
const ast = providedAst !== null && providedAst !== void 0 ? providedAst : (0, parse_ast_1.parseAst)(await readSourceFile({ remotionRoot, fileName }));
|
|
1210
1208
|
const location = exportName === 'default'
|
|
1211
1209
|
? findDefaultExportLocation(ast)
|
|
1212
1210
|
: findLocalSymbolLocation({ ast, name: exportName });
|
|
1213
1211
|
const canAddSequence = canAddSequenceToComponent({
|
|
1214
|
-
ast
|
|
1212
|
+
ast,
|
|
1215
1213
|
exportName,
|
|
1216
1214
|
});
|
|
1217
1215
|
return {
|
|
@@ -1241,6 +1239,7 @@ const getComponentLocationRecursively = async ({ remotionRoot, fileName, exportN
|
|
|
1241
1239
|
remotionRoot,
|
|
1242
1240
|
fileName,
|
|
1243
1241
|
exportName,
|
|
1242
|
+
ast,
|
|
1244
1243
|
});
|
|
1245
1244
|
}
|
|
1246
1245
|
const reExportTargets = findReExportTargets({
|
|
@@ -1271,6 +1270,7 @@ const getComponentLocationRecursively = async ({ remotionRoot, fileName, exportN
|
|
|
1271
1270
|
remotionRoot,
|
|
1272
1271
|
fileName,
|
|
1273
1272
|
exportName,
|
|
1273
|
+
ast,
|
|
1274
1274
|
});
|
|
1275
1275
|
}
|
|
1276
1276
|
finally {
|
|
@@ -1283,7 +1283,7 @@ const resolveCompositionComponentWithFile = async ({ remotionRoot, compositionFi
|
|
|
1283
1283
|
remotionRoot,
|
|
1284
1284
|
fileName: compositionFileName,
|
|
1285
1285
|
});
|
|
1286
|
-
const ast = (0, parse_ast_1.
|
|
1286
|
+
const ast = (0, parse_ast_1.parseAstForReadOnly)(input);
|
|
1287
1287
|
const compositionElement = findCompositionElement({ ast, compositionId });
|
|
1288
1288
|
if (!compositionElement) {
|
|
1289
1289
|
throw new Error(`Could not find composition "${compositionId}"`);
|
|
@@ -10,6 +10,7 @@ const video_config_values_1 = require("../../helpers/video-config-values");
|
|
|
10
10
|
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
11
11
|
const staticStatus = (codeValue) => ({
|
|
12
12
|
status: 'static',
|
|
13
|
+
keyframeDisplayOffsetAdjustment: null,
|
|
13
14
|
codeValue,
|
|
14
15
|
});
|
|
15
16
|
const findEffectsAttr = (jsx) => {
|
|
@@ -110,6 +111,7 @@ const getPropsFromObjectExpression = ({ ast, objExpr, keys, videoConfigValues, }
|
|
|
110
111
|
out[key] = numericExpression
|
|
111
112
|
? {
|
|
112
113
|
status: 'static',
|
|
114
|
+
keyframeDisplayOffsetAdjustment: null,
|
|
113
115
|
codeValue: numericExpression.value,
|
|
114
116
|
...(numericExpression.type === 'literal'
|
|
115
117
|
? {}
|
|
@@ -120,6 +122,7 @@ const getPropsFromObjectExpression = ({ ast, objExpr, keys, videoConfigValues, }
|
|
|
120
122
|
}
|
|
121
123
|
out[key] = {
|
|
122
124
|
status: 'static',
|
|
125
|
+
keyframeDisplayOffsetAdjustment: null,
|
|
123
126
|
codeValue: (0, can_update_sequence_props_1.extractStaticValue)(valueExpr),
|
|
124
127
|
};
|
|
125
128
|
}
|
|
@@ -2,6 +2,7 @@ import type { Expression, File, JSXElement, JSXOpeningElement } from '@babel/typ
|
|
|
2
2
|
import type { SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
|
|
3
3
|
import type { CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, SequenceNodePath, VideoConfigValues } from 'remotion';
|
|
4
4
|
import { type VideoConfigIdentifierValues } from '../../helpers/video-config-values';
|
|
5
|
+
export declare const takeCachedSequencePropsStatusAst: (fileContents: string) => File | null;
|
|
5
6
|
type StaticValueOptions = {
|
|
6
7
|
allowSpecialValues: boolean;
|
|
7
8
|
};
|
|
@@ -24,6 +25,31 @@ export declare const hasJsxChildrenAttribute: (jsxElement: JSXOpeningElement) =>
|
|
|
24
25
|
export declare const getStaticJsxTextContent: (jsxElement: JSXElement) => StaticJsxTextContent | null;
|
|
25
26
|
export declare const findNodePathForJsxElement: (ast: File, target: JSXOpeningElement) => SequenceNodePath | null;
|
|
26
27
|
export declare const lineColumnToNodePath: (ast: File, targetLine: number, targetColumn?: number | undefined, fileContents?: string | undefined) => SequenceNodePath | null;
|
|
28
|
+
export declare const lineColumnsToNodePaths: ({ ast, targets, fileContents, }: {
|
|
29
|
+
ast: File;
|
|
30
|
+
targets: {
|
|
31
|
+
line: number;
|
|
32
|
+
column: number;
|
|
33
|
+
}[];
|
|
34
|
+
fileContents: string;
|
|
35
|
+
}) => (SequenceNodePath | null)[];
|
|
36
|
+
export declare const resolveSequencePropsNodePathsFromFilename: ({ fileName, targets, remotionRoot, }: {
|
|
37
|
+
fileName: string;
|
|
38
|
+
targets: {
|
|
39
|
+
line: number;
|
|
40
|
+
column: number;
|
|
41
|
+
}[];
|
|
42
|
+
remotionRoot: string;
|
|
43
|
+
}) => (SequenceNodePath | null)[];
|
|
44
|
+
export declare const computeSequencePropsStatusFromAst: ({ ast, nodePath, componentIdentity, keys, assetKeys, effects, videoConfigValues, }: {
|
|
45
|
+
ast: File;
|
|
46
|
+
nodePath: SequenceNodePath;
|
|
47
|
+
componentIdentity: string | null;
|
|
48
|
+
keys: string[];
|
|
49
|
+
assetKeys?: string[] | undefined;
|
|
50
|
+
effects: string[][];
|
|
51
|
+
videoConfigValues: VideoConfigValues | null;
|
|
52
|
+
}) => CanUpdateSequencePropsResponseTrue;
|
|
27
53
|
export declare const computeSequencePropsStatusFromContent: ({ fileContents, nodePath, componentIdentity, keys, assetKeys, effects, videoConfigValues, }: {
|
|
28
54
|
fileContents: string;
|
|
29
55
|
nodePath: SequenceNodePath;
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.computeSequencePropsStatusFromFilenameByLocation = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.lineColumnToNodePath = exports.findNodePathForJsxElement = exports.getStaticJsxTextContent = exports.hasJsxChildrenAttribute = exports.getStaticJsxChildrenAttribute = exports.findJsxElementNodeAtNodePath = exports.findJsxElementAtNodePath = exports.findJsxElementPathAtNodePath = exports.getNodePathForRecastPath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = void 0;
|
|
36
|
+
exports.computeSequencePropsStatusFromFilenameByLocation = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsStatusFromAst = exports.resolveSequencePropsNodePathsFromFilename = exports.lineColumnsToNodePaths = exports.lineColumnToNodePath = exports.findNodePathForJsxElement = exports.getStaticJsxTextContent = exports.hasJsxChildrenAttribute = exports.getStaticJsxChildrenAttribute = exports.findJsxElementNodeAtNodePath = exports.findJsxElementAtNodePath = exports.findJsxElementPathAtNodePath = exports.getNodePathForRecastPath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = exports.takeCachedSequencePropsStatusAst = void 0;
|
|
37
37
|
const node_fs_1 = require("node:fs");
|
|
38
38
|
const renderer_1 = require("@remotion/renderer");
|
|
39
39
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
@@ -55,8 +55,41 @@ const can_update_effect_props_1 = require("./can-update-effect-props");
|
|
|
55
55
|
// computation is read-only, so all subscribers can share one parsed snapshot
|
|
56
56
|
// until the notification burst has finished.
|
|
57
57
|
let cachedSequencePropsStatusAst = null;
|
|
58
|
+
// A subsequent save can consume the last read-only snapshot if the file has
|
|
59
|
+
// not changed. The save mutates the AST, so it must only be reused once.
|
|
60
|
+
let reusableSequencePropsStatusAst = null;
|
|
61
|
+
const getCachedSequencePropsStatusAst = (fileContents) => {
|
|
62
|
+
if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.fileContents) !== fileContents) {
|
|
63
|
+
const snapshot = {
|
|
64
|
+
fileContents,
|
|
65
|
+
ast: (0, parse_ast_1.parseAst)(fileContents),
|
|
66
|
+
videoConfigIdentifierValues: new Map(),
|
|
67
|
+
};
|
|
68
|
+
cachedSequencePropsStatusAst = snapshot;
|
|
69
|
+
reusableSequencePropsStatusAst = snapshot;
|
|
70
|
+
queueMicrotask(() => {
|
|
71
|
+
if (cachedSequencePropsStatusAst === snapshot) {
|
|
72
|
+
cachedSequencePropsStatusAst = null;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return cachedSequencePropsStatusAst;
|
|
77
|
+
};
|
|
78
|
+
const takeCachedSequencePropsStatusAst = (fileContents) => {
|
|
79
|
+
if ((reusableSequencePropsStatusAst === null || reusableSequencePropsStatusAst === void 0 ? void 0 : reusableSequencePropsStatusAst.fileContents) !== fileContents) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const { ast } = reusableSequencePropsStatusAst;
|
|
83
|
+
reusableSequencePropsStatusAst = null;
|
|
84
|
+
if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.ast) === ast) {
|
|
85
|
+
cachedSequencePropsStatusAst = null;
|
|
86
|
+
}
|
|
87
|
+
return ast;
|
|
88
|
+
};
|
|
89
|
+
exports.takeCachedSequencePropsStatusAst = takeCachedSequencePropsStatusAst;
|
|
58
90
|
const staticStatus = (codeValue, numericExpression) => ({
|
|
59
91
|
status: 'static',
|
|
92
|
+
keyframeDisplayOffsetAdjustment: null,
|
|
60
93
|
codeValue,
|
|
61
94
|
...(numericExpression === null || numericExpression.type === 'literal'
|
|
62
95
|
? {}
|
|
@@ -389,13 +422,20 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
|
|
|
389
422
|
const outputArg = callExpression.arguments[2];
|
|
390
423
|
if (!frameArg ||
|
|
391
424
|
frameArg.type === 'SpreadElement' ||
|
|
392
|
-
!isCurrentFrameIdentifier(frameArg, ast) ||
|
|
393
425
|
!inputArg ||
|
|
394
426
|
!outputArg ||
|
|
395
427
|
inputArg.type !== 'ArrayExpression' ||
|
|
396
428
|
outputArg.type !== 'ArrayExpression') {
|
|
397
429
|
return undefined;
|
|
398
430
|
}
|
|
431
|
+
const frameDisplayOffset = getCurrentFrameDisplayOffsetAdjustment({
|
|
432
|
+
node: frameArg,
|
|
433
|
+
ast,
|
|
434
|
+
videoConfigValues,
|
|
435
|
+
});
|
|
436
|
+
if (frameDisplayOffset === null) {
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
399
439
|
if (inputArg.elements.length !== outputArg.elements.length) {
|
|
400
440
|
return undefined;
|
|
401
441
|
}
|
|
@@ -436,39 +476,200 @@ const getInterpolationKeyframes = (node, ast, videoConfigValues) => {
|
|
|
436
476
|
clamping: metadata.clamping,
|
|
437
477
|
posterize: metadata.posterize,
|
|
438
478
|
output: metadata.output,
|
|
479
|
+
keyframeDisplayOffsetAdjustment: frameDisplayOffset.hasEnclosingElement
|
|
480
|
+
? frameDisplayOffset.adjustment
|
|
481
|
+
: null,
|
|
439
482
|
};
|
|
440
483
|
};
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
484
|
+
const getRemotionImportNames = ({ ast, importedName, }) => {
|
|
485
|
+
var _a;
|
|
486
|
+
var _b, _c;
|
|
487
|
+
const direct = new Set();
|
|
488
|
+
const namespaces = new Set();
|
|
489
|
+
for (const statement of ast.program.body) {
|
|
490
|
+
if (statement.type !== 'ImportDeclaration' ||
|
|
491
|
+
statement.source.value !== 'remotion') {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
for (const specifier of (_b = statement.specifiers) !== null && _b !== void 0 ? _b : []) {
|
|
495
|
+
if (specifier.type === 'ImportSpecifier' &&
|
|
496
|
+
((specifier.imported.type === 'Identifier' &&
|
|
497
|
+
specifier.imported.name === importedName) ||
|
|
498
|
+
(specifier.imported.type === 'StringLiteral' &&
|
|
499
|
+
specifier.imported.value === importedName))) {
|
|
500
|
+
direct.add((_c = (_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _c !== void 0 ? _c : importedName);
|
|
501
|
+
}
|
|
502
|
+
if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
503
|
+
namespaces.add(specifier.local.name);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return { direct, namespaces };
|
|
508
|
+
};
|
|
509
|
+
const isUseCurrentFrameCall = (node, ast) => {
|
|
510
|
+
if (node.type !== 'CallExpression' || node.arguments.length !== 0) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
const imports = getRemotionImportNames({
|
|
514
|
+
ast,
|
|
515
|
+
importedName: 'useCurrentFrame',
|
|
516
|
+
});
|
|
517
|
+
if (node.callee.type === 'Identifier') {
|
|
518
|
+
return imports.direct.has(node.callee.name);
|
|
519
|
+
}
|
|
520
|
+
return (node.callee.type === 'MemberExpression' &&
|
|
521
|
+
!node.callee.computed &&
|
|
522
|
+
node.callee.object.type === 'Identifier' &&
|
|
523
|
+
node.callee.property.type === 'Identifier' &&
|
|
524
|
+
imports.namespaces.has(node.callee.object.name) &&
|
|
525
|
+
node.callee.property.name === 'useCurrentFrame');
|
|
526
|
+
};
|
|
527
|
+
const findNodePath = (ast, target) => {
|
|
528
|
+
let found = null;
|
|
529
|
+
recast.types.visit(ast, {
|
|
530
|
+
visitNode(p) {
|
|
531
|
+
if (p.node === target) {
|
|
532
|
+
found = p;
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
return this.traverse(p);
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
return found;
|
|
539
|
+
};
|
|
540
|
+
const getJsxNumericAttribute = ({ openingElement, name, defaultValue, videoConfigValues, }) => {
|
|
541
|
+
var _a, _b;
|
|
542
|
+
var _c;
|
|
543
|
+
if (openingElement.attributes.some((attribute) => attribute.type === 'JSXSpreadAttribute')) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
for (let index = openingElement.attributes.length - 1; index >= 0; index--) {
|
|
547
|
+
const attribute = openingElement.attributes[index];
|
|
548
|
+
if (attribute.type !== 'JSXAttribute' ||
|
|
549
|
+
attribute.name.type !== 'JSXIdentifier' ||
|
|
550
|
+
attribute.name.name !== name) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if (((_a = attribute.value) === null || _a === void 0 ? void 0 : _a.type) !== 'JSXExpressionContainer' ||
|
|
554
|
+
attribute.value.expression.type === 'JSXEmptyExpression') {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
return ((_c = (_b = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
|
|
558
|
+
node: attribute.value.expression,
|
|
559
|
+
videoConfigValues,
|
|
560
|
+
})) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : null);
|
|
561
|
+
}
|
|
562
|
+
return defaultValue;
|
|
563
|
+
};
|
|
564
|
+
const getFrameDisplayOffsetAdjustmentBetweenPaths = ({ startPath, endPath, videoConfigValues, }) => {
|
|
565
|
+
let current = startPath;
|
|
566
|
+
let hasSeenControlledElement = false;
|
|
567
|
+
let hasEnclosingElement = false;
|
|
568
|
+
let adjustment = 0;
|
|
569
|
+
while (current && current.value !== endPath.value) {
|
|
570
|
+
const currentNode = current.value;
|
|
571
|
+
if (currentNode.type === 'FunctionDeclaration' ||
|
|
572
|
+
currentNode.type === 'FunctionExpression' ||
|
|
573
|
+
currentNode.type === 'ArrowFunctionExpression') {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
if (currentNode.type === 'JSXElement') {
|
|
577
|
+
if (!hasSeenControlledElement) {
|
|
578
|
+
hasSeenControlledElement = true;
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
hasEnclosingElement = true;
|
|
582
|
+
// Sequence-backed built-ins and userland components can both shift
|
|
583
|
+
// their children, so the prop names are the semantic boundary.
|
|
584
|
+
const from = getJsxNumericAttribute({
|
|
585
|
+
openingElement: currentNode.openingElement,
|
|
586
|
+
name: 'from',
|
|
587
|
+
defaultValue: 0,
|
|
588
|
+
videoConfigValues,
|
|
589
|
+
});
|
|
590
|
+
const trimBefore = getJsxNumericAttribute({
|
|
591
|
+
openingElement: currentNode.openingElement,
|
|
592
|
+
name: 'trimBefore',
|
|
593
|
+
defaultValue: 0,
|
|
594
|
+
videoConfigValues,
|
|
595
|
+
});
|
|
596
|
+
if (from === null || trimBefore === null) {
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
adjustment -= from - trimBefore;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
current = current.parentPath;
|
|
603
|
+
}
|
|
604
|
+
return current ? { adjustment, hasEnclosingElement } : null;
|
|
605
|
+
};
|
|
606
|
+
const getDefaultFrameDisplayOffsetAdjustment = ({ jsxElement, ast, videoConfigValues, }) => {
|
|
607
|
+
var _a;
|
|
608
|
+
const jsxPath = findNodePath(ast, jsxElement);
|
|
609
|
+
if (!jsxPath) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
let functionPath = jsxPath.parentPath;
|
|
613
|
+
while (functionPath) {
|
|
614
|
+
const node = functionPath.value;
|
|
615
|
+
if (node.type === 'FunctionDeclaration' ||
|
|
616
|
+
node.type === 'FunctionExpression' ||
|
|
617
|
+
node.type === 'ArrowFunctionExpression') {
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
functionPath = functionPath.parentPath;
|
|
621
|
+
}
|
|
622
|
+
if (!functionPath) {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
const result = getFrameDisplayOffsetAdjustmentBetweenPaths({
|
|
626
|
+
startPath: jsxPath,
|
|
627
|
+
endPath: functionPath,
|
|
628
|
+
videoConfigValues,
|
|
629
|
+
});
|
|
630
|
+
return (_a = result === null || result === void 0 ? void 0 : result.adjustment) !== null && _a !== void 0 ? _a : null;
|
|
446
631
|
};
|
|
447
|
-
const
|
|
632
|
+
const getCurrentFrameDisplayOffsetAdjustment = ({ node, ast, videoConfigValues, }) => {
|
|
633
|
+
var _a;
|
|
448
634
|
if (node.type === 'TSAsExpression') {
|
|
449
|
-
return
|
|
635
|
+
return getCurrentFrameDisplayOffsetAdjustment({
|
|
636
|
+
node: node.expression,
|
|
637
|
+
ast,
|
|
638
|
+
videoConfigValues,
|
|
639
|
+
});
|
|
450
640
|
}
|
|
451
641
|
if (node.type !== 'Identifier') {
|
|
452
|
-
return
|
|
642
|
+
return null;
|
|
453
643
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
644
|
+
const nodePath = findNodePath(ast, node);
|
|
645
|
+
const bindingScope = (_a = nodePath === null || nodePath === void 0 ? void 0 : nodePath.scope) === null || _a === void 0 ? void 0 : _a.lookup(node.name);
|
|
646
|
+
if (!nodePath || !bindingScope) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
let matchingDeclarations = 0;
|
|
650
|
+
let isCurrentFrameBinding = false;
|
|
651
|
+
recast.types.visit(bindingScope.path, {
|
|
457
652
|
visitVariableDeclarator(p) {
|
|
653
|
+
var _a;
|
|
458
654
|
const { id, init } = p.node;
|
|
459
|
-
if (id.type !== 'Identifier' ||
|
|
655
|
+
if (id.type !== 'Identifier' ||
|
|
656
|
+
id.name !== node.name ||
|
|
657
|
+
((_a = p.scope.lookup(node.name)) === null || _a === void 0 ? void 0 : _a.path.node) !== bindingScope.path.node) {
|
|
460
658
|
return this.traverse(p);
|
|
461
659
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
else {
|
|
466
|
-
hasOtherDeclaration = true;
|
|
467
|
-
}
|
|
660
|
+
matchingDeclarations++;
|
|
661
|
+
isCurrentFrameBinding = Boolean(init && isUseCurrentFrameCall(init, ast));
|
|
468
662
|
return false;
|
|
469
663
|
},
|
|
470
664
|
});
|
|
471
|
-
|
|
665
|
+
if (matchingDeclarations !== 1 || !isCurrentFrameBinding) {
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
return getFrameDisplayOffsetAdjustmentBetweenPaths({
|
|
669
|
+
startPath: nodePath,
|
|
670
|
+
endPath: bindingScope.path,
|
|
671
|
+
videoConfigValues,
|
|
672
|
+
});
|
|
472
673
|
};
|
|
473
674
|
const getComputedStatus = (node, ast, videoConfigValues) => {
|
|
474
675
|
const interpolation = getInterpolationKeyframes(node, ast, videoConfigValues);
|
|
@@ -478,6 +679,7 @@ const getComputedStatus = (node, ast, videoConfigValues) => {
|
|
|
478
679
|
return {
|
|
479
680
|
status: 'keyframed',
|
|
480
681
|
interpolationFunction: interpolation.interpolationFunction,
|
|
682
|
+
keyframeDisplayOffsetAdjustment: interpolation.keyframeDisplayOffsetAdjustment,
|
|
481
683
|
keyframes: interpolation.keyframes,
|
|
482
684
|
easing: interpolation.easing,
|
|
483
685
|
clamping: interpolation.clamping,
|
|
@@ -648,8 +850,7 @@ const findNodePathForJsxElement = (ast, target) => {
|
|
|
648
850
|
};
|
|
649
851
|
exports.findNodePathForJsxElement = findNodePathForJsxElement;
|
|
650
852
|
const RECAST_TAB_WIDTH = 4;
|
|
651
|
-
const sourceColumnToRecastColumn = ({
|
|
652
|
-
const sourceLine = fileContents.split('\n')[line - 1];
|
|
853
|
+
const sourceColumnToRecastColumn = ({ sourceLine, column, }) => {
|
|
653
854
|
if (sourceLine === undefined) {
|
|
654
855
|
return column;
|
|
655
856
|
}
|
|
@@ -671,8 +872,7 @@ const lineColumnToNodePath = (ast, targetLine, targetColumn, fileContents) => {
|
|
|
671
872
|
const recastTargetColumn = targetColumn === undefined || fileContents === undefined
|
|
672
873
|
? targetColumn
|
|
673
874
|
: sourceColumnToRecastColumn({
|
|
674
|
-
fileContents,
|
|
675
|
-
line: targetLine,
|
|
875
|
+
sourceLine: fileContents.split('\n')[targetLine - 1],
|
|
676
876
|
column: targetColumn,
|
|
677
877
|
});
|
|
678
878
|
recast.types.visit(ast, {
|
|
@@ -694,6 +894,55 @@ const lineColumnToNodePath = (ast, targetLine, targetColumn, fileContents) => {
|
|
|
694
894
|
return (_a = lineMatches.at(-1)) !== null && _a !== void 0 ? _a : null;
|
|
695
895
|
};
|
|
696
896
|
exports.lineColumnToNodePath = lineColumnToNodePath;
|
|
897
|
+
const lineColumnsToNodePaths = ({ ast, targets, fileContents, }) => {
|
|
898
|
+
const sourceLines = fileContents.split('\n');
|
|
899
|
+
const targetIndicesByLine = new Map();
|
|
900
|
+
const recastTargetColumns = targets.map(({ line, column }, index) => {
|
|
901
|
+
var _a;
|
|
902
|
+
const indices = (_a = targetIndicesByLine.get(line)) !== null && _a !== void 0 ? _a : [];
|
|
903
|
+
indices.push(index);
|
|
904
|
+
targetIndicesByLine.set(line, indices);
|
|
905
|
+
return sourceColumnToRecastColumn({
|
|
906
|
+
sourceLine: sourceLines[line - 1],
|
|
907
|
+
column,
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
const lineMatches = targets.map(() => null);
|
|
911
|
+
const exactMatches = targets.map(() => null);
|
|
912
|
+
const exactMatchCounts = targets.map(() => 0);
|
|
913
|
+
recast.types.visit(ast, {
|
|
914
|
+
visitJSXOpeningElement(p) {
|
|
915
|
+
var _a, _b;
|
|
916
|
+
const { node } = p;
|
|
917
|
+
const line = (_a = node.loc) === null || _a === void 0 ? void 0 : _a.start.line;
|
|
918
|
+
const targetIndices = line ? targetIndicesByLine.get(line) : undefined;
|
|
919
|
+
if (targetIndices) {
|
|
920
|
+
const nodePath = (0, exports.getNodePathForRecastPath)(p, ast);
|
|
921
|
+
for (const index of targetIndices) {
|
|
922
|
+
lineMatches[index] = nodePath;
|
|
923
|
+
if (((_b = node.loc) === null || _b === void 0 ? void 0 : _b.start.column) === recastTargetColumns[index]) {
|
|
924
|
+
exactMatches[index] = nodePath;
|
|
925
|
+
exactMatchCounts[index]++;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return this.traverse(p);
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
return targets.map((_, index) => exactMatchCounts[index] === 1 ? exactMatches[index] : lineMatches[index]);
|
|
933
|
+
};
|
|
934
|
+
exports.lineColumnsToNodePaths = lineColumnsToNodePaths;
|
|
935
|
+
const resolveSequencePropsNodePathsFromFilename = ({ fileName, targets, remotionRoot, }) => {
|
|
936
|
+
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
937
|
+
remotionRoot,
|
|
938
|
+
fileName,
|
|
939
|
+
action: 'read',
|
|
940
|
+
});
|
|
941
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
942
|
+
const { ast } = getCachedSequencePropsStatusAst(fileContents);
|
|
943
|
+
return (0, exports.lineColumnsToNodePaths)({ ast, targets, fileContents });
|
|
944
|
+
};
|
|
945
|
+
exports.resolveSequencePropsNodePathsFromFilename = resolveSequencePropsNodePathsFromFilename;
|
|
697
946
|
const PIXEL_VALUE_REGEX = /^-?\d+(\.\d+)?px$/;
|
|
698
947
|
const isSupportedTranslateValue = (value) => {
|
|
699
948
|
const parts = value.split(/\s+/);
|
|
@@ -924,32 +1173,8 @@ const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys,
|
|
|
924
1173
|
}
|
|
925
1174
|
return filteredProps;
|
|
926
1175
|
};
|
|
927
|
-
const
|
|
1176
|
+
const computeSequencePropsStatusFromAstAndIdentifiers = ({ ast, nodePath, componentIdentity, keys, assetKeys, effects, videoConfigIdentifierValues, }) => {
|
|
928
1177
|
var _a;
|
|
929
|
-
if ((cachedSequencePropsStatusAst === null || cachedSequencePropsStatusAst === void 0 ? void 0 : cachedSequencePropsStatusAst.fileContents) !== fileContents) {
|
|
930
|
-
cachedSequencePropsStatusAst = null;
|
|
931
|
-
const snapshot = {
|
|
932
|
-
fileContents,
|
|
933
|
-
ast: (0, parse_ast_1.parseAst)(fileContents),
|
|
934
|
-
videoConfigIdentifierValues: new Map(),
|
|
935
|
-
};
|
|
936
|
-
cachedSequencePropsStatusAst = snapshot;
|
|
937
|
-
queueMicrotask(() => {
|
|
938
|
-
if (cachedSequencePropsStatusAst === snapshot) {
|
|
939
|
-
cachedSequencePropsStatusAst = null;
|
|
940
|
-
}
|
|
941
|
-
});
|
|
942
|
-
}
|
|
943
|
-
const { ast } = cachedSequencePropsStatusAst;
|
|
944
|
-
const videoConfigCacheKey = JSON.stringify(videoConfigValues);
|
|
945
|
-
let videoConfigIdentifierValues = cachedSequencePropsStatusAst.videoConfigIdentifierValues.get(videoConfigCacheKey);
|
|
946
|
-
if (videoConfigIdentifierValues === undefined) {
|
|
947
|
-
videoConfigIdentifierValues = (0, video_config_values_1.getVideoConfigIdentifierValues)({
|
|
948
|
-
ast,
|
|
949
|
-
videoConfigValues,
|
|
950
|
-
});
|
|
951
|
-
cachedSequencePropsStatusAst.videoConfigIdentifierValues.set(videoConfigCacheKey, videoConfigIdentifierValues);
|
|
952
|
-
}
|
|
953
1178
|
const jsxElementNode = (0, exports.findJsxElementNodeAtNodePath)(ast, nodePath);
|
|
954
1179
|
const jsxElement = (_a = jsxElementNode === null || jsxElementNode === void 0 ? void 0 : jsxElementNode.openingElement) !== null && _a !== void 0 ? _a : null;
|
|
955
1180
|
if (!jsxElement || !jsxElementNode) {
|
|
@@ -975,12 +1200,80 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, compone
|
|
|
975
1200
|
effects,
|
|
976
1201
|
videoConfigValues: videoConfigIdentifierValues,
|
|
977
1202
|
});
|
|
1203
|
+
const defaultKeyframeDisplayOffsetAdjustment = getDefaultFrameDisplayOffsetAdjustment({
|
|
1204
|
+
jsxElement,
|
|
1205
|
+
ast,
|
|
1206
|
+
videoConfigValues: videoConfigIdentifierValues,
|
|
1207
|
+
});
|
|
1208
|
+
const addDefaultKeyframeDisplayOffsetAdjustment = (status) => {
|
|
1209
|
+
if (status.status !== 'static') {
|
|
1210
|
+
return status;
|
|
1211
|
+
}
|
|
1212
|
+
if (defaultKeyframeDisplayOffsetAdjustment === null) {
|
|
1213
|
+
return computedStatus();
|
|
1214
|
+
}
|
|
1215
|
+
if (defaultKeyframeDisplayOffsetAdjustment === 0) {
|
|
1216
|
+
return status;
|
|
1217
|
+
}
|
|
1218
|
+
return {
|
|
1219
|
+
...status,
|
|
1220
|
+
keyframeDisplayOffsetAdjustment: defaultKeyframeDisplayOffsetAdjustment,
|
|
1221
|
+
};
|
|
1222
|
+
};
|
|
978
1223
|
return {
|
|
979
1224
|
canUpdate: true,
|
|
980
|
-
props: filteredProps,
|
|
981
|
-
|
|
1225
|
+
props: Object.fromEntries(Object.entries(filteredProps).map(([key, status]) => [
|
|
1226
|
+
key,
|
|
1227
|
+
addDefaultKeyframeDisplayOffsetAdjustment(status),
|
|
1228
|
+
])),
|
|
1229
|
+
effects: effectsStatuses.map((effectStatus) => effectStatus.canUpdate
|
|
1230
|
+
? {
|
|
1231
|
+
...effectStatus,
|
|
1232
|
+
props: Object.fromEntries(Object.entries(effectStatus.props).map(([key, status]) => [
|
|
1233
|
+
key,
|
|
1234
|
+
addDefaultKeyframeDisplayOffsetAdjustment(status),
|
|
1235
|
+
])),
|
|
1236
|
+
}
|
|
1237
|
+
: effectStatus),
|
|
982
1238
|
};
|
|
983
1239
|
};
|
|
1240
|
+
const computeSequencePropsStatusFromAst = ({ ast, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
|
|
1241
|
+
return computeSequencePropsStatusFromAstAndIdentifiers({
|
|
1242
|
+
ast,
|
|
1243
|
+
nodePath,
|
|
1244
|
+
componentIdentity,
|
|
1245
|
+
keys,
|
|
1246
|
+
assetKeys,
|
|
1247
|
+
effects,
|
|
1248
|
+
videoConfigIdentifierValues: (0, video_config_values_1.getVideoConfigIdentifierValues)({
|
|
1249
|
+
ast,
|
|
1250
|
+
videoConfigValues,
|
|
1251
|
+
}),
|
|
1252
|
+
});
|
|
1253
|
+
};
|
|
1254
|
+
exports.computeSequencePropsStatusFromAst = computeSequencePropsStatusFromAst;
|
|
1255
|
+
const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
|
|
1256
|
+
const cachedAst = getCachedSequencePropsStatusAst(fileContents);
|
|
1257
|
+
const { ast } = cachedAst;
|
|
1258
|
+
const videoConfigCacheKey = JSON.stringify(videoConfigValues);
|
|
1259
|
+
let videoConfigIdentifierValues = cachedAst.videoConfigIdentifierValues.get(videoConfigCacheKey);
|
|
1260
|
+
if (videoConfigIdentifierValues === undefined) {
|
|
1261
|
+
videoConfigIdentifierValues = (0, video_config_values_1.getVideoConfigIdentifierValues)({
|
|
1262
|
+
ast,
|
|
1263
|
+
videoConfigValues,
|
|
1264
|
+
});
|
|
1265
|
+
cachedAst.videoConfigIdentifierValues.set(videoConfigCacheKey, videoConfigIdentifierValues);
|
|
1266
|
+
}
|
|
1267
|
+
return computeSequencePropsStatusFromAstAndIdentifiers({
|
|
1268
|
+
ast,
|
|
1269
|
+
nodePath,
|
|
1270
|
+
componentIdentity,
|
|
1271
|
+
keys,
|
|
1272
|
+
assetKeys,
|
|
1273
|
+
effects,
|
|
1274
|
+
videoConfigIdentifierValues,
|
|
1275
|
+
});
|
|
1276
|
+
};
|
|
984
1277
|
exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
|
|
985
1278
|
const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, keys, assetKeys = [], effects, remotionRoot, videoConfigValues, }) => {
|
|
986
1279
|
const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
@@ -1008,7 +1301,7 @@ const computeSequencePropsStatusFromFilenameByLocation = ({ fileName, line, colu
|
|
|
1008
1301
|
action: 'read',
|
|
1009
1302
|
});
|
|
1010
1303
|
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
1011
|
-
const ast = (
|
|
1304
|
+
const { ast } = getCachedSequencePropsStatusAst(fileContents);
|
|
1012
1305
|
const resolvedNodePath = (0, exports.lineColumnToNodePath)(ast, line, column, fileContents);
|
|
1013
1306
|
if (!resolvedNodePath) {
|
|
1014
1307
|
return {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getDefaultEditorInfoHandler = void 0;
|
|
4
|
+
const custom_editor_1 = require("../../helpers/custom-editor");
|
|
4
5
|
const editor_registry_1 = require("../../helpers/editor-registry");
|
|
5
6
|
const getDefaultEditorInfoHandler = async ({ getDefaultEditor }) => {
|
|
6
7
|
const installedEditors = await (0, editor_registry_1.getAvailableEditors)();
|
|
7
8
|
const configuredEditor = getDefaultEditor();
|
|
8
|
-
const customEditor = configuredEditor &&
|
|
9
|
+
const customEditor = configuredEditor &&
|
|
10
|
+
typeof configuredEditor === 'object' &&
|
|
11
|
+
(0, custom_editor_1.resolveCustomEditorExecutable)(configuredEditor)
|
|
9
12
|
? configuredEditor
|
|
10
13
|
: null;
|
|
11
14
|
return {
|
|
@@ -190,6 +190,7 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
190
190
|
}
|
|
191
191
|
const snapshots = [];
|
|
192
192
|
const outputByPath = new Map();
|
|
193
|
+
const statusAstByPath = new Map();
|
|
193
194
|
const resultByIndex = new Map();
|
|
194
195
|
const updatedNodePaths = new Map();
|
|
195
196
|
const sequenceKeyframeLogs = [];
|
|
@@ -198,14 +199,20 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
198
199
|
for (const [absolutePath, group] of editGroups) {
|
|
199
200
|
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
200
201
|
let output = fileContents;
|
|
202
|
+
const cachedStatusAst = group.edits.length > 0
|
|
203
|
+
? (0, can_update_sequence_props_1.takeCachedSequencePropsStatusAst)(fileContents)
|
|
204
|
+
: null;
|
|
205
|
+
let sequencePropsAst = null;
|
|
201
206
|
let firstLogLine = Number.POSITIVE_INFINITY;
|
|
202
207
|
if (group.edits.length > 0) {
|
|
203
|
-
const { output: sequencePropsOutput, formatted, results: updateResults, } = await (0, update_sequence_props_1.updateMultipleSequenceProps)({
|
|
208
|
+
const { output: sequencePropsOutput, formatted, results: updateResults, ast, } = await (0, update_sequence_props_1.updateMultipleSequenceProps)({
|
|
204
209
|
input: output,
|
|
205
210
|
changes: group.edits.map(exports.convertSequencePropEditToCodemodChange),
|
|
206
211
|
prettierConfigOverride: null,
|
|
212
|
+
ast: cachedStatusAst !== null && cachedStatusAst !== void 0 ? cachedStatusAst : undefined,
|
|
207
213
|
});
|
|
208
214
|
output = sequencePropsOutput;
|
|
215
|
+
sequencePropsAst = ast;
|
|
209
216
|
const firstUpdate = updateResults[0];
|
|
210
217
|
if (firstUpdate) {
|
|
211
218
|
firstLogLine = Math.min(firstLogLine, firstUpdate.logLine);
|
|
@@ -365,6 +372,13 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
365
372
|
});
|
|
366
373
|
}
|
|
367
374
|
}
|
|
375
|
+
if (sequencePropsAst &&
|
|
376
|
+
group.captionPatches.length === 0 &&
|
|
377
|
+
group.addedKeyframes.length === 0 &&
|
|
378
|
+
group.movedSequenceKeyframes.length === 0 &&
|
|
379
|
+
group.effectKeyframes.length === 0) {
|
|
380
|
+
statusAstByPath.set(absolutePath, sequencePropsAst);
|
|
381
|
+
}
|
|
368
382
|
outputByPath.set(absolutePath, output);
|
|
369
383
|
snapshots.push({
|
|
370
384
|
filePath: absolutePath,
|
|
@@ -481,15 +495,24 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
|
|
|
481
495
|
if (!output) {
|
|
482
496
|
throw new Error('Could not compute sequence prop edit status');
|
|
483
497
|
}
|
|
484
|
-
const
|
|
485
|
-
fileContents: output,
|
|
498
|
+
const statusInput = {
|
|
486
499
|
keys: (0, studio_shared_1.getAllSchemaKeys)(target.schema),
|
|
487
500
|
assetKeys: (0, studio_shared_1.getAssetSchemaKeys)(target.schema),
|
|
488
501
|
nodePath: (_a = updatedNodePaths.get(`${absolutePath}:${JSON.stringify(target.nodePath.nodePath)}`)) !== null && _a !== void 0 ? _a : target.nodePath.nodePath,
|
|
489
502
|
componentIdentity: null,
|
|
490
503
|
effects: [],
|
|
491
504
|
videoConfigValues: target.nodePath.videoConfigValues,
|
|
492
|
-
}
|
|
505
|
+
};
|
|
506
|
+
const statusAst = statusAstByPath.get(absolutePath);
|
|
507
|
+
const newStatus = statusAst
|
|
508
|
+
? (0, can_update_sequence_props_1.computeSequencePropsStatusFromAst)({
|
|
509
|
+
...statusInput,
|
|
510
|
+
ast: statusAst,
|
|
511
|
+
})
|
|
512
|
+
: (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
|
|
513
|
+
...statusInput,
|
|
514
|
+
fileContents: output,
|
|
515
|
+
});
|
|
493
516
|
return {
|
|
494
517
|
fileName: target.fileName,
|
|
495
518
|
nodePath: target.nodePath,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SubscribeToSequencePropsBatchRequest, SubscribeToSequencePropsBatchResponse } from '@remotion/studio-shared';
|
|
2
2
|
import type { ApiHandler } from '../api-types';
|
|
3
|
-
export declare const subscribeToSequenceProps: ApiHandler<
|
|
3
|
+
export declare const subscribeToSequenceProps: ApiHandler<SubscribeToSequencePropsBatchRequest, SubscribeToSequencePropsBatchResponse>;
|
|
@@ -2,12 +2,43 @@
|
|
|
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
|
|
6
|
-
|
|
5
|
+
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
6
|
+
const subscribeToSequenceProps = ({ input, remotionRoot, logLevel }) => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
const requests = (_a = input.requests) !== null && _a !== void 0 ? _a : [input];
|
|
9
|
+
const unresolvedByFile = new Map();
|
|
10
|
+
for (const [index, request] of requests.entries()) {
|
|
11
|
+
if (request.nodePath !== null) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const unresolved = (_b = unresolvedByFile.get(request.fileName)) !== null && _b !== void 0 ? _b : [];
|
|
15
|
+
unresolved.push({ index, line: request.line, column: request.column });
|
|
16
|
+
unresolvedByFile.set(request.fileName, unresolved);
|
|
17
|
+
}
|
|
18
|
+
const resolvedNodePaths = new Map();
|
|
19
|
+
for (const [fileName, unresolved] of unresolvedByFile) {
|
|
20
|
+
try {
|
|
21
|
+
const nodePaths = (0, can_update_sequence_props_1.resolveSequencePropsNodePathsFromFilename)({
|
|
22
|
+
fileName,
|
|
23
|
+
targets: unresolved,
|
|
24
|
+
remotionRoot,
|
|
25
|
+
});
|
|
26
|
+
for (const [index, nodePath] of nodePaths.entries()) {
|
|
27
|
+
if (nodePath) {
|
|
28
|
+
resolvedNodePaths.set(unresolved[index].index, nodePath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (_c) {
|
|
33
|
+
// Let each subscription produce its usual not-found response.
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const results = requests.map(({ fileName, line, column, nodePath, componentIdentity, keys, assetKeys = [], effects, clientId, videoConfigValues, }, index) => (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
|
|
7
37
|
fileName,
|
|
8
38
|
line,
|
|
9
39
|
column,
|
|
10
40
|
nodePath,
|
|
41
|
+
resolvedNodePath: resolvedNodePaths.get(index),
|
|
11
42
|
componentIdentity,
|
|
12
43
|
keys,
|
|
13
44
|
assetKeys,
|
|
@@ -16,7 +47,10 @@ const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, c
|
|
|
16
47
|
clientId,
|
|
17
48
|
videoConfigValues,
|
|
18
49
|
logLevel,
|
|
50
|
+
}));
|
|
51
|
+
return Promise.resolve({
|
|
52
|
+
...results[0],
|
|
53
|
+
results,
|
|
19
54
|
});
|
|
20
|
-
return Promise.resolve(result);
|
|
21
55
|
};
|
|
22
56
|
exports.subscribeToSequenceProps = subscribeToSequenceProps;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
|
|
2
2
|
import type { SequenceNodePath, VideoConfigValues } from 'remotion';
|
|
3
|
-
export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }: {
|
|
3
|
+
export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }: {
|
|
4
4
|
fileName: string;
|
|
5
5
|
line: number;
|
|
6
6
|
column: number;
|
|
7
7
|
nodePath: SequenceNodePath | null;
|
|
8
|
+
resolvedNodePath?: SequenceNodePath | null | undefined;
|
|
8
9
|
componentIdentity: string | null;
|
|
9
10
|
keys: string[];
|
|
10
11
|
assetKeys: string[];
|
|
@@ -15,7 +15,7 @@ const node_path_cache_1 = require("./node-path-cache");
|
|
|
15
15
|
const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
|
|
16
16
|
const sequencePropsWatchers = {};
|
|
17
17
|
const getWatcherKey = (nodePath, assetKeys) => `${(0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath)}:${assetKeys.join('\0')}:${JSON.stringify(nodePath.videoConfigValues)}`;
|
|
18
|
-
const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
|
|
18
|
+
const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
|
|
19
19
|
if (preferredNodePath) {
|
|
20
20
|
try {
|
|
21
21
|
const fromNodePath = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
|
|
@@ -85,6 +85,36 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
|
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
if (resolvedNodePath) {
|
|
89
|
+
try {
|
|
90
|
+
return {
|
|
91
|
+
status: (0, can_update_sequence_props_1.computeSequencePropsStatus)({
|
|
92
|
+
fileName,
|
|
93
|
+
nodePath: resolvedNodePath,
|
|
94
|
+
componentIdentity,
|
|
95
|
+
keys,
|
|
96
|
+
assetKeys,
|
|
97
|
+
effects,
|
|
98
|
+
remotionRoot,
|
|
99
|
+
videoConfigValues,
|
|
100
|
+
}),
|
|
101
|
+
nodePath: {
|
|
102
|
+
absolutePath: node_path_1.default.resolve(remotionRoot, fileName),
|
|
103
|
+
nodePath: resolvedNodePath,
|
|
104
|
+
sequenceKeys: keys,
|
|
105
|
+
effectKeys: effects,
|
|
106
|
+
videoConfigValues,
|
|
107
|
+
},
|
|
108
|
+
success: true,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (!(error instanceof jsx_component_identity_1.JsxElementIdentityMismatchError ||
|
|
113
|
+
error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError)) {
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
88
118
|
const status = (0, can_update_sequence_props_1.computeSequencePropsStatusFromFilenameByLocation)({
|
|
89
119
|
fileName,
|
|
90
120
|
line,
|
|
@@ -99,13 +129,14 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
|
|
|
99
129
|
});
|
|
100
130
|
return status;
|
|
101
131
|
};
|
|
102
|
-
const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }) => {
|
|
132
|
+
const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath = null, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }) => {
|
|
103
133
|
var _a;
|
|
104
134
|
const initialResult = getSequencePropsStatus({
|
|
105
135
|
fileName,
|
|
106
136
|
line,
|
|
107
137
|
column,
|
|
108
138
|
preferredNodePath,
|
|
139
|
+
resolvedNodePath,
|
|
109
140
|
componentIdentity,
|
|
110
141
|
keys,
|
|
111
142
|
assetKeys,
|
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.513",
|
|
7
7
|
"description": "Run a Remotion Studio with a server backend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"scripts": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@remotion/studio-protocol": "4.0.
|
|
26
|
+
"@remotion/studio-protocol": "4.0.513",
|
|
27
27
|
"@babel/types": "7.24.0",
|
|
28
28
|
"@babel/parser": "7.24.1",
|
|
29
29
|
"@svgr/core": "8.1.0",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"semver": "7.5.3",
|
|
33
33
|
"zod": "4.4.3",
|
|
34
34
|
"prettier": "3.8.1",
|
|
35
|
-
"remotion": "4.0.
|
|
35
|
+
"remotion": "4.0.513",
|
|
36
36
|
"recast": "0.23.11",
|
|
37
|
-
"@remotion/bundler": "4.0.
|
|
38
|
-
"@remotion/renderer": "4.0.
|
|
39
|
-
"@remotion/studio-codemods": "4.0.
|
|
40
|
-
"@remotion/studio-shared": "4.0.
|
|
37
|
+
"@remotion/bundler": "4.0.513",
|
|
38
|
+
"@remotion/renderer": "4.0.513",
|
|
39
|
+
"@remotion/studio-codemods": "4.0.513",
|
|
40
|
+
"@remotion/studio-shared": "4.0.513",
|
|
41
41
|
"memfs": "3.4.3",
|
|
42
42
|
"open": "8.4.2"
|
|
43
43
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"ast-types": "0.16.1",
|
|
46
46
|
"react": "19.2.3",
|
|
47
47
|
"@types/semver": "7.5.3",
|
|
48
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
48
|
+
"@remotion/eslint-config-internal": "4.0.513",
|
|
49
49
|
"eslint": "9.19.0",
|
|
50
50
|
"@types/node": "20.12.14",
|
|
51
51
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|