@remotion/studio-server 4.0.431 → 4.0.433

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.
@@ -0,0 +1,11 @@
1
+ import type { JSXOpeningElement } from '@babel/types';
2
+ import type { ExpressionKind } from 'ast-types/lib/gen/kinds';
3
+ export declare const parseValueExpression: (value: unknown) => ExpressionKind;
4
+ export declare const updateNestedProp: ({ node, parentKey, childKey, value, defaultValue, isDefault, }: {
5
+ node: JSXOpeningElement;
6
+ parentKey: string;
7
+ childKey: string;
8
+ value: unknown;
9
+ defaultValue: unknown;
10
+ isDefault: boolean;
11
+ }) => string;
@@ -0,0 +1,156 @@
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.updateNestedProp = exports.parseValueExpression = void 0;
37
+ const studio_shared_1 = require("@remotion/studio-shared");
38
+ const recast = __importStar(require("recast"));
39
+ const parse_ast_1 = require("./parse-ast");
40
+ const b = recast.types.builders;
41
+ const parseValueExpression = (value) => {
42
+ return (0, parse_ast_1.parseAst)(`a = ${(0, studio_shared_1.stringifyDefaultProps)({ props: value, enumPaths: [] })}`)
43
+ .program.body[0].expression.right;
44
+ };
45
+ exports.parseValueExpression = parseValueExpression;
46
+ const findJsxAttribute = (attributes, name) => {
47
+ const attrIndex = attributes.findIndex((a) => {
48
+ if (a.type === 'JSXSpreadAttribute') {
49
+ return false;
50
+ }
51
+ if (a.name.type === 'JSXNamespacedName') {
52
+ return false;
53
+ }
54
+ return a.name.name === name;
55
+ });
56
+ const found = attrIndex !== -1 ? attributes[attrIndex] : undefined;
57
+ return {
58
+ attrIndex,
59
+ attr: found && found.type === 'JSXAttribute'
60
+ ? found
61
+ : undefined,
62
+ };
63
+ };
64
+ const findObjectProperty = (objExpr, propertyName) => {
65
+ const propIndex = objExpr.properties.findIndex((p) => p.type === 'ObjectProperty' &&
66
+ ((p.key.type === 'Identifier' &&
67
+ p.key.name === propertyName) ||
68
+ (p.key.type === 'StringLiteral' &&
69
+ p.key.value === propertyName)));
70
+ return {
71
+ propIndex,
72
+ prop: propIndex !== -1
73
+ ? objExpr.properties[propIndex]
74
+ : undefined,
75
+ };
76
+ };
77
+ const getObjectExpression = (attr) => {
78
+ const { value } = attr;
79
+ if (!value || value.type !== 'JSXExpressionContainer') {
80
+ return null;
81
+ }
82
+ const container = value;
83
+ if (container.expression.type !== 'ObjectExpression') {
84
+ return null;
85
+ }
86
+ return container.expression;
87
+ };
88
+ const getOldValueString = ({ attr, childKey, defaultValue, }) => {
89
+ if (attr) {
90
+ const objExpr = getObjectExpression(attr);
91
+ if (objExpr) {
92
+ const { prop } = findObjectProperty(objExpr, childKey);
93
+ if (prop) {
94
+ return recast.print(prop.value).code;
95
+ }
96
+ }
97
+ }
98
+ if (defaultValue !== null) {
99
+ return JSON.stringify(defaultValue);
100
+ }
101
+ return '';
102
+ };
103
+ const removeNestedProp = ({ attr, attrIndex, attributes, childKey, }) => {
104
+ if (!attr) {
105
+ return;
106
+ }
107
+ const objExpr = getObjectExpression(attr);
108
+ if (!objExpr) {
109
+ return;
110
+ }
111
+ const { propIndex } = findObjectProperty(objExpr, childKey);
112
+ if (propIndex !== -1) {
113
+ objExpr.properties.splice(propIndex, 1);
114
+ }
115
+ if (objExpr.properties.length === 0 && attrIndex !== -1) {
116
+ attributes.splice(attrIndex, 1);
117
+ }
118
+ };
119
+ const setNestedProp = ({ attr, attributes, parentKey, childKey, value, }) => {
120
+ const parsedValue = (0, exports.parseValueExpression)(value);
121
+ if (attr) {
122
+ const objExpr = getObjectExpression(attr);
123
+ if (objExpr) {
124
+ const { prop } = findObjectProperty(objExpr, childKey);
125
+ if (prop) {
126
+ prop.value = parsedValue;
127
+ }
128
+ else {
129
+ objExpr.properties.push(b.objectProperty(b.identifier(childKey), parsedValue));
130
+ }
131
+ }
132
+ }
133
+ else {
134
+ const objExpr = b.objectExpression([
135
+ b.objectProperty(b.identifier(childKey), parsedValue),
136
+ ]);
137
+ const newAttr = b.jsxAttribute(b.jsxIdentifier(parentKey), b.jsxExpressionContainer(objExpr));
138
+ attributes.push(newAttr);
139
+ }
140
+ };
141
+ const updateNestedProp = ({ node, parentKey, childKey, value, defaultValue, isDefault, }) => {
142
+ if (!node.attributes) {
143
+ node.attributes = [];
144
+ }
145
+ const { attributes } = node;
146
+ const { attrIndex, attr } = findJsxAttribute(attributes, parentKey);
147
+ const oldValueString = getOldValueString({ attr, childKey, defaultValue });
148
+ if (isDefault) {
149
+ removeNestedProp({ attr, attrIndex, attributes, childKey });
150
+ }
151
+ else {
152
+ setNestedProp({ attr, attributes, parentKey, childKey, value });
153
+ }
154
+ return oldValueString;
155
+ };
156
+ exports.updateNestedProp = updateNestedProp;
@@ -1,12 +1,13 @@
1
- import { type EnumPath } from '@remotion/studio-shared';
2
- export declare const updateSequenceProps: ({ input, targetLine, key, value, enumPaths, defaultValue, }: {
1
+ import type { SequenceNodePath } from '@remotion/studio-shared';
2
+ export declare const updateSequenceProps: ({ input, nodePath, key, value, defaultValue, prettierConfigOverride, }: {
3
3
  input: string;
4
- targetLine: number;
4
+ nodePath: SequenceNodePath;
5
5
  key: string;
6
6
  value: unknown;
7
- enumPaths: EnumPath[];
8
7
  defaultValue: unknown;
8
+ prettierConfigOverride?: Record<string, unknown> | null | undefined;
9
9
  }) => Promise<{
10
10
  output: string;
11
11
  oldValueString: string;
12
+ formatted: boolean;
12
13
  }>;
@@ -34,63 +34,73 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.updateSequenceProps = void 0;
37
- const studio_shared_1 = require("@remotion/studio-shared");
38
37
  const recast = __importStar(require("recast"));
38
+ const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
39
39
  const parse_ast_1 = require("./parse-ast");
40
- const updateSequenceProps = async ({ input, targetLine, key, value, enumPaths, defaultValue, }) => {
40
+ const update_nested_prop_1 = require("./update-nested-prop");
41
+ const b = recast.types.builders;
42
+ const updateSequenceProps = async ({ input, nodePath, key, value, defaultValue, prettierConfigOverride, }) => {
43
+ var _a, _b;
41
44
  const ast = (0, parse_ast_1.parseAst)(input);
42
- let found = false;
43
45
  let oldValueString = '';
44
46
  const isDefault = defaultValue !== null &&
45
47
  JSON.stringify(value) === JSON.stringify(defaultValue);
46
- recast.types.visit(ast, {
47
- visitJSXOpeningElement(path) {
48
- var _a, _b;
49
- const { node } = path;
50
- if (!node.loc || node.loc.start.line !== targetLine) {
51
- return this.traverse(path);
52
- }
53
- const attrIndex = (_a = node.attributes) === null || _a === void 0 ? void 0 : _a.findIndex((a) => {
54
- if (a.type === 'JSXSpreadAttribute') {
55
- return false;
56
- }
57
- if (a.name.type === 'JSXNamespacedName') {
58
- return false;
59
- }
60
- return a.name.name === key;
61
- });
62
- const attr = attrIndex !== undefined && attrIndex !== -1
63
- ? (_b = node.attributes) === null || _b === void 0 ? void 0 : _b[attrIndex]
64
- : undefined;
65
- if (attr && attr.type !== 'JSXSpreadAttribute' && attr.value) {
66
- const printed = recast.print(attr.value).code;
67
- // Strip JSX expression container braces, e.g. "{30}" -> "30"
68
- oldValueString =
69
- printed.startsWith('{') && printed.endsWith('}')
70
- ? printed.slice(1, -1)
71
- : printed;
72
- }
73
- else if (attr && attr.type !== 'JSXSpreadAttribute' && !attr.value) {
74
- // JSX shorthand like `loop` (no value) is implicitly `true`
75
- oldValueString = 'true';
48
+ const dotIndex = key.indexOf('.');
49
+ const isNested = dotIndex !== -1;
50
+ const parentKey = isNested ? key.slice(0, dotIndex) : key;
51
+ const childKey = isNested ? key.slice(dotIndex + 1) : '';
52
+ const node = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, nodePath);
53
+ if (!node) {
54
+ throw new Error('Could not find a JSX element at the specified line to update');
55
+ }
56
+ if (isNested) {
57
+ oldValueString = (0, update_nested_prop_1.updateNestedProp)({
58
+ node,
59
+ parentKey,
60
+ childKey,
61
+ value,
62
+ defaultValue,
63
+ isDefault,
64
+ });
65
+ }
66
+ else {
67
+ const attrIndex = (_a = node.attributes) === null || _a === void 0 ? void 0 : _a.findIndex((a) => {
68
+ if (a.type === 'JSXSpreadAttribute') {
69
+ return false;
76
70
  }
77
- else if (!attr && defaultValue !== null) {
78
- oldValueString = JSON.stringify(defaultValue);
71
+ if (a.name.type === 'JSXNamespacedName') {
72
+ return false;
79
73
  }
80
- if (isDefault) {
81
- if (attr && attr.type !== 'JSXSpreadAttribute' && node.attributes) {
82
- node.attributes.splice(attrIndex, 1);
83
- }
84
- found = true;
85
- return this.traverse(path);
74
+ return a.name.name === key;
75
+ });
76
+ const attr = attrIndex !== undefined && attrIndex !== -1
77
+ ? (_b = node.attributes) === null || _b === void 0 ? void 0 : _b[attrIndex]
78
+ : undefined;
79
+ if (attr && attr.type !== 'JSXSpreadAttribute' && attr.value) {
80
+ const printed = recast.print(attr.value).code;
81
+ // Strip JSX expression container braces, e.g. "{30}" -> "30"
82
+ oldValueString =
83
+ printed.startsWith('{') && printed.endsWith('}')
84
+ ? printed.slice(1, -1)
85
+ : printed;
86
+ }
87
+ else if (attr && attr.type !== 'JSXSpreadAttribute' && !attr.value) {
88
+ // JSX shorthand like `loop` (no value) is implicitly `true`
89
+ oldValueString = 'true';
90
+ }
91
+ else if (!attr && defaultValue !== null) {
92
+ oldValueString = JSON.stringify(defaultValue);
93
+ }
94
+ if (isDefault) {
95
+ if (attr && attr.type !== 'JSXSpreadAttribute' && node.attributes) {
96
+ node.attributes.splice(attrIndex, 1);
86
97
  }
87
- const parsed = (0, parse_ast_1.parseAst)(`a = ${(0, studio_shared_1.stringifyDefaultProps)({ props: value, enumPaths })}`)
88
- .program.body[0].expression.right;
89
- const newValue = value === true
90
- ? null
91
- : recast.types.builders.jsxExpressionContainer(parsed);
98
+ }
99
+ else {
100
+ const parsed = (0, update_nested_prop_1.parseValueExpression)(value);
101
+ const newValue = value === true ? null : b.jsxExpressionContainer(parsed);
92
102
  if (!attr || attr.type === 'JSXSpreadAttribute') {
93
- const newAttr = recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(key), newValue);
103
+ const newAttr = b.jsxAttribute(b.jsxIdentifier(key), newValue);
94
104
  if (!node.attributes) {
95
105
  node.attributes = [];
96
106
  }
@@ -99,36 +109,53 @@ const updateSequenceProps = async ({ input, targetLine, key, value, enumPaths, d
99
109
  else {
100
110
  attr.value = newValue;
101
111
  }
102
- found = true;
103
- return this.traverse(path);
104
- },
105
- });
106
- if (!found) {
107
- throw new Error('Could not find a JSX element at the specified line to update');
112
+ }
108
113
  }
114
+ const finalFile = (0, parse_ast_1.serializeAst)(ast);
109
115
  let prettier = null;
110
116
  try {
111
117
  prettier = await Promise.resolve().then(() => __importStar(require('prettier')));
112
118
  }
113
- catch (_a) {
114
- throw new Error('Prettier cannot be found in the current project.');
119
+ catch (_c) {
120
+ return {
121
+ output: finalFile,
122
+ oldValueString,
123
+ formatted: false,
124
+ };
115
125
  }
116
126
  const { format, resolveConfig, resolveConfigFile } = prettier;
117
- const configFilePath = await resolveConfigFile();
118
- if (!configFilePath) {
119
- throw new Error('The Prettier config file was not found');
127
+ let prettierConfig;
128
+ if (prettierConfigOverride !== undefined) {
129
+ prettierConfig = prettierConfigOverride;
130
+ }
131
+ else {
132
+ const configFilePath = await resolveConfigFile();
133
+ if (!configFilePath) {
134
+ return {
135
+ output: finalFile,
136
+ oldValueString,
137
+ formatted: false,
138
+ };
139
+ }
140
+ prettierConfig = await resolveConfig(configFilePath);
120
141
  }
121
- const prettierConfig = await resolveConfig(configFilePath);
122
142
  if (!prettierConfig) {
123
- throw new Error('The Prettier config file was not found. For this feature, the "prettier" package must be installed and a .prettierrc file must exist.');
143
+ return {
144
+ output: finalFile,
145
+ oldValueString,
146
+ formatted: false,
147
+ };
124
148
  }
125
- const finalFile = (0, parse_ast_1.serializeAst)(ast);
126
149
  const prettified = await format(finalFile, {
127
150
  ...prettierConfig,
128
151
  filepath: 'test.tsx',
129
152
  plugins: [],
130
- endOfLine: 'auto',
153
+ endOfLine: 'lf',
131
154
  });
132
- return { output: prettified, oldValueString };
155
+ return {
156
+ output: prettified,
157
+ oldValueString,
158
+ formatted: true,
159
+ };
133
160
  };
134
161
  exports.updateSequenceProps = updateSequenceProps;
@@ -1,8 +1,17 @@
1
- import type { Expression } from '@babel/types';
2
- import type { CanUpdateSequencePropsResponse } from '@remotion/studio-shared';
1
+ import type { Expression, File, JSXOpeningElement } from '@babel/types';
2
+ import type { CanUpdateSequencePropsResponse, SequenceNodePath } from '@remotion/studio-shared';
3
3
  export declare const isStaticValue: (node: Expression) => boolean;
4
4
  export declare const extractStaticValue: (node: Expression) => unknown;
5
- export declare const computeSequencePropsStatus: ({ fileName, line, keys, remotionRoot, }: {
5
+ export declare const findJsxElementAtNodePath: (ast: File, nodePath: SequenceNodePath) => JSXOpeningElement | null;
6
+ export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
7
+ export declare const computeSequencePropsStatusFromContent: (fileContents: string, nodePath: SequenceNodePath, keys: string[]) => CanUpdateSequencePropsResponse;
8
+ export declare const computeSequencePropsStatus: ({ fileName, nodePath, keys, remotionRoot, }: {
9
+ fileName: string;
10
+ nodePath: SequenceNodePath;
11
+ keys: string[];
12
+ remotionRoot: string;
13
+ }) => CanUpdateSequencePropsResponse;
14
+ export declare const computeSequencePropsStatusByLine: ({ fileName, line, keys, remotionRoot, }: {
6
15
  fileName: string;
7
16
  line: number;
8
17
  keys: string[];
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.computeSequencePropsStatus = exports.extractStaticValue = exports.isStaticValue = void 0;
39
+ exports.computeSequencePropsStatusByLine = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.lineColumnToNodePath = exports.findJsxElementAtNodePath = exports.extractStaticValue = exports.isStaticValue = void 0;
40
40
  const node_fs_1 = require("node:fs");
41
41
  const node_path_1 = __importDefault(require("node:path"));
42
42
  const recast = __importStar(require("recast"));
@@ -151,21 +151,146 @@ const getPropsStatus = (jsxElement) => {
151
151
  }
152
152
  return props;
153
153
  };
154
- const findJsxElementAtLine = (ast, targetLine) => {
155
- let found = null;
154
+ const getNodePathForRecastPath = (
155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
+ recastPath) => {
157
+ const segments = [];
158
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
159
+ let current = recastPath;
160
+ while (current && current.parentPath) {
161
+ segments.unshift(current.name);
162
+ current = current.parentPath;
163
+ }
164
+ // Recast paths start with "root" which doesn't correspond to a real AST property
165
+ if (segments.length > 0 && segments[0] === 'root') {
166
+ return segments.slice(1);
167
+ }
168
+ return segments;
169
+ };
170
+ const findJsxElementAtNodePath = (ast, nodePath) => {
171
+ let current = new recast.types.NodePath(ast);
172
+ for (const segment of nodePath) {
173
+ current = current.get(segment);
174
+ if (current.value === null || current.value === undefined) {
175
+ return null;
176
+ }
177
+ }
178
+ if (recast.types.namedTypes.JSXOpeningElement.check(current.value)) {
179
+ return current.value;
180
+ }
181
+ return null;
182
+ };
183
+ exports.findJsxElementAtNodePath = findJsxElementAtNodePath;
184
+ const lineColumnToNodePath = (ast, targetLine) => {
185
+ let foundPath = null;
156
186
  recast.types.visit(ast, {
157
- visitJSXOpeningElement(nodePath) {
158
- const { node } = nodePath;
187
+ visitJSXOpeningElement(p) {
188
+ const { node } = p;
159
189
  if (node.loc && node.loc.start.line === targetLine) {
160
- found = node;
190
+ foundPath = getNodePathForRecastPath(p);
161
191
  return false;
162
192
  }
163
- return this.traverse(nodePath);
193
+ return this.traverse(p);
164
194
  },
165
195
  });
166
- return found;
196
+ return foundPath;
197
+ };
198
+ exports.lineColumnToNodePath = lineColumnToNodePath;
199
+ const PIXEL_VALUE_REGEX = /^-?\d+(\.\d+)?px$/;
200
+ const isSupportedTranslateValue = (value) => {
201
+ const parts = value.split(/\s+/);
202
+ if (parts.length === 1 || parts.length === 2) {
203
+ return parts.every((part) => PIXEL_VALUE_REGEX.test(part));
204
+ }
205
+ return false;
206
+ };
207
+ const validateStyleValue = (childKey, value) => {
208
+ if (childKey === 'translate' && typeof value === 'string') {
209
+ return isSupportedTranslateValue(value);
210
+ }
211
+ return true;
212
+ };
213
+ const getNestedPropStatus = (jsxElement, parentKey, childKey) => {
214
+ const attr = jsxElement.attributes.find((a) => a.type !== 'JSXSpreadAttribute' &&
215
+ a.name.type !== 'JSXNamespacedName' &&
216
+ a.name.name === parentKey);
217
+ if (!attr || !attr.value) {
218
+ // Parent attribute doesn't exist, nested prop can be added
219
+ return { canUpdate: true, codeValue: undefined };
220
+ }
221
+ if (attr.value.type !== 'JSXExpressionContainer') {
222
+ return { canUpdate: false, reason: 'computed' };
223
+ }
224
+ const { expression } = attr.value;
225
+ if (expression.type === 'JSXEmptyExpression' ||
226
+ expression.type !== 'ObjectExpression') {
227
+ // Parent is not an object literal (e.g. style={myStyles})
228
+ return { canUpdate: false, reason: 'computed' };
229
+ }
230
+ const objExpr = expression;
231
+ const prop = objExpr.properties.find((p) => p.type === 'ObjectProperty' &&
232
+ ((p.key.type === 'Identifier' && p.key.name === childKey) ||
233
+ (p.key.type === 'StringLiteral' && p.key.value === childKey)));
234
+ if (!prop) {
235
+ // Property not set in the object, can be added
236
+ return { canUpdate: true, codeValue: undefined };
237
+ }
238
+ const propValue = prop.value;
239
+ if (!(0, exports.isStaticValue)(propValue)) {
240
+ return { canUpdate: false, reason: 'computed' };
241
+ }
242
+ const codeValue = (0, exports.extractStaticValue)(propValue);
243
+ if (!validateStyleValue(childKey, codeValue)) {
244
+ return { canUpdate: false, reason: 'computed' };
245
+ }
246
+ return { canUpdate: true, codeValue };
247
+ };
248
+ const computeSequencePropsStatusFromContent = (fileContents, nodePath, keys) => {
249
+ const ast = (0, parse_ast_1.parseAst)(fileContents);
250
+ const jsxElement = (0, exports.findJsxElementAtNodePath)(ast, nodePath);
251
+ if (!jsxElement) {
252
+ throw new Error('Could not find a JSX element at the specified location');
253
+ }
254
+ const allProps = getPropsStatus(jsxElement);
255
+ const filteredProps = {};
256
+ for (const key of keys) {
257
+ const dotIndex = key.indexOf('.');
258
+ if (dotIndex !== -1) {
259
+ filteredProps[key] = getNestedPropStatus(jsxElement, key.slice(0, dotIndex), key.slice(dotIndex + 1));
260
+ }
261
+ else if (key in allProps) {
262
+ filteredProps[key] = allProps[key];
263
+ }
264
+ else {
265
+ filteredProps[key] = { canUpdate: true, codeValue: undefined };
266
+ }
267
+ }
268
+ return {
269
+ canUpdate: true,
270
+ props: filteredProps,
271
+ nodePath,
272
+ };
273
+ };
274
+ exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
275
+ const computeSequencePropsStatus = ({ fileName, nodePath, keys, remotionRoot, }) => {
276
+ try {
277
+ const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
278
+ const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
279
+ if (fileRelativeToRoot.startsWith('..')) {
280
+ throw new Error('Cannot read a file outside the project');
281
+ }
282
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
283
+ return (0, exports.computeSequencePropsStatusFromContent)(fileContents, nodePath, keys);
284
+ }
285
+ catch (err) {
286
+ return {
287
+ canUpdate: false,
288
+ reason: err.message,
289
+ };
290
+ }
167
291
  };
168
- const computeSequencePropsStatus = ({ fileName, line, keys, remotionRoot, }) => {
292
+ exports.computeSequencePropsStatus = computeSequencePropsStatus;
293
+ const computeSequencePropsStatusByLine = ({ fileName, line, keys, remotionRoot, }) => {
169
294
  try {
170
295
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
171
296
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -174,24 +299,16 @@ const computeSequencePropsStatus = ({ fileName, line, keys, remotionRoot, }) =>
174
299
  }
175
300
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
176
301
  const ast = (0, parse_ast_1.parseAst)(fileContents);
177
- const jsxElement = findJsxElementAtLine(ast, line);
178
- if (!jsxElement) {
302
+ const resolvedNodePath = (0, exports.lineColumnToNodePath)(ast, line);
303
+ if (!resolvedNodePath) {
179
304
  throw new Error('Could not find a JSX element at the specified location');
180
305
  }
181
- const allProps = getPropsStatus(jsxElement);
182
- const filteredProps = {};
183
- for (const key of keys) {
184
- if (key in allProps) {
185
- filteredProps[key] = allProps[key];
186
- }
187
- else {
188
- filteredProps[key] = { canUpdate: true, codeValue: undefined };
189
- }
190
- }
191
- return {
192
- canUpdate: true,
193
- props: filteredProps,
194
- };
306
+ return (0, exports.computeSequencePropsStatus)({
307
+ fileName,
308
+ nodePath: resolvedNodePath,
309
+ keys,
310
+ remotionRoot,
311
+ });
195
312
  }
196
313
  catch (err) {
197
314
  return {
@@ -200,4 +317,4 @@ const computeSequencePropsStatus = ({ fileName, line, keys, remotionRoot, }) =>
200
317
  };
201
318
  }
202
319
  };
203
- exports.computeSequencePropsStatus = computeSequencePropsStatus;
320
+ exports.computeSequencePropsStatusByLine = computeSequencePropsStatusByLine;
@@ -0,0 +1,10 @@
1
+ export declare const logUpdate: ({ absolutePath, fileRelativeToRoot, key, oldValueString, newValueString, defaultValueString, formatted, logLevel, }: {
2
+ absolutePath: string;
3
+ fileRelativeToRoot: string;
4
+ key: string;
5
+ oldValueString: string;
6
+ newValueString: string;
7
+ defaultValueString: string | null;
8
+ formatted: boolean;
9
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
10
+ }) => void;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logUpdate = void 0;
4
+ const renderer_1 = require("@remotion/renderer");
5
+ const make_link_1 = require("../../hyperlinks/make-link");
6
+ let warnedAboutPrettier = false;
7
+ const normalizeQuotes = (str) => {
8
+ if (str.length >= 2 &&
9
+ ((str.startsWith("'") && str.endsWith("'")) ||
10
+ (str.startsWith('"') && str.endsWith('"')))) {
11
+ return `'${str.slice(1, -1)}'`;
12
+ }
13
+ return str;
14
+ };
15
+ const formatValueChange = ({ oldValueString, newValueString, defaultValueString, }) => {
16
+ // Changed to default value (prop gets deleted) → show only old value in red
17
+ if (defaultValueString !== null && newValueString === defaultValueString) {
18
+ return renderer_1.RenderInternals.chalk.red(oldValueString);
19
+ }
20
+ // Changed from default value (prop gets added) → show only new value in green
21
+ if (defaultValueString !== null && oldValueString === defaultValueString) {
22
+ return renderer_1.RenderInternals.chalk.green(newValueString);
23
+ }
24
+ return `${renderer_1.RenderInternals.chalk.red(oldValueString)} \u2192 ${renderer_1.RenderInternals.chalk.green(newValueString)}`;
25
+ };
26
+ const formatPropChange = ({ key, oldValueString, newValueString, defaultValueString, }) => {
27
+ const isResetToDefault = defaultValueString !== null && newValueString === defaultValueString;
28
+ const isChangeFromDefault = defaultValueString !== null && oldValueString === defaultValueString;
29
+ const valueChange = formatValueChange({
30
+ oldValueString,
31
+ newValueString,
32
+ defaultValueString,
33
+ });
34
+ const dotIndex = key.indexOf('.');
35
+ if (dotIndex === -1) {
36
+ if (isResetToDefault) {
37
+ return renderer_1.RenderInternals.chalk.red(`${key}={${oldValueString}}`);
38
+ }
39
+ if (isChangeFromDefault) {
40
+ return renderer_1.RenderInternals.chalk.green(`${key}={${newValueString}}`);
41
+ }
42
+ return `${key}={${valueChange}}`;
43
+ }
44
+ const parentKey = key.slice(0, dotIndex);
45
+ const childKey = key.slice(dotIndex + 1);
46
+ if (isResetToDefault) {
47
+ return `${parentKey}={{${renderer_1.RenderInternals.chalk.red(`${childKey}: ${oldValueString}`)}}}`;
48
+ }
49
+ if (isChangeFromDefault) {
50
+ return `${parentKey}={{${renderer_1.RenderInternals.chalk.green(`${childKey}: ${newValueString}`)}}}`;
51
+ }
52
+ return `${parentKey}={{${childKey}: ${valueChange}}}`;
53
+ };
54
+ const logUpdate = ({ absolutePath, fileRelativeToRoot, key, oldValueString, newValueString, defaultValueString, formatted, logLevel, }) => {
55
+ const locationLabel = `${fileRelativeToRoot}`;
56
+ const fileLink = (0, make_link_1.makeHyperlink)({
57
+ url: `file://${absolutePath}`,
58
+ text: locationLabel,
59
+ fallback: locationLabel,
60
+ });
61
+ const propChange = formatPropChange({
62
+ key,
63
+ oldValueString: normalizeQuotes(oldValueString),
64
+ newValueString: normalizeQuotes(newValueString),
65
+ defaultValueString: defaultValueString !== null ? normalizeQuotes(defaultValueString) : null,
66
+ });
67
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${fileLink}:`)} ${propChange}`);
68
+ if (!formatted && !warnedAboutPrettier) {
69
+ warnedAboutPrettier = true;
70
+ renderer_1.RenderInternals.Log.warn({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.yellow('Could not format with Prettier. File will need to be formatted manually.'));
71
+ }
72
+ };
73
+ exports.logUpdate = logUpdate;
@@ -6,11 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.saveSequencePropsHandler = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const renderer_1 = require("@remotion/renderer");
10
9
  const update_sequence_props_1 = require("../../codemods/update-sequence-props");
11
- const make_link_1 = require("../../hyperlinks/make-link");
12
10
  const hmr_suppression_1 = require("../hmr-suppression");
13
- const saveSequencePropsHandler = async ({ input: { fileName, line, column, key, value, enumPaths, defaultValue }, remotionRoot, logLevel, }) => {
11
+ const log_update_1 = require("./log-update");
12
+ const saveSequencePropsHandler = async ({ input: { fileName, nodePath, key, value, defaultValue }, remotionRoot, logLevel, }) => {
14
13
  try {
15
14
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
16
15
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -18,24 +17,27 @@ const saveSequencePropsHandler = async ({ input: { fileName, line, column, key,
18
17
  throw new Error('Cannot modify a file outside the project');
19
18
  }
20
19
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
21
- const { output, oldValueString } = await (0, update_sequence_props_1.updateSequenceProps)({
20
+ const { output, oldValueString, formatted } = await (0, update_sequence_props_1.updateSequenceProps)({
22
21
  input: fileContents,
23
- targetLine: line,
22
+ nodePath,
24
23
  key,
25
24
  value: JSON.parse(value),
26
- enumPaths,
27
25
  defaultValue: defaultValue !== null ? JSON.parse(defaultValue) : null,
28
26
  });
29
27
  (0, hmr_suppression_1.suppressHmrForFile)(absolutePath);
30
28
  (0, node_fs_1.writeFileSync)(absolutePath, output);
31
29
  const newValueString = JSON.stringify(JSON.parse(value));
32
- const locationLabel = `${fileRelativeToRoot}:${line}:${column}`;
33
- const fileLink = (0, make_link_1.makeHyperlink)({
34
- url: `file://${absolutePath}`,
35
- text: locationLabel,
36
- fallback: locationLabel,
30
+ const parsedDefault = defaultValue !== null ? JSON.parse(defaultValue) : null;
31
+ (0, log_update_1.logUpdate)({
32
+ absolutePath,
33
+ fileRelativeToRoot,
34
+ key,
35
+ oldValueString,
36
+ newValueString,
37
+ defaultValueString: parsedDefault !== null ? JSON.stringify(parsedDefault) : null,
38
+ formatted,
39
+ logLevel,
37
40
  });
38
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blueBright(`${fileLink} updated: ${key} ${oldValueString} \u2192 ${newValueString}`));
39
41
  return {
40
42
  success: true,
41
43
  };
@@ -2,11 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.subscribeToSequenceProps = void 0;
4
4
  const sequence_props_watchers_1 = require("../sequence-props-watchers");
5
- const subscribeToSequenceProps = ({ input: { fileName, line, column, keys, clientId }, remotionRoot }) => {
5
+ const subscribeToSequenceProps = ({ input: { fileName, line, keys, clientId }, remotionRoot }) => {
6
6
  const result = (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
7
7
  fileName,
8
8
  line,
9
- column,
10
9
  keys,
11
10
  remotionRoot,
12
11
  clientId,
@@ -2,11 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.unsubscribeFromSequenceProps = void 0;
4
4
  const sequence_props_watchers_1 = require("../sequence-props-watchers");
5
- const unsubscribeFromSequenceProps = ({ input: { fileName, line, column, clientId }, remotionRoot }) => {
5
+ const unsubscribeFromSequenceProps = ({ input: { fileName, nodePath, clientId }, remotionRoot }) => {
6
6
  (0, sequence_props_watchers_1.unsubscribeFromSequencePropsWatchers)({
7
7
  fileName,
8
- line,
9
- column,
8
+ nodePath,
10
9
  remotionRoot,
11
10
  clientId,
12
11
  });
@@ -1,16 +1,14 @@
1
- import type { CanUpdateSequencePropsResponse } from '@remotion/studio-shared';
2
- export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, keys, remotionRoot, clientId, }: {
1
+ import type { CanUpdateSequencePropsResponse, SequenceNodePath } from '@remotion/studio-shared';
2
+ export declare const subscribeToSequencePropsWatchers: ({ fileName, line, keys, remotionRoot, clientId, }: {
3
3
  fileName: string;
4
4
  line: number;
5
- column: number;
6
5
  keys: string[];
7
6
  remotionRoot: string;
8
7
  clientId: string;
9
8
  }) => CanUpdateSequencePropsResponse;
10
- export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, line, column, remotionRoot, clientId, }: {
9
+ export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath, remotionRoot, clientId, }: {
11
10
  fileName: string;
12
- line: number;
13
- column: number;
11
+ nodePath: SequenceNodePath;
14
12
  remotionRoot: string;
15
13
  clientId: string;
16
14
  }) => void;
@@ -9,23 +9,28 @@ const file_watcher_1 = require("../file-watcher");
9
9
  const live_events_1 = require("./live-events");
10
10
  const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
11
11
  const sequencePropsWatchers = {};
12
- const makeWatcherKey = ({ absolutePath, line, column, }) => {
13
- return `${absolutePath}:${line}:${column}`;
12
+ const makeWatcherKey = ({ absolutePath, nodePath, }) => {
13
+ return `${absolutePath}:${JSON.stringify(nodePath)}`;
14
14
  };
15
- const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, remotionRoot, clientId, }) => {
15
+ const subscribeToSequencePropsWatchers = ({ fileName, line, keys, remotionRoot, clientId, }) => {
16
16
  var _a;
17
17
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
18
- const watcherKey = makeWatcherKey({ absolutePath, line, column });
19
- // Unwatch any existing watcher for the same key
20
- if ((_a = sequencePropsWatchers[clientId]) === null || _a === void 0 ? void 0 : _a[watcherKey]) {
21
- sequencePropsWatchers[clientId][watcherKey].unwatch();
22
- }
23
- const initialResult = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
18
+ // Initial lookup by line+column to resolve the nodePath
19
+ const initialResult = (0, can_update_sequence_props_1.computeSequencePropsStatusByLine)({
24
20
  fileName,
25
21
  line,
26
22
  keys,
27
23
  remotionRoot,
28
24
  });
25
+ if (!initialResult.canUpdate) {
26
+ return initialResult;
27
+ }
28
+ const { nodePath } = initialResult;
29
+ const watcherKey = makeWatcherKey({ absolutePath, nodePath });
30
+ // Unwatch any existing watcher for the same key
31
+ if ((_a = sequencePropsWatchers[clientId]) === null || _a === void 0 ? void 0 : _a[watcherKey]) {
32
+ sequencePropsWatchers[clientId][watcherKey].unwatch();
33
+ }
29
34
  const { unwatch } = (0, file_watcher_1.installFileWatcher)({
30
35
  file: absolutePath,
31
36
  onChange: (type) => {
@@ -34,7 +39,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, remoti
34
39
  }
35
40
  const result = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
36
41
  fileName,
37
- line,
42
+ nodePath,
38
43
  keys,
39
44
  remotionRoot,
40
45
  });
@@ -42,8 +47,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, remoti
42
47
  listener.sendEventToClient({
43
48
  type: 'sequence-props-updated',
44
49
  fileName,
45
- line,
46
- column,
50
+ nodePath,
47
51
  result,
48
52
  });
49
53
  });
@@ -56,14 +60,16 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, remoti
56
60
  return initialResult;
57
61
  };
58
62
  exports.subscribeToSequencePropsWatchers = subscribeToSequencePropsWatchers;
59
- const unsubscribeFromSequencePropsWatchers = ({ fileName, line, column, remotionRoot, clientId, }) => {
60
- var _a;
63
+ const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot, clientId, }) => {
61
64
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
62
- const watcherKey = makeWatcherKey({ absolutePath, line, column });
63
- if (!sequencePropsWatchers[clientId]) {
65
+ const watcherKey = makeWatcherKey({ absolutePath, nodePath });
66
+ if (!sequencePropsWatchers[clientId] ||
67
+ !sequencePropsWatchers[clientId][watcherKey]) {
68
+ // eslint-disable-next-line no-console
69
+ console.warn(`Unexpected: unsubscribe for sequence props watcher that does not exist (clientId=${clientId}, key=${watcherKey})`);
64
70
  return;
65
71
  }
66
- (_a = sequencePropsWatchers[clientId][watcherKey]) === null || _a === void 0 ? void 0 : _a.unwatch();
72
+ sequencePropsWatchers[clientId][watcherKey].unwatch();
67
73
  delete sequencePropsWatchers[clientId][watcherKey];
68
74
  };
69
75
  exports.unsubscribeFromSequencePropsWatchers = unsubscribeFromSequencePropsWatchers;
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.431",
6
+ "version": "4.0.433",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "sideEffects": false,
@@ -27,11 +27,11 @@
27
27
  "@babel/parser": "7.24.1",
28
28
  "semver": "7.5.3",
29
29
  "prettier": "3.8.1",
30
- "remotion": "4.0.431",
30
+ "remotion": "4.0.433",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.431",
33
- "@remotion/renderer": "4.0.431",
34
- "@remotion/studio-shared": "4.0.431",
32
+ "@remotion/bundler": "4.0.433",
33
+ "@remotion/renderer": "4.0.433",
34
+ "@remotion/studio-shared": "4.0.433",
35
35
  "memfs": "3.4.3",
36
36
  "source-map": "0.7.3",
37
37
  "open": "^8.4.2"
@@ -41,7 +41,7 @@
41
41
  "react": "19.2.3",
42
42
  "@babel/types": "7.24.0",
43
43
  "@types/semver": "^7.3.4",
44
- "@remotion/eslint-config-internal": "4.0.431",
44
+ "@remotion/eslint-config-internal": "4.0.433",
45
45
  "eslint": "9.19.0",
46
46
  "@types/node": "20.12.14",
47
47
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
@@ -1,8 +0,0 @@
1
- import type { File } from '@babel/types';
2
- import { type ApplyComponentVisualControlCodemod } from '@remotion/studio-shared';
3
- import type { ApplyCodeModReturnType, Change } from './recast-mods';
4
- export declare const applyComponentVisualControl: ({ file, transformation, changesMade, }: {
5
- file: File;
6
- transformation: ApplyComponentVisualControlCodemod;
7
- changesMade: Change[];
8
- }) => ApplyCodeModReturnType;
@@ -1,92 +0,0 @@
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.applyComponentVisualControl = void 0;
37
- const studio_shared_1 = require("@remotion/studio-shared");
38
- const recast = __importStar(require("recast"));
39
- const parse_ast_1 = require("./parse-ast");
40
- const applyComponentVisualControl = ({ file, transformation, changesMade, }) => {
41
- recast.types.visit(file.program, {
42
- visitJSXOpeningElement(path) {
43
- var _a;
44
- const { node } = path;
45
- if (node.name.type !== 'JSXIdentifier' ||
46
- node.name.name !== transformation.componentName) {
47
- return this.traverse(path);
48
- }
49
- if (((_a = node.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== transformation.line) {
50
- return this.traverse(path);
51
- }
52
- const attributes = node.attributes;
53
- if (!attributes) {
54
- return this.traverse(path);
55
- }
56
- for (const change of transformation.changes) {
57
- const parsed = (0, parse_ast_1.parseAst)(`a = ${(0, studio_shared_1.stringifyDefaultProps)({ props: JSON.parse(change.newValueSerialized), enumPaths: change.enumPaths })}`).program.body[0].expression.right;
58
- const existingAttr = attributes.find((attr) => attr.type === 'JSXAttribute' &&
59
- attr.name.type === 'JSXIdentifier' &&
60
- attr.name.name === change.propName);
61
- if (existingAttr && existingAttr.type === 'JSXAttribute') {
62
- existingAttr.value = {
63
- type: 'JSXExpressionContainer',
64
- expression: parsed,
65
- };
66
- changesMade.push({
67
- description: `Updated prop ${change.propName} on ${transformation.componentName}`,
68
- });
69
- }
70
- else {
71
- attributes.push({
72
- type: 'JSXAttribute',
73
- name: {
74
- type: 'JSXIdentifier',
75
- name: change.propName,
76
- },
77
- value: {
78
- type: 'JSXExpressionContainer',
79
- expression: parsed,
80
- },
81
- });
82
- changesMade.push({
83
- description: `Added prop ${change.propName} to ${transformation.componentName}`,
84
- });
85
- }
86
- }
87
- return false;
88
- },
89
- });
90
- return { newAst: file, changesMade };
91
- };
92
- exports.applyComponentVisualControl = applyComponentVisualControl;
@@ -1,3 +0,0 @@
1
- import type { ApplyComponentVisualControlRequest, ApplyComponentVisualControlResponse } from '@remotion/studio-shared';
2
- import type { ApiHandler } from '../api-types';
3
- export declare const applyComponentVisualControlHandler: ApiHandler<ApplyComponentVisualControlRequest, ApplyComponentVisualControlResponse>;
@@ -1,38 +0,0 @@
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.applyComponentVisualControlHandler = void 0;
7
- const node_fs_1 = require("node:fs");
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const parse_ast_1 = require("../../codemods/parse-ast");
10
- const recast_mods_1 = require("../../codemods/recast-mods");
11
- const applyComponentVisualControlHandler = ({ input: { fileName, componentName, line, column, changes }, remotionRoot }) => {
12
- const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
13
- const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
14
- if (fileRelativeToRoot.startsWith('..')) {
15
- throw new Error('Cannot apply component visual control change to a file outside the project');
16
- }
17
- const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
18
- const ast = (0, parse_ast_1.parseAst)(fileContents);
19
- const { newAst, changesMade } = (0, recast_mods_1.applyCodemod)({
20
- file: ast,
21
- codeMod: {
22
- type: 'apply-component-visual-control',
23
- componentName,
24
- line,
25
- column,
26
- changes,
27
- },
28
- });
29
- if (changesMade.length === 0) {
30
- throw new Error('No changes were made to the file');
31
- }
32
- const output = (0, parse_ast_1.serializeAst)(newAst);
33
- (0, node_fs_1.writeFileSync)(absolutePath, output);
34
- return Promise.resolve({
35
- success: true,
36
- });
37
- };
38
- exports.applyComponentVisualControlHandler = applyComponentVisualControlHandler;