@remotion/studio-server 4.0.444 → 4.0.446
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/client-render-queue.js +1 -0
- package/dist/codemods/delete-jsx-node.js +10 -50
- package/dist/codemods/duplicate-jsx-node.d.ts +12 -0
- package/dist/codemods/duplicate-jsx-node.js +311 -0
- package/dist/codemods/format-file-content.d.ts +7 -0
- package/dist/codemods/format-file-content.js +80 -0
- package/dist/codemods/jsx-sequence-context.d.ts +11 -0
- package/dist/codemods/jsx-sequence-context.js +68 -0
- package/dist/codemods/update-default-props.js +1 -0
- package/dist/codemods/update-sequence-props.js +6 -44
- package/dist/file-watcher.d.ts +7 -0
- package/dist/file-watcher.js +19 -7
- package/dist/helpers/get-ast-node-path.d.ts +3 -0
- package/dist/helpers/get-ast-node-path.js +48 -0
- package/dist/index.d.ts +1 -0
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/default-props-watchers.js +1 -0
- package/dist/preview-server/file-existence-watchers.js +1 -0
- package/dist/preview-server/get-static-file-fallback-hint.d.ts +7 -0
- package/dist/preview-server/get-static-file-fallback-hint.js +43 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +6 -6
- package/dist/preview-server/routes/duplicate-jsx-node.d.ts +3 -0
- package/dist/preview-server/routes/duplicate-jsx-node.js +66 -0
- package/dist/preview-server/sequence-props-watchers.js +1 -0
- package/dist/preview-server/undo-stack.d.ts +3 -1
- package/dist/preview-server/undo-stack.js +1 -0
- package/dist/routes.js +22 -1
- package/dist/watch-root-file.js +1 -0
- package/package.json +7 -7
|
@@ -26,6 +26,7 @@ const addCompletedClientRender = ({ render, remotionRoot, }) => {
|
|
|
26
26
|
const filePath = (0, resolve_output_path_1.resolveOutputPath)(remotionRoot, render.outName);
|
|
27
27
|
const { unwatch } = (0, file_watcher_1.installFileWatcher)({
|
|
28
28
|
file: filePath,
|
|
29
|
+
existenceOnly: true,
|
|
29
30
|
onChange: (event) => {
|
|
30
31
|
if (event.type === 'created' || event.type === 'deleted') {
|
|
31
32
|
updateCompletedClientRender(render.id, {
|
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.deleteJsxNode = exports.deleteJsxElementAtPath = exports.findJsxElementPathForDeletion = exports.getJsxElementTagLabel = void 0;
|
|
37
37
|
const recast = __importStar(require("recast"));
|
|
38
|
+
const get_ast_node_path_1 = require("../helpers/get-ast-node-path");
|
|
39
|
+
const format_file_content_1 = require("./format-file-content");
|
|
38
40
|
const parse_ast_1 = require("./parse-ast");
|
|
39
41
|
const { builders: b, namedTypes } = recast.types;
|
|
40
42
|
/** Recast `builders.nullLiteral()` is typed against ast-types; normalize to Babel `Expression`. */
|
|
@@ -63,12 +65,9 @@ const getJsxElementTagLabel = (element) => {
|
|
|
63
65
|
};
|
|
64
66
|
exports.getJsxElementTagLabel = getJsxElementTagLabel;
|
|
65
67
|
const findJsxElementPathForDeletion = (ast, nodePath) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (current.value === null || current.value === undefined) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
68
|
+
const current = (0, get_ast_node_path_1.getAstNodePath)(ast, nodePath);
|
|
69
|
+
if (!current) {
|
|
70
|
+
return null;
|
|
72
71
|
}
|
|
73
72
|
if (namedTypes.JSXOpeningElement.check(current.value)) {
|
|
74
73
|
const parent = current.parentPath;
|
|
@@ -301,52 +300,13 @@ const deleteJsxNode = async ({ input, nodePath, prettierConfigOverride, }) => {
|
|
|
301
300
|
const logLine = (_d = (_c = (_a = jsxElement.openingElement.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _c !== void 0 ? _c : (_b = jsxElement.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : 1;
|
|
302
301
|
(0, exports.deleteJsxElementAtPath)(jsxPath);
|
|
303
302
|
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
catch (_e) {
|
|
309
|
-
return {
|
|
310
|
-
output: finalFile,
|
|
311
|
-
formatted: false,
|
|
312
|
-
nodeLabel,
|
|
313
|
-
logLine,
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
const { format, resolveConfig, resolveConfigFile } = prettier;
|
|
317
|
-
let prettierConfig;
|
|
318
|
-
if (prettierConfigOverride !== undefined) {
|
|
319
|
-
prettierConfig = prettierConfigOverride;
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
const configFilePath = await resolveConfigFile();
|
|
323
|
-
if (!configFilePath) {
|
|
324
|
-
return {
|
|
325
|
-
output: finalFile,
|
|
326
|
-
formatted: false,
|
|
327
|
-
nodeLabel,
|
|
328
|
-
logLine,
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
prettierConfig = await resolveConfig(configFilePath);
|
|
332
|
-
}
|
|
333
|
-
if (!prettierConfig) {
|
|
334
|
-
return {
|
|
335
|
-
output: finalFile,
|
|
336
|
-
formatted: false,
|
|
337
|
-
nodeLabel,
|
|
338
|
-
logLine,
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
const prettified = await format(finalFile, {
|
|
342
|
-
...prettierConfig,
|
|
343
|
-
filepath: 'test.tsx',
|
|
344
|
-
plugins: [],
|
|
345
|
-
endOfLine: 'lf',
|
|
303
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
304
|
+
input: finalFile,
|
|
305
|
+
prettierConfigOverride,
|
|
346
306
|
});
|
|
347
307
|
return {
|
|
348
|
-
output
|
|
349
|
-
formatted
|
|
308
|
+
output,
|
|
309
|
+
formatted,
|
|
350
310
|
nodeLabel,
|
|
351
311
|
logLine,
|
|
352
312
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SequenceNodePath } from '@remotion/studio-shared';
|
|
2
|
+
export declare const duplicateJsxElementAtPath: (jsxPath: import("ast-types/lib/node-path").NodePath<N, V>) => void;
|
|
3
|
+
export declare const duplicateJsxNode: ({ input, nodePath, prettierConfigOverride, }: {
|
|
4
|
+
input: string;
|
|
5
|
+
nodePath: SequenceNodePath;
|
|
6
|
+
prettierConfigOverride?: Record<string, unknown> | null | undefined;
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
output: string;
|
|
9
|
+
formatted: boolean;
|
|
10
|
+
nodeLabel: string;
|
|
11
|
+
logLine: number;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,311 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.duplicateJsxNode = exports.duplicateJsxElementAtPath = void 0;
|
|
37
|
+
const types_1 = require("@babel/types");
|
|
38
|
+
const recast = __importStar(require("recast"));
|
|
39
|
+
const delete_jsx_node_1 = require("./delete-jsx-node");
|
|
40
|
+
const format_file_content_1 = require("./format-file-content");
|
|
41
|
+
const parse_ast_1 = require("./parse-ast");
|
|
42
|
+
const { namedTypes } = recast.types;
|
|
43
|
+
const makeFragment = (first, second) => ({
|
|
44
|
+
type: 'JSXFragment',
|
|
45
|
+
openingFragment: { type: 'JSXOpeningFragment' },
|
|
46
|
+
closingFragment: { type: 'JSXClosingFragment' },
|
|
47
|
+
children: [first, second],
|
|
48
|
+
});
|
|
49
|
+
const uniquifyNamePropOnClone = (clone) => {
|
|
50
|
+
for (const attr of clone.openingElement.attributes) {
|
|
51
|
+
if (attr.type !== 'JSXAttribute' || attr.name.type !== 'JSXIdentifier') {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (attr.name.name !== 'name') {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (!attr.value) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (attr.value.type === 'StringLiteral') {
|
|
61
|
+
attr.value.value = `${attr.value.value}-copy`;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (attr.value.type === 'JSXExpressionContainer' &&
|
|
65
|
+
attr.value.expression.type === 'StringLiteral') {
|
|
66
|
+
attr.value.expression.value = `${attr.value.expression.value}-copy`;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const duplicateInLogicalExpression = (parent, node, clone) => {
|
|
72
|
+
const frag = makeFragment(node, clone);
|
|
73
|
+
if (parent.left === node) {
|
|
74
|
+
parent.left = frag;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (parent.right === node) {
|
|
78
|
+
parent.right = frag;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
};
|
|
83
|
+
const duplicateInConditionalExpression = (parent, node, clone) => {
|
|
84
|
+
const frag = makeFragment(node, clone);
|
|
85
|
+
if (parent.consequent === node) {
|
|
86
|
+
parent.consequent = frag;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (parent.alternate === node) {
|
|
90
|
+
parent.alternate = frag;
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
};
|
|
95
|
+
const duplicateInArrowFunctionExpression = (parent, node, clone) => {
|
|
96
|
+
const frag = makeFragment(node, clone);
|
|
97
|
+
if (parent.body === node) {
|
|
98
|
+
parent.body = frag;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
};
|
|
103
|
+
const duplicateInReturnStatement = (parent, node, clone) => {
|
|
104
|
+
const frag = makeFragment(node, clone);
|
|
105
|
+
if (parent.argument === node) {
|
|
106
|
+
parent.argument = frag;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
const duplicateInCallExpression = (parent, node, clone) => {
|
|
112
|
+
const idx = parent.arguments.indexOf(node);
|
|
113
|
+
if (idx !== -1) {
|
|
114
|
+
parent.arguments.splice(idx + 1, 0, clone);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
};
|
|
119
|
+
const duplicateInOptionalCallExpression = (parent, node, clone) => {
|
|
120
|
+
const idx = parent.arguments.indexOf(node);
|
|
121
|
+
if (idx !== -1) {
|
|
122
|
+
parent.arguments.splice(idx + 1, 0, clone);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
};
|
|
127
|
+
const duplicateInArrayExpression = (parent, node, clone) => {
|
|
128
|
+
const idx = parent.elements.indexOf(node);
|
|
129
|
+
if (idx !== -1) {
|
|
130
|
+
parent.elements.splice(idx + 1, 0, clone);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
};
|
|
135
|
+
const duplicateInAssignmentExpression = (parent, node, clone) => {
|
|
136
|
+
const frag = makeFragment(node, clone);
|
|
137
|
+
if (parent.right === node) {
|
|
138
|
+
parent.right = frag;
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
143
|
+
const duplicateInVariableDeclarator = (parent, node, clone) => {
|
|
144
|
+
const frag = makeFragment(node, clone);
|
|
145
|
+
if (parent.init === node) {
|
|
146
|
+
parent.init = frag;
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
};
|
|
151
|
+
const duplicateInExportDefaultDeclaration = (parent, node, clone) => {
|
|
152
|
+
const frag = makeFragment(node, clone);
|
|
153
|
+
if (parent.declaration === node) {
|
|
154
|
+
parent.declaration =
|
|
155
|
+
frag;
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
};
|
|
160
|
+
const duplicateInSequenceExpression = (parent, node, clone) => {
|
|
161
|
+
const idx = parent.expressions.indexOf(node);
|
|
162
|
+
if (idx !== -1) {
|
|
163
|
+
parent.expressions.splice(idx + 1, 0, clone);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
};
|
|
168
|
+
const duplicateInNewExpression = (parent, node, clone) => {
|
|
169
|
+
const idx = parent.arguments.indexOf(node);
|
|
170
|
+
if (idx !== -1) {
|
|
171
|
+
parent.arguments.splice(idx + 1, 0, clone);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
};
|
|
176
|
+
const duplicateInExpressionStatement = (parent, node, clone) => {
|
|
177
|
+
const frag = makeFragment(node, clone);
|
|
178
|
+
if (parent.expression === node) {
|
|
179
|
+
parent.expression = frag;
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
};
|
|
184
|
+
const duplicateInParenthesizedExpression = (parent, node, clone) => {
|
|
185
|
+
const frag = makeFragment(node, clone);
|
|
186
|
+
if (parent.expression === node) {
|
|
187
|
+
parent.expression = frag;
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
};
|
|
192
|
+
const duplicateInJSXExpressionContainer = (parent, node, clone) => {
|
|
193
|
+
const frag = makeFragment(node, clone);
|
|
194
|
+
if (parent.expression === node) {
|
|
195
|
+
parent.expression = frag;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
};
|
|
200
|
+
const duplicateInTSAsExpression = (parent, node, clone) => {
|
|
201
|
+
const frag = makeFragment(node, clone);
|
|
202
|
+
if (parent.expression === node) {
|
|
203
|
+
parent.expression = frag;
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
};
|
|
208
|
+
const duplicateInJSXParentChildren = (parent, node, clone) => {
|
|
209
|
+
const idx = parent.children.indexOf(node);
|
|
210
|
+
if (idx !== -1) {
|
|
211
|
+
parent.children.splice(idx + 1, 0, clone);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
};
|
|
216
|
+
const insertDuplicateForParent = (parentNode, node, clone) => {
|
|
217
|
+
if (namedTypes.LogicalExpression.check(parentNode)) {
|
|
218
|
+
return duplicateInLogicalExpression(parentNode, node, clone);
|
|
219
|
+
}
|
|
220
|
+
if (namedTypes.ConditionalExpression.check(parentNode)) {
|
|
221
|
+
return duplicateInConditionalExpression(parentNode, node, clone);
|
|
222
|
+
}
|
|
223
|
+
if (namedTypes.ArrowFunctionExpression.check(parentNode)) {
|
|
224
|
+
return duplicateInArrowFunctionExpression(parentNode, node, clone);
|
|
225
|
+
}
|
|
226
|
+
if (namedTypes.ReturnStatement.check(parentNode)) {
|
|
227
|
+
return duplicateInReturnStatement(parentNode, node, clone);
|
|
228
|
+
}
|
|
229
|
+
if (namedTypes.CallExpression.check(parentNode)) {
|
|
230
|
+
return duplicateInCallExpression(parentNode, node, clone);
|
|
231
|
+
}
|
|
232
|
+
if (parentNode.type === 'OptionalCallExpression') {
|
|
233
|
+
return duplicateInOptionalCallExpression(parentNode, node, clone);
|
|
234
|
+
}
|
|
235
|
+
if (namedTypes.ArrayExpression.check(parentNode)) {
|
|
236
|
+
return duplicateInArrayExpression(parentNode, node, clone);
|
|
237
|
+
}
|
|
238
|
+
if (namedTypes.AssignmentExpression.check(parentNode)) {
|
|
239
|
+
return duplicateInAssignmentExpression(parentNode, node, clone);
|
|
240
|
+
}
|
|
241
|
+
if (namedTypes.VariableDeclarator.check(parentNode)) {
|
|
242
|
+
return duplicateInVariableDeclarator(parentNode, node, clone);
|
|
243
|
+
}
|
|
244
|
+
if (namedTypes.ExportDefaultDeclaration.check(parentNode)) {
|
|
245
|
+
return duplicateInExportDefaultDeclaration(parentNode, node, clone);
|
|
246
|
+
}
|
|
247
|
+
if (namedTypes.SequenceExpression.check(parentNode)) {
|
|
248
|
+
return duplicateInSequenceExpression(parentNode, node, clone);
|
|
249
|
+
}
|
|
250
|
+
if (namedTypes.NewExpression.check(parentNode)) {
|
|
251
|
+
return duplicateInNewExpression(parentNode, node, clone);
|
|
252
|
+
}
|
|
253
|
+
if (namedTypes.ExpressionStatement.check(parentNode)) {
|
|
254
|
+
return duplicateInExpressionStatement(parentNode, node, clone);
|
|
255
|
+
}
|
|
256
|
+
if (namedTypes.ParenthesizedExpression.check(parentNode)) {
|
|
257
|
+
return duplicateInParenthesizedExpression(parentNode, node, clone);
|
|
258
|
+
}
|
|
259
|
+
if (namedTypes.JSXExpressionContainer.check(parentNode)) {
|
|
260
|
+
return duplicateInJSXExpressionContainer(parentNode, node, clone);
|
|
261
|
+
}
|
|
262
|
+
if (namedTypes.TSAsExpression.check(parentNode)) {
|
|
263
|
+
return duplicateInTSAsExpression(parentNode, node, clone);
|
|
264
|
+
}
|
|
265
|
+
if (namedTypes.JSXElement.check(parentNode)) {
|
|
266
|
+
return duplicateInJSXParentChildren(parentNode, node, clone);
|
|
267
|
+
}
|
|
268
|
+
if (namedTypes.JSXFragment.check(parentNode)) {
|
|
269
|
+
return duplicateInJSXParentChildren(parentNode, node, clone);
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
};
|
|
273
|
+
const duplicateJsxElementAtPath = (jsxPath) => {
|
|
274
|
+
const { node, parentPath } = jsxPath;
|
|
275
|
+
if (!parentPath) {
|
|
276
|
+
throw new Error('Cannot duplicate JSX element with no parent');
|
|
277
|
+
}
|
|
278
|
+
const jsxNode = node;
|
|
279
|
+
const clone = (0, types_1.cloneNode)(jsxNode, true);
|
|
280
|
+
uniquifyNamePropOnClone(clone);
|
|
281
|
+
if (insertDuplicateForParent(parentPath.node, jsxNode, clone)) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
jsxPath.replace(makeFragment(jsxNode, clone));
|
|
285
|
+
};
|
|
286
|
+
exports.duplicateJsxElementAtPath = duplicateJsxElementAtPath;
|
|
287
|
+
const duplicateJsxNode = async ({ input, nodePath, prettierConfigOverride, }) => {
|
|
288
|
+
var _a, _b;
|
|
289
|
+
var _c, _d;
|
|
290
|
+
const ast = (0, parse_ast_1.parseAst)(input);
|
|
291
|
+
const jsxPath = (0, delete_jsx_node_1.findJsxElementPathForDeletion)(ast, nodePath);
|
|
292
|
+
if (!jsxPath) {
|
|
293
|
+
throw new Error('Could not find a JSX element at the specified location to duplicate');
|
|
294
|
+
}
|
|
295
|
+
const jsxElement = jsxPath.node;
|
|
296
|
+
const nodeLabel = (0, delete_jsx_node_1.getJsxElementTagLabel)(jsxElement);
|
|
297
|
+
const logLine = (_d = (_c = (_a = jsxElement.openingElement.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _c !== void 0 ? _c : (_b = jsxElement.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : 1;
|
|
298
|
+
(0, exports.duplicateJsxElementAtPath)(jsxPath);
|
|
299
|
+
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
300
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
301
|
+
input: finalFile,
|
|
302
|
+
prettierConfigOverride,
|
|
303
|
+
});
|
|
304
|
+
return {
|
|
305
|
+
output,
|
|
306
|
+
formatted,
|
|
307
|
+
nodeLabel,
|
|
308
|
+
logLine,
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
exports.duplicateJsxNode = duplicateJsxNode;
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.formatFileContent = void 0;
|
|
37
|
+
const formatFileContent = async ({ input, prettierConfigOverride, }) => {
|
|
38
|
+
let prettier = null;
|
|
39
|
+
try {
|
|
40
|
+
prettier = await Promise.resolve().then(() => __importStar(require('prettier')));
|
|
41
|
+
}
|
|
42
|
+
catch (_a) {
|
|
43
|
+
return {
|
|
44
|
+
output: input,
|
|
45
|
+
formatted: false,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const { format, resolveConfig, resolveConfigFile } = prettier;
|
|
49
|
+
let prettierConfig;
|
|
50
|
+
if (prettierConfigOverride !== undefined) {
|
|
51
|
+
prettierConfig = prettierConfigOverride;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const configFilePath = await resolveConfigFile();
|
|
55
|
+
if (!configFilePath) {
|
|
56
|
+
return {
|
|
57
|
+
output: input,
|
|
58
|
+
formatted: false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
prettierConfig = await resolveConfig(configFilePath);
|
|
62
|
+
}
|
|
63
|
+
if (!prettierConfig) {
|
|
64
|
+
return {
|
|
65
|
+
output: input,
|
|
66
|
+
formatted: false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const prettified = await format(input, {
|
|
70
|
+
...prettierConfig,
|
|
71
|
+
filepath: 'test.tsx',
|
|
72
|
+
plugins: [],
|
|
73
|
+
endOfLine: 'lf',
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
output: prettified,
|
|
77
|
+
formatted: true,
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
exports.formatFileContent = formatFileContent;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Expression, File } from '@babel/types';
|
|
2
|
+
import type { SequenceNodePath } from '@remotion/studio-shared';
|
|
3
|
+
/**
|
|
4
|
+
* Whether the callee is a `.map(...)` member call (including optional `?.map`).
|
|
5
|
+
*/
|
|
6
|
+
export declare const isMapCallee: (callee: Expression) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* True when the JSX element at `nodePath` is defined inside a `.map()` callback
|
|
9
|
+
* (array iteration). Used to flag duplicate / edit behavior for list-driven JSX.
|
|
10
|
+
*/
|
|
11
|
+
export declare const isJsxUnderMapCallback: (ast: File, nodePath: SequenceNodePath) => boolean;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isJsxUnderMapCallback = exports.isMapCallee = void 0;
|
|
4
|
+
const delete_jsx_node_1 = require("./delete-jsx-node");
|
|
5
|
+
const unwrapExpression = (expr) => {
|
|
6
|
+
if (expr.type === 'TSAsExpression') {
|
|
7
|
+
return unwrapExpression(expr.expression);
|
|
8
|
+
}
|
|
9
|
+
if (expr.type === 'ParenthesizedExpression') {
|
|
10
|
+
return unwrapExpression(expr.expression);
|
|
11
|
+
}
|
|
12
|
+
return expr;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Whether the callee is a `.map(...)` member call (including optional `?.map`).
|
|
16
|
+
*/
|
|
17
|
+
const isMapCallee = (callee) => {
|
|
18
|
+
const c = unwrapExpression(callee);
|
|
19
|
+
if (c.type === 'MemberExpression') {
|
|
20
|
+
if (c.computed) {
|
|
21
|
+
return c.property.type === 'StringLiteral' && c.property.value === 'map';
|
|
22
|
+
}
|
|
23
|
+
return c.property.type === 'Identifier' && c.property.name === 'map';
|
|
24
|
+
}
|
|
25
|
+
if (c.type === 'OptionalMemberExpression') {
|
|
26
|
+
if (c.computed) {
|
|
27
|
+
return c.property.type === 'StringLiteral' && c.property.value === 'map';
|
|
28
|
+
}
|
|
29
|
+
return c.property.type === 'Identifier' && c.property.name === 'map';
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
};
|
|
33
|
+
exports.isMapCallee = isMapCallee;
|
|
34
|
+
/**
|
|
35
|
+
* True when the JSX element at `nodePath` is defined inside a `.map()` callback
|
|
36
|
+
* (array iteration). Used to flag duplicate / edit behavior for list-driven JSX.
|
|
37
|
+
*/
|
|
38
|
+
const isJsxUnderMapCallback = (ast, nodePath) => {
|
|
39
|
+
const jsxPath = (0, delete_jsx_node_1.findJsxElementPathForDeletion)(ast, nodePath);
|
|
40
|
+
if (!jsxPath) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
let path = jsxPath.parentPath;
|
|
44
|
+
while (path) {
|
|
45
|
+
const n = path.node;
|
|
46
|
+
if (n.type === 'ArrowFunctionExpression' ||
|
|
47
|
+
n.type === 'FunctionExpression') {
|
|
48
|
+
const outer = path.parentPath;
|
|
49
|
+
if ((outer === null || outer === void 0 ? void 0 : outer.node.type) === 'CallExpression') {
|
|
50
|
+
const call = outer.node;
|
|
51
|
+
if ((0, exports.isMapCallee)(call.callee) &&
|
|
52
|
+
call.arguments.some((arg) => arg === n)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if ((outer === null || outer === void 0 ? void 0 : outer.node.type) === 'OptionalCallExpression') {
|
|
57
|
+
const call = outer.node;
|
|
58
|
+
if ((0, exports.isMapCallee)(call.callee) &&
|
|
59
|
+
call.arguments.some((arg) => arg === n)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
path = path.parentPath;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
exports.isJsxUnderMapCallback = isJsxUnderMapCallback;
|
|
@@ -216,6 +216,7 @@ const getCompositionDefaultPropsLine = ({ input, compositionId, }) => {
|
|
|
216
216
|
}
|
|
217
217
|
found = true;
|
|
218
218
|
line = (_e = (_d = (_b = openingElement.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : (_c = path.node.loc) === null || _c === void 0 ? void 0 : _c.start.line) !== null && _e !== void 0 ? _e : 1;
|
|
219
|
+
this.traverse(path);
|
|
219
220
|
},
|
|
220
221
|
});
|
|
221
222
|
return line;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.updateSequenceProps = void 0;
|
|
37
37
|
const recast = __importStar(require("recast"));
|
|
38
38
|
const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
|
|
39
|
+
const format_file_content_1 = require("./format-file-content");
|
|
39
40
|
const parse_ast_1 = require("./parse-ast");
|
|
40
41
|
const update_nested_prop_1 = require("./update-nested-prop");
|
|
41
42
|
const b = recast.types.builders;
|
|
@@ -114,53 +115,14 @@ const updateSequenceProps = async ({ input, nodePath, key, value, defaultValue,
|
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
const finalFile = (0, parse_ast_1.serializeAst)(ast);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
catch (_e) {
|
|
122
|
-
return {
|
|
123
|
-
output: finalFile,
|
|
124
|
-
oldValueString,
|
|
125
|
-
formatted: false,
|
|
126
|
-
logLine,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
const { format, resolveConfig, resolveConfigFile } = prettier;
|
|
130
|
-
let prettierConfig;
|
|
131
|
-
if (prettierConfigOverride !== undefined) {
|
|
132
|
-
prettierConfig = prettierConfigOverride;
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
const configFilePath = await resolveConfigFile();
|
|
136
|
-
if (!configFilePath) {
|
|
137
|
-
return {
|
|
138
|
-
output: finalFile,
|
|
139
|
-
oldValueString,
|
|
140
|
-
formatted: false,
|
|
141
|
-
logLine,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
prettierConfig = await resolveConfig(configFilePath);
|
|
145
|
-
}
|
|
146
|
-
if (!prettierConfig) {
|
|
147
|
-
return {
|
|
148
|
-
output: finalFile,
|
|
149
|
-
oldValueString,
|
|
150
|
-
formatted: false,
|
|
151
|
-
logLine,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
const prettified = await format(finalFile, {
|
|
155
|
-
...prettierConfig,
|
|
156
|
-
filepath: 'test.tsx',
|
|
157
|
-
plugins: [],
|
|
158
|
-
endOfLine: 'lf',
|
|
118
|
+
const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
|
|
119
|
+
input: finalFile,
|
|
120
|
+
prettierConfigOverride,
|
|
159
121
|
});
|
|
160
122
|
return {
|
|
161
|
-
output
|
|
123
|
+
output,
|
|
162
124
|
oldValueString,
|
|
163
|
-
formatted
|
|
125
|
+
formatted,
|
|
164
126
|
logLine,
|
|
165
127
|
};
|
|
166
128
|
};
|
package/dist/file-watcher.d.ts
CHANGED
|
@@ -12,6 +12,13 @@ export type FileWatcherRegistry = {
|
|
|
12
12
|
installFileWatcher: (options: {
|
|
13
13
|
file: string;
|
|
14
14
|
onChange: OnChange;
|
|
15
|
+
/**
|
|
16
|
+
* When true, only created/deleted events are emitted (no reads on change).
|
|
17
|
+
* Use for binary or very large files (e.g. render output) where subscribers
|
|
18
|
+
* only need to know whether the path exists.
|
|
19
|
+
* Pass false when subscribers need content (including `changed` events).
|
|
20
|
+
*/
|
|
21
|
+
existenceOnly: boolean;
|
|
15
22
|
}) => {
|
|
16
23
|
exists: boolean;
|
|
17
24
|
unwatch: () => void;
|
package/dist/file-watcher.js
CHANGED
|
@@ -35,10 +35,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.writeFileAndNotifyFileWatchers = exports.installFileWatcher = exports.getFileWatcherRegistry = exports.setFileWatcherRegistry = exports.createFileWatcherRegistry = void 0;
|
|
37
37
|
const node_fs_1 = __importStar(require("node:fs"));
|
|
38
|
+
const getRegistryKey = (file, existenceOnly) => existenceOnly ? `${file}\0existence-only` : file;
|
|
38
39
|
const createFileWatcherRegistry = () => {
|
|
39
40
|
const sharedWatchers = new Map();
|
|
40
|
-
const _installFileWatcher = ({ file, onChange, }) => {
|
|
41
|
-
const
|
|
41
|
+
const _installFileWatcher = ({ file, onChange, existenceOnly, }) => {
|
|
42
|
+
const registryKey = getRegistryKey(file, existenceOnly);
|
|
43
|
+
const existing = sharedWatchers.get(registryKey);
|
|
42
44
|
if (existing) {
|
|
43
45
|
existing.subscribers.add(onChange);
|
|
44
46
|
return {
|
|
@@ -47,7 +49,7 @@ const createFileWatcherRegistry = () => {
|
|
|
47
49
|
existing.subscribers.delete(onChange);
|
|
48
50
|
if (existing.subscribers.size === 0) {
|
|
49
51
|
existing.unwatch();
|
|
50
|
-
sharedWatchers.delete(
|
|
52
|
+
sharedWatchers.delete(registryKey);
|
|
51
53
|
}
|
|
52
54
|
},
|
|
53
55
|
};
|
|
@@ -64,7 +66,17 @@ const createFileWatcherRegistry = () => {
|
|
|
64
66
|
const listener = () => {
|
|
65
67
|
const existsNow = node_fs_1.default.existsSync(file);
|
|
66
68
|
let event = null;
|
|
67
|
-
if (
|
|
69
|
+
if (existenceOnly) {
|
|
70
|
+
if (!shared.existedBefore && existsNow) {
|
|
71
|
+
shared.existedBefore = true;
|
|
72
|
+
event = { type: 'created', content: '' };
|
|
73
|
+
}
|
|
74
|
+
else if (shared.existedBefore && !existsNow) {
|
|
75
|
+
shared.existedBefore = false;
|
|
76
|
+
event = { type: 'deleted' };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (!shared.existedBefore && existsNow) {
|
|
68
80
|
const content = (0, node_fs_1.readFileSync)(file, 'utf-8');
|
|
69
81
|
shared.existedBefore = true;
|
|
70
82
|
shared.lastKnownContent = content;
|
|
@@ -95,21 +107,21 @@ const createFileWatcherRegistry = () => {
|
|
|
95
107
|
}
|
|
96
108
|
};
|
|
97
109
|
node_fs_1.default.watchFile(file, { interval: 100 }, listener);
|
|
98
|
-
sharedWatchers.set(
|
|
110
|
+
sharedWatchers.set(registryKey, shared);
|
|
99
111
|
return {
|
|
100
112
|
exists: existedAtBeginning,
|
|
101
113
|
unwatch: () => {
|
|
102
114
|
shared.subscribers.delete(onChange);
|
|
103
115
|
if (shared.subscribers.size === 0) {
|
|
104
116
|
shared.unwatch();
|
|
105
|
-
sharedWatchers.delete(
|
|
117
|
+
sharedWatchers.delete(registryKey);
|
|
106
118
|
}
|
|
107
119
|
},
|
|
108
120
|
};
|
|
109
121
|
};
|
|
110
122
|
const _writeFileAndNotifyFileWatchers = (file, content) => {
|
|
111
123
|
(0, node_fs_1.writeFileSync)(file, content);
|
|
112
|
-
const shared = sharedWatchers.get(file);
|
|
124
|
+
const shared = sharedWatchers.get(getRegistryKey(file, false));
|
|
113
125
|
if (!shared) {
|
|
114
126
|
return;
|
|
115
127
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAstNodePath = void 0;
|
|
37
|
+
const recast = __importStar(require("recast"));
|
|
38
|
+
const getAstNodePath = (ast, nodePath) => {
|
|
39
|
+
let current = new recast.types.NodePath(ast);
|
|
40
|
+
for (const segment of nodePath) {
|
|
41
|
+
current = current.get(segment);
|
|
42
|
+
if (current.value === null || current.value === undefined) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return current;
|
|
47
|
+
};
|
|
48
|
+
exports.getAstNodePath = getAstNodePath;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ const apply_visual_control_change_1 = require("./routes/apply-visual-control-cha
|
|
|
7
7
|
const cancel_render_1 = require("./routes/cancel-render");
|
|
8
8
|
const delete_jsx_node_1 = require("./routes/delete-jsx-node");
|
|
9
9
|
const delete_static_file_1 = require("./routes/delete-static-file");
|
|
10
|
+
const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
|
|
10
11
|
const install_dependency_1 = require("./routes/install-dependency");
|
|
11
12
|
const open_in_file_explorer_1 = require("./routes/open-in-file-explorer");
|
|
12
13
|
const project_info_1 = require("./routes/project-info");
|
|
@@ -39,6 +40,7 @@ exports.allApiRoutes = {
|
|
|
39
40
|
'/api/unsubscribe-from-sequence-props': unsubscribe_from_sequence_props_1.unsubscribeFromSequenceProps,
|
|
40
41
|
'/api/save-sequence-props': save_sequence_props_1.saveSequencePropsHandler,
|
|
41
42
|
'/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
|
|
43
|
+
'/api/duplicate-jsx-node': duplicate_jsx_node_1.duplicateJsxNodeHandler,
|
|
42
44
|
'/api/update-available': update_available_1.handleUpdate,
|
|
43
45
|
'/api/project-info': project_info_1.projectInfoHandler,
|
|
44
46
|
'/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
|
|
@@ -12,6 +12,7 @@ const subscribeToFileExistenceWatchers = ({ file: relativeFile, remotionRoot, cl
|
|
|
12
12
|
const file = node_path_1.default.resolve(remotionRoot, relativeFile);
|
|
13
13
|
const { unwatch, exists } = (0, file_watcher_1.installFileWatcher)({
|
|
14
14
|
file,
|
|
15
|
+
existenceOnly: true,
|
|
15
16
|
onChange: (event) => {
|
|
16
17
|
if (event.type === 'created') {
|
|
17
18
|
(0, live_events_1.waitForLiveEventsListener)().then((listener) => {
|
|
@@ -0,0 +1,43 @@
|
|
|
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.getStaticFileFallbackHint = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const getStaticFileFallbackHint = ({ method, pathname, publicDir, }) => {
|
|
10
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
let normalizedPathname;
|
|
14
|
+
try {
|
|
15
|
+
normalizedPathname = decodeURIComponent(pathname);
|
|
16
|
+
}
|
|
17
|
+
catch (_a) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (normalizedPathname === '/' || !node_path_1.default.extname(normalizedPathname)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const relativePath = normalizedPathname.replace(/^\/+/, '');
|
|
24
|
+
if (!relativePath) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const resolvedPublicDir = node_path_1.default.resolve(publicDir);
|
|
28
|
+
const filePath = node_path_1.default.resolve(publicDir, relativePath);
|
|
29
|
+
const relativeToPublicDir = node_path_1.default.relative(resolvedPublicDir, filePath);
|
|
30
|
+
try {
|
|
31
|
+
if (relativeToPublicDir.startsWith('..') ||
|
|
32
|
+
node_path_1.default.isAbsolute(relativeToPublicDir) ||
|
|
33
|
+
!(0, node_fs_1.existsSync)(filePath) ||
|
|
34
|
+
(0, node_fs_1.statSync)(filePath).isDirectory()) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (_b) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return relativePath;
|
|
42
|
+
};
|
|
43
|
+
exports.getStaticFileFallbackHint = getStaticFileFallbackHint;
|
|
@@ -40,7 +40,9 @@ exports.computeSequencePropsStatusByLine = exports.computeSequencePropsStatus =
|
|
|
40
40
|
const node_fs_1 = require("node:fs");
|
|
41
41
|
const node_path_1 = __importDefault(require("node:path"));
|
|
42
42
|
const recast = __importStar(require("recast"));
|
|
43
|
+
const jsx_sequence_context_1 = require("../../codemods/jsx-sequence-context");
|
|
43
44
|
const parse_ast_1 = require("../../codemods/parse-ast");
|
|
45
|
+
const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
|
|
44
46
|
const isStaticValue = (node) => {
|
|
45
47
|
switch (node.type) {
|
|
46
48
|
case 'NumericLiteral':
|
|
@@ -172,12 +174,9 @@ recastPath) => {
|
|
|
172
174
|
return segments;
|
|
173
175
|
};
|
|
174
176
|
const findJsxElementAtNodePath = (ast, nodePath) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (current.value === null || current.value === undefined) {
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
177
|
+
const current = (0, get_ast_node_path_1.getAstNodePath)(ast, nodePath);
|
|
178
|
+
if (!current) {
|
|
179
|
+
return null;
|
|
181
180
|
}
|
|
182
181
|
if (recast.types.namedTypes.JSXOpeningElement.check(current.value)) {
|
|
183
182
|
return current.value;
|
|
@@ -273,6 +272,7 @@ const computeSequencePropsStatusFromContent = (fileContents, nodePath, keys) =>
|
|
|
273
272
|
canUpdate: true,
|
|
274
273
|
props: filteredProps,
|
|
275
274
|
nodePath,
|
|
275
|
+
jsxInMapCallback: (0, jsx_sequence_context_1.isJsxUnderMapCallback)(ast, nodePath),
|
|
276
276
|
};
|
|
277
277
|
};
|
|
278
278
|
exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
|
|
@@ -0,0 +1,66 @@
|
|
|
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.duplicateJsxNodeHandler = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const renderer_1 = require("@remotion/renderer");
|
|
10
|
+
const duplicate_jsx_node_1 = require("../../codemods/duplicate-jsx-node");
|
|
11
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
12
|
+
const format_log_file_location_1 = require("../format-log-file-location");
|
|
13
|
+
const undo_stack_1 = require("../undo-stack");
|
|
14
|
+
const log_update_1 = require("./log-update");
|
|
15
|
+
const duplicateJsxNodeHandler = async ({ input: { fileName, nodePath }, remotionRoot, logLevel }) => {
|
|
16
|
+
try {
|
|
17
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[duplicate-jsx-node] Received request for fileName="${fileName}"`);
|
|
18
|
+
const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
|
|
19
|
+
const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
|
|
20
|
+
if (fileRelativeToRoot.startsWith('..')) {
|
|
21
|
+
throw new Error('Cannot modify a file outside the project');
|
|
22
|
+
}
|
|
23
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
24
|
+
const { output, formatted, nodeLabel, logLine } = await (0, duplicate_jsx_node_1.duplicateJsxNode)({
|
|
25
|
+
input: fileContents,
|
|
26
|
+
nodePath,
|
|
27
|
+
});
|
|
28
|
+
(0, undo_stack_1.pushToUndoStack)({
|
|
29
|
+
filePath: absolutePath,
|
|
30
|
+
oldContents: fileContents,
|
|
31
|
+
logLevel,
|
|
32
|
+
remotionRoot,
|
|
33
|
+
logLine,
|
|
34
|
+
description: {
|
|
35
|
+
undoMessage: `Undid duplication of ${nodeLabel}`,
|
|
36
|
+
redoMessage: `Redid duplication of ${nodeLabel}`,
|
|
37
|
+
},
|
|
38
|
+
entryType: 'duplicate-jsx-node',
|
|
39
|
+
suppressHmrOnFileRestore: false,
|
|
40
|
+
});
|
|
41
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
|
|
42
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
|
|
43
|
+
const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
|
|
44
|
+
remotionRoot,
|
|
45
|
+
absolutePath,
|
|
46
|
+
line: logLine,
|
|
47
|
+
});
|
|
48
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}:`)} Duplicated ${nodeLabel}`);
|
|
49
|
+
if (!formatted) {
|
|
50
|
+
(0, log_update_1.warnAboutPrettierOnce)(logLevel);
|
|
51
|
+
}
|
|
52
|
+
renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[duplicate-jsx-node] Wrote ${fileRelativeToRoot}${formatted ? ' (formatted)' : ''}`);
|
|
53
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
reason: err.message,
|
|
62
|
+
stack: err.stack,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
exports.duplicateJsxNodeHandler = duplicateJsxNodeHandler;
|
|
@@ -61,6 +61,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, remoti
|
|
|
61
61
|
}
|
|
62
62
|
const { unwatch } = (0, file_watcher_1.installFileWatcher)({
|
|
63
63
|
file: absolutePath,
|
|
64
|
+
existenceOnly: false,
|
|
64
65
|
onChange: (event) => {
|
|
65
66
|
if (event.type === 'deleted') {
|
|
66
67
|
return;
|
|
@@ -3,7 +3,7 @@ export interface UndoEntryDescription {
|
|
|
3
3
|
undoMessage: string;
|
|
4
4
|
redoMessage: string;
|
|
5
5
|
}
|
|
6
|
-
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'delete-jsx-node';
|
|
6
|
+
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'delete-jsx-node' | 'duplicate-jsx-node';
|
|
7
7
|
type UndoEntry = {
|
|
8
8
|
filePath: string;
|
|
9
9
|
oldContents: string;
|
|
@@ -20,6 +20,8 @@ type UndoEntry = {
|
|
|
20
20
|
entryType: 'sequence-props';
|
|
21
21
|
} | {
|
|
22
22
|
entryType: 'delete-jsx-node';
|
|
23
|
+
} | {
|
|
24
|
+
entryType: 'duplicate-jsx-node';
|
|
23
25
|
});
|
|
24
26
|
export declare function pushToUndoStack({ filePath, oldContents, logLevel, remotionRoot, logLine, description, entryType, suppressHmrOnFileRestore }: {
|
|
25
27
|
filePath: string;
|
|
@@ -87,6 +87,7 @@ function ensureWatching(filePath) {
|
|
|
87
87
|
}
|
|
88
88
|
const watcher = (0, file_watcher_1.installFileWatcher)({
|
|
89
89
|
file: filePath,
|
|
90
|
+
existenceOnly: false,
|
|
90
91
|
onChange: () => {
|
|
91
92
|
var _a;
|
|
92
93
|
const count = (_a = suppressedWrites.get(filePath)) !== null && _a !== void 0 ? _a : 0;
|
package/dist/routes.js
CHANGED
|
@@ -39,6 +39,7 @@ const node_fs_1 = require("node:fs");
|
|
|
39
39
|
const node_path_1 = __importStar(require("node:path"));
|
|
40
40
|
const node_url_1 = require("node:url");
|
|
41
41
|
const bundler_1 = require("@remotion/bundler");
|
|
42
|
+
const renderer_1 = require("@remotion/renderer");
|
|
42
43
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
43
44
|
const client_render_queue_1 = require("./client-render-queue");
|
|
44
45
|
const get_file_source_1 = require("./helpers/get-file-source");
|
|
@@ -47,11 +48,13 @@ const open_in_editor_1 = require("./helpers/open-in-editor");
|
|
|
47
48
|
const resolve_output_path_1 = require("./helpers/resolve-output-path");
|
|
48
49
|
const api_routes_1 = require("./preview-server/api-routes");
|
|
49
50
|
const get_package_manager_1 = require("./preview-server/get-package-manager");
|
|
51
|
+
const get_static_file_fallback_hint_1 = require("./preview-server/get-static-file-fallback-hint");
|
|
50
52
|
const handler_1 = require("./preview-server/handler");
|
|
51
53
|
const parse_body_1 = require("./preview-server/parse-body");
|
|
52
54
|
const public_folder_1 = require("./preview-server/public-folder");
|
|
53
55
|
const serve_static_1 = require("./preview-server/serve-static");
|
|
54
56
|
const editorGuess = (0, open_in_editor_1.guessEditor)();
|
|
57
|
+
const loggedStaticFileHints = new Set();
|
|
55
58
|
const static404 = (response) => {
|
|
56
59
|
response.writeHead(404);
|
|
57
60
|
response.end('The static/ prefix has been changed, this URL is no longer valid.');
|
|
@@ -75,7 +78,24 @@ const handleRemotionConfig = (response, remotionRoot) => {
|
|
|
75
78
|
response.end(JSON.stringify(body));
|
|
76
79
|
return Promise.resolve();
|
|
77
80
|
};
|
|
78
|
-
const handleFallback = async ({ remotionRoot, hash, response, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, numberOfAudioTags, audioLatencyHint, gitSource, logLevel, enableCrossSiteIsolation, }) => {
|
|
81
|
+
const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, numberOfAudioTags, audioLatencyHint, gitSource, logLevel, enableCrossSiteIsolation, }) => {
|
|
82
|
+
const requestUrl = new URL(request.url, 'http://localhost');
|
|
83
|
+
const { pathname } = requestUrl;
|
|
84
|
+
const staticFileHint = (0, get_static_file_fallback_hint_1.getStaticFileFallbackHint)({
|
|
85
|
+
method: request.method,
|
|
86
|
+
pathname,
|
|
87
|
+
publicDir,
|
|
88
|
+
});
|
|
89
|
+
if (staticFileHint &&
|
|
90
|
+
pathname.includes('.') &&
|
|
91
|
+
!loggedStaticFileHints.has(staticFileHint)) {
|
|
92
|
+
loggedStaticFileHints.add(staticFileHint);
|
|
93
|
+
renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, [
|
|
94
|
+
`"${pathname}" was requested but not found.`,
|
|
95
|
+
'To import assets from the public/ folder, you must wrap them in staticFile(): https://www.remotion.dev/docs/assets',
|
|
96
|
+
`Change \`"${pathname}"\` to \`staticFile("${pathname}")\` to fix the error.`,
|
|
97
|
+
].join('\n'));
|
|
98
|
+
}
|
|
79
99
|
const [edit] = await editorGuess;
|
|
80
100
|
const displayName = (0, open_in_editor_1.getDisplayNameForEditor)(edit ? edit.command : null);
|
|
81
101
|
response.setHeader('content-type', 'text/html');
|
|
@@ -406,6 +426,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
|
|
|
406
426
|
remotionRoot,
|
|
407
427
|
hash: staticHash,
|
|
408
428
|
response,
|
|
429
|
+
request,
|
|
409
430
|
getCurrentInputProps,
|
|
410
431
|
getEnvVariables,
|
|
411
432
|
publicDir,
|
package/dist/watch-root-file.js
CHANGED
|
@@ -11,6 +11,7 @@ const watchRootFile = async (remotionRoot, entryPoint) => {
|
|
|
11
11
|
}
|
|
12
12
|
(0, file_watcher_1.installFileWatcher)({
|
|
13
13
|
file: rootFile.rootFile,
|
|
14
|
+
existenceOnly: false,
|
|
14
15
|
onChange: () => {
|
|
15
16
|
// Don't care if changed, added or deleted - should trigger a refetch in the frontend all the time
|
|
16
17
|
(0, live_events_1.waitForLiveEventsListener)().then((listener) => {
|
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.446",
|
|
7
7
|
"description": "Run a Remotion Studio with a server backend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"sideEffects": false,
|
|
@@ -24,14 +24,15 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@babel/types": "7.24.0",
|
|
27
28
|
"@babel/parser": "7.24.1",
|
|
28
29
|
"semver": "7.5.3",
|
|
29
30
|
"prettier": "3.8.1",
|
|
30
|
-
"remotion": "4.0.
|
|
31
|
+
"remotion": "4.0.446",
|
|
31
32
|
"recast": "0.23.11",
|
|
32
|
-
"@remotion/bundler": "4.0.
|
|
33
|
-
"@remotion/renderer": "4.0.
|
|
34
|
-
"@remotion/studio-shared": "4.0.
|
|
33
|
+
"@remotion/bundler": "4.0.446",
|
|
34
|
+
"@remotion/renderer": "4.0.446",
|
|
35
|
+
"@remotion/studio-shared": "4.0.446",
|
|
35
36
|
"memfs": "3.4.3",
|
|
36
37
|
"source-map": "0.7.3",
|
|
37
38
|
"open": "^8.4.2"
|
|
@@ -39,9 +40,8 @@
|
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"ast-types": "0.16.1",
|
|
41
42
|
"react": "19.2.3",
|
|
42
|
-
"@babel/types": "7.24.0",
|
|
43
43
|
"@types/semver": "^7.3.4",
|
|
44
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
44
|
+
"@remotion/eslint-config-internal": "4.0.446",
|
|
45
45
|
"eslint": "9.19.0",
|
|
46
46
|
"@types/node": "20.12.14",
|
|
47
47
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|