@remotion/studio-server 4.0.464 → 4.0.466
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/apply-codemod-to-file.d.ts +6 -0
- package/dist/codemods/apply-codemod-to-file.js +35 -0
- package/dist/codemods/delete-effect.d.ts +12 -0
- package/dist/codemods/delete-effect.js +54 -0
- package/dist/codemods/duplicate-composition.js +1 -1
- package/dist/codemods/recast-mods.js +64 -0
- package/dist/codemods/update-effect-props/update-effect-props.d.ts +1 -0
- package/dist/codemods/update-effect-props/update-effect-props.js +6 -6
- package/dist/helpers/resolve-composition-component.d.ts +11 -0
- package/dist/helpers/resolve-composition-component.js +691 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/dev-middleware/setup-output-filesystem.js +2 -2
- package/dist/preview-server/routes/add-render.js +1 -0
- package/dist/preview-server/routes/apply-codemod.js +66 -12
- package/dist/preview-server/routes/can-update-effect-props.js +4 -5
- 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/delete-effect.d.ts +3 -0
- package/dist/preview-server/routes/delete-effect.js +68 -0
- package/dist/preview-server/routes/log-updates/formatting.js +3 -1
- package/dist/preview-server/undo-stack.d.ts +9 -1
- package/dist/routes.js +39 -0
- package/package.json +6 -6
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RecastCodemod, SymbolicatedStackFrame } from '@remotion/studio-shared';
|
|
2
|
+
export declare const resolveFilePathFromSymbolicatedStack: (remotionRoot: string, stack: SymbolicatedStackFrame) => string;
|
|
3
|
+
export declare const applyCodemodToFile: ({ filePath, codeMod, }: {
|
|
4
|
+
filePath: string;
|
|
5
|
+
codeMod: RecastCodemod;
|
|
6
|
+
}) => Promise<string>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.applyCodemodToFile = exports.resolveFilePathFromSymbolicatedStack = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const can_update_default_props_1 = require("../preview-server/routes/can-update-default-props");
|
|
10
|
+
const duplicate_composition_1 = require("./duplicate-composition");
|
|
11
|
+
const resolveFilePathFromSymbolicatedStack = (remotionRoot, stack) => {
|
|
12
|
+
if (!stack.originalFileName) {
|
|
13
|
+
throw new Error('Could not determine the file where this composition is defined');
|
|
14
|
+
}
|
|
15
|
+
const absolutePath = node_path_1.default.resolve(remotionRoot, stack.originalFileName);
|
|
16
|
+
const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
|
|
17
|
+
if (fileRelativeToRoot.startsWith('..')) {
|
|
18
|
+
throw new Error('Cannot apply codemod to a file outside the project');
|
|
19
|
+
}
|
|
20
|
+
if (!(0, node_fs_1.existsSync)(absolutePath)) {
|
|
21
|
+
throw new Error(`File not found: ${stack.originalFileName}`);
|
|
22
|
+
}
|
|
23
|
+
return absolutePath;
|
|
24
|
+
};
|
|
25
|
+
exports.resolveFilePathFromSymbolicatedStack = resolveFilePathFromSymbolicatedStack;
|
|
26
|
+
const applyCodemodToFile = async ({ filePath, codeMod, }) => {
|
|
27
|
+
(0, can_update_default_props_1.checkIfTypeScriptFile)(filePath);
|
|
28
|
+
const input = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
|
|
29
|
+
const { newContents } = (0, duplicate_composition_1.parseAndApplyCodemod)({
|
|
30
|
+
codeMod,
|
|
31
|
+
input,
|
|
32
|
+
});
|
|
33
|
+
return (0, duplicate_composition_1.formatOutput)(newContents);
|
|
34
|
+
};
|
|
35
|
+
exports.applyCodemodToFile = applyCodemodToFile;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SequenceNodePath } from 'remotion';
|
|
2
|
+
export declare const deleteEffect: ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }: {
|
|
3
|
+
input: string;
|
|
4
|
+
sequenceNodePath: SequenceNodePath;
|
|
5
|
+
effectIndex: number;
|
|
6
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
output: string;
|
|
9
|
+
formatted: boolean;
|
|
10
|
+
effectLabel: string;
|
|
11
|
+
logLine: number;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteEffect = void 0;
|
|
4
|
+
const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
|
|
5
|
+
const format_file_content_1 = require("./format-file-content");
|
|
6
|
+
const parse_ast_1 = require("./parse-ast");
|
|
7
|
+
const update_effect_props_1 = require("./update-effect-props/update-effect-props");
|
|
8
|
+
const getEffectsArray = (attr) => {
|
|
9
|
+
if (!attr.value || attr.value.type !== 'JSXExpressionContainer') {
|
|
10
|
+
throw new Error('Cannot delete effect: effects prop is not an array');
|
|
11
|
+
}
|
|
12
|
+
const expr = attr.value.expression;
|
|
13
|
+
if (expr.type !== 'ArrayExpression') {
|
|
14
|
+
throw new Error('Cannot delete effect: effects prop is not an array');
|
|
15
|
+
}
|
|
16
|
+
return expr;
|
|
17
|
+
};
|
|
18
|
+
const deleteEffect = async ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }) => {
|
|
19
|
+
var _a, _b;
|
|
20
|
+
var _c, _d, _e;
|
|
21
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
22
|
+
const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, sequenceNodePath);
|
|
23
|
+
if (!jsx) {
|
|
24
|
+
throw new Error('Could not find a JSX element at the specified location to delete effect');
|
|
25
|
+
}
|
|
26
|
+
const attr = (0, update_effect_props_1.findEffectsAttr)((_c = jsx.attributes) !== null && _c !== void 0 ? _c : []);
|
|
27
|
+
if (!attr) {
|
|
28
|
+
throw new Error('Could not find effects on the target JSX element');
|
|
29
|
+
}
|
|
30
|
+
const effectsArray = getEffectsArray(attr);
|
|
31
|
+
const found = (0, update_effect_props_1.findEffectCallExpression)({ attr, effectIndex });
|
|
32
|
+
if (found.kind === 'error') {
|
|
33
|
+
throw new Error(`Cannot delete effect: ${found.reason}`);
|
|
34
|
+
}
|
|
35
|
+
effectsArray.elements.splice(effectIndex, 1);
|
|
36
|
+
if (effectsArray.elements.length === 0) {
|
|
37
|
+
const attrIndex = jsx.attributes.indexOf(attr);
|
|
38
|
+
if (attrIndex !== -1) {
|
|
39
|
+
jsx.attributes.splice(attrIndex, 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
43
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
44
|
+
input: finalFile,
|
|
45
|
+
prettierConfigOverride,
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
output,
|
|
49
|
+
formatted,
|
|
50
|
+
effectLabel: `${found.callee}()`,
|
|
51
|
+
logLine: (_e = (_d = (_a = found.call.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _d !== void 0 ? _d : (_b = jsx.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _e !== void 0 ? _e : 1,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
exports.deleteEffect = deleteEffect;
|
|
@@ -69,7 +69,7 @@ const parseAndApplyCodemod = ({ input, codeMod, }) => {
|
|
|
69
69
|
codeMod,
|
|
70
70
|
});
|
|
71
71
|
if (changesMade.length === 0) {
|
|
72
|
-
throw new Error('Unable to calculate the changes needed for this file. Edit the
|
|
72
|
+
throw new Error('Unable to calculate the changes needed for this file. Edit the file manually.');
|
|
73
73
|
}
|
|
74
74
|
const output = (0, parse_ast_1.serializeAst)(newAst);
|
|
75
75
|
return { changesMade, newContents: output };
|
|
@@ -60,11 +60,65 @@ const mapReturnStatement = (statement, transformation, changesMade) => {
|
|
|
60
60
|
if (!statement.argument) {
|
|
61
61
|
return statement;
|
|
62
62
|
}
|
|
63
|
+
const replacement = transformLoneJsxElement(statement.argument, transformation, changesMade);
|
|
64
|
+
if (replacement !== null) {
|
|
65
|
+
return { ...statement, argument: replacement };
|
|
66
|
+
}
|
|
63
67
|
return {
|
|
64
68
|
...statement,
|
|
65
69
|
argument: mapAll(statement.argument, transformation, changesMade),
|
|
66
70
|
};
|
|
67
71
|
};
|
|
72
|
+
const nullLiteral = () => ({ type: 'NullLiteral' });
|
|
73
|
+
// When a node was originally parenthesized (e.g. the `<JSX/>` inside
|
|
74
|
+
// `return (<JSX/>)`), Babel records `extra.parenthesized` on it. If we move
|
|
75
|
+
// such a node into a JSXFragment without clearing that hint, recast prints
|
|
76
|
+
// stray `(` / `)` characters around it as JSX text. Clear the hint so the
|
|
77
|
+
// node prints cleanly in its new context.
|
|
78
|
+
const stripParenthesizedExtra = (node) => {
|
|
79
|
+
if (!node.extra) {
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
const { parenthesized: _p, parenStart: _ps, ...rest } = node.extra;
|
|
83
|
+
return { ...node, extra: rest };
|
|
84
|
+
};
|
|
85
|
+
const wrapInJsxFragment = (children) => ({
|
|
86
|
+
type: 'JSXFragment',
|
|
87
|
+
openingFragment: { type: 'JSXOpeningFragment' },
|
|
88
|
+
closingFragment: { type: 'JSXClosingFragment' },
|
|
89
|
+
children: children.map(stripParenthesizedExtra),
|
|
90
|
+
});
|
|
91
|
+
// When a <Composition> JSX element appears in a position where it cannot
|
|
92
|
+
// simply be removed from a parent's children list (e.g. as the sole return
|
|
93
|
+
// value of a wrapper component or as the concise body of an arrow function),
|
|
94
|
+
// we still want delete/rename/duplicate codemods to work. This helper detects
|
|
95
|
+
// that case and produces a structurally-valid replacement expression.
|
|
96
|
+
const transformLoneJsxElement = (expression, transformation, changesMade) => {
|
|
97
|
+
if (expression.type !== 'JSXElement') {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const compId = getCompositionIdFromJSXElement(expression);
|
|
101
|
+
if (compId === null) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const isMatch = (transformation.type === 'delete-composition' &&
|
|
105
|
+
compId === transformation.idToDelete) ||
|
|
106
|
+
(transformation.type === 'rename-composition' &&
|
|
107
|
+
compId === transformation.idToRename) ||
|
|
108
|
+
(transformation.type === 'duplicate-composition' &&
|
|
109
|
+
compId === transformation.idToDuplicate);
|
|
110
|
+
if (!isMatch) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const transformed = mapJsxChild(expression, transformation, changesMade);
|
|
114
|
+
if (transformed.length === 0) {
|
|
115
|
+
return nullLiteral();
|
|
116
|
+
}
|
|
117
|
+
if (transformed.length === 1) {
|
|
118
|
+
return transformed[0];
|
|
119
|
+
}
|
|
120
|
+
return wrapInJsxFragment(transformed);
|
|
121
|
+
};
|
|
68
122
|
const mapJsxElementOrFragment = (jsxFragment, transformation, changesMade) => {
|
|
69
123
|
return {
|
|
70
124
|
...jsxFragment,
|
|
@@ -129,6 +183,16 @@ const mapRecognizedType = (expression, transformation, changesMade) => {
|
|
|
129
183
|
}
|
|
130
184
|
if (expression.type === 'ArrowFunctionExpression' ||
|
|
131
185
|
expression.type === 'FunctionExpression') {
|
|
186
|
+
if (expression.type === 'ArrowFunctionExpression' &&
|
|
187
|
+
expression.body.type === 'JSXElement') {
|
|
188
|
+
const replacement = transformLoneJsxElement(expression.body, transformation, changesMade);
|
|
189
|
+
if (replacement !== null) {
|
|
190
|
+
return {
|
|
191
|
+
...expression,
|
|
192
|
+
body: replacement,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
132
196
|
return {
|
|
133
197
|
...expression,
|
|
134
198
|
body: mapAll(expression.body, transformation, changesMade),
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.updateEffectProps = exports.updateEffectPropsAst = exports.findEffectCallExpression = exports.enumerateEffectArrayElements = void 0;
|
|
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
39
|
const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
|
|
@@ -50,19 +50,19 @@ const parseValueExpression = (value) => {
|
|
|
50
50
|
}
|
|
51
51
|
return stmt.expression.right;
|
|
52
52
|
};
|
|
53
|
-
const
|
|
53
|
+
const findEffectsAttr = (attrs) => {
|
|
54
54
|
for (const attr of attrs) {
|
|
55
55
|
if (attr.type !== 'JSXAttribute') {
|
|
56
56
|
continue;
|
|
57
57
|
}
|
|
58
58
|
const a = attr;
|
|
59
|
-
if (a.name.type === 'JSXIdentifier' &&
|
|
60
|
-
a.name.name === '_experimentalEffects') {
|
|
59
|
+
if (a.name.type === 'JSXIdentifier' && a.name.name === 'effects') {
|
|
61
60
|
return a;
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
return null;
|
|
65
64
|
};
|
|
65
|
+
exports.findEffectsAttr = findEffectsAttr;
|
|
66
66
|
const getCalleeName = (call) => {
|
|
67
67
|
const { callee } = call;
|
|
68
68
|
if (callee.type === 'Identifier') {
|
|
@@ -140,9 +140,9 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
|
|
|
140
140
|
if (!jsx) {
|
|
141
141
|
throw new Error('Could not find a JSX element at the specified location to update effects');
|
|
142
142
|
}
|
|
143
|
-
const attr =
|
|
143
|
+
const attr = (0, exports.findEffectsAttr)((_e = jsx.attributes) !== null && _e !== void 0 ? _e : []);
|
|
144
144
|
if (!attr) {
|
|
145
|
-
throw new Error('Could not find
|
|
145
|
+
throw new Error('Could not find effects on the target JSX element');
|
|
146
146
|
}
|
|
147
147
|
const found = (0, exports.findEffectCallExpression)({
|
|
148
148
|
attr,
|
|
@@ -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>;
|