@remotion/studio-server 4.0.471 → 4.0.472

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.
Files changed (31) hide show
  1. package/dist/codemods/add-effect.d.ts +11 -0
  2. package/dist/codemods/add-effect.js +14 -52
  3. package/dist/codemods/format-file-content.js +1 -1
  4. package/dist/codemods/parse-ast.js +4 -1
  5. package/dist/codemods/paste-effects.d.ts +15 -0
  6. package/dist/codemods/paste-effects.js +234 -0
  7. package/dist/codemods/recast-mods.js +178 -31
  8. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +1 -1
  9. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +7 -55
  10. package/dist/codemods/update-keyframes/update-keyframes.d.ts +11 -6
  11. package/dist/codemods/update-keyframes/update-keyframes.js +127 -16
  12. package/dist/helpers/get-ast-node-path.js +6 -1
  13. package/dist/helpers/import-agnostic-node-path.d.ts +10 -0
  14. package/dist/helpers/import-agnostic-node-path.js +154 -0
  15. package/dist/helpers/imports.d.ts +16 -0
  16. package/dist/helpers/imports.js +145 -0
  17. package/dist/helpers/resolve-composition-component.js +114 -51
  18. package/dist/preview-server/api-routes.js +2 -0
  19. package/dist/preview-server/routes/add-effect-keyframe.js +2 -0
  20. package/dist/preview-server/routes/add-sequence-keyframe.js +1 -0
  21. package/dist/preview-server/routes/apply-codemod.js +18 -0
  22. package/dist/preview-server/routes/can-update-effect-props.d.ts +3 -2
  23. package/dist/preview-server/routes/can-update-effect-props.js +75 -6
  24. package/dist/preview-server/routes/can-update-sequence-props.js +33 -30
  25. package/dist/preview-server/routes/delete-keyframes.js +1 -0
  26. package/dist/preview-server/routes/insert-jsx-element.js +23 -0
  27. package/dist/preview-server/routes/paste-effects.d.ts +3 -0
  28. package/dist/preview-server/routes/paste-effects.js +78 -0
  29. package/dist/preview-server/routes/save-effect-props.js +1 -0
  30. package/dist/preview-server/undo-stack.d.ts +7 -1
  31. package/package.json +6 -6
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.updateEffectKeyframes = exports.updateEffectKeyframesAst = exports.updateSequenceKeyframes = exports.updateSequenceKeyframesAst = void 0;
37
+ const studio_shared_1 = require("@remotion/studio-shared");
37
38
  const recast = __importStar(require("recast"));
38
39
  const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
39
40
  const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
@@ -71,8 +72,7 @@ const getInterpolationExpression = (node) => {
71
72
  }
72
73
  if (node.type !== 'CallExpression' ||
73
74
  node.callee.type !== 'Identifier' ||
74
- (node.callee.name !== 'interpolate' &&
75
- node.callee.name !== 'interpolateColors')) {
75
+ !(0, studio_shared_1.isKeyframeInterpolationFunction)(node.callee.name)) {
76
76
  return null;
77
77
  }
78
78
  const frameArg = getSupportedCallArgument(node.arguments[0]);
@@ -124,14 +124,23 @@ const getInterpolationExpression = (node) => {
124
124
  keyframes,
125
125
  };
126
126
  };
127
- const getInterpolationCalleeForValues = ({ staticValue, newValue, }) => {
128
- return b.identifier(typeof staticValue === 'string' && typeof newValue === 'string'
129
- ? 'interpolateColors'
130
- : 'interpolate');
127
+ const getInterpolationCalleeForValues = ({ schema, key, staticValue, newValue, }) => {
128
+ return b.identifier((0, studio_shared_1.getKeyframeInterpolationFunction)({
129
+ schema,
130
+ key,
131
+ staticValue,
132
+ newValue,
133
+ }));
131
134
  };
132
135
  const createFrameExpression = (frame) => {
133
136
  return (0, update_nested_prop_1.parseValueExpression)(frame);
134
137
  };
138
+ const createClampOptionsExpression = () => {
139
+ return b.objectExpression([
140
+ b.objectProperty(b.identifier('extrapolateLeft'), b.stringLiteral('clamp')),
141
+ b.objectProperty(b.identifier('extrapolateRight'), b.stringLiteral('clamp')),
142
+ ]);
143
+ };
135
144
  const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) => {
136
145
  const sortedKeyframes = [...keyframes].sort((first, second) => first.frame - second.frame);
137
146
  return b.callExpression(callee, [
@@ -145,10 +154,21 @@ const noIntroducedIdentifiers = {
145
154
  calleeName: null,
146
155
  needsFrameHook: false,
147
156
  };
148
- const addKeyframe = ({ expression, frame, value, }) => {
157
+ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
158
+ if (!(0, studio_shared_1.isSchemaFieldKeyframable)({ schema, key })) {
159
+ throw new Error(`Cannot add keyframe: "${key}" is not keyframable`);
160
+ }
149
161
  const existing = getInterpolationExpression(expression);
150
162
  const newOutput = (0, update_nested_prop_1.parseValueExpression)(value);
151
163
  if (existing) {
164
+ const existingCalleeName = existing.callee.type === 'Identifier'
165
+ ? existing.callee.name
166
+ : 'interpolate';
167
+ const schemaCalleeName = (0, studio_shared_1.getKeyframeInterpolationFunctionForSchemaField)({
168
+ schema,
169
+ key,
170
+ });
171
+ const nextCalleeName = schemaCalleeName !== null && schemaCalleeName !== void 0 ? schemaCalleeName : existingCalleeName;
152
172
  const existingIndex = existing.keyframes.findIndex((keyframe) => keyframe.frame === frame);
153
173
  const nextKeyframes = existingIndex === -1
154
174
  ? [...existing.keyframes, { frame, output: newOutput, value }]
@@ -157,12 +177,17 @@ const addKeyframe = ({ expression, frame, value, }) => {
157
177
  : keyframe);
158
178
  return {
159
179
  expression: createInterpolateExpression({
160
- callee: existing.callee,
180
+ callee: b.identifier(nextCalleeName),
161
181
  input: existing.input,
162
182
  extraArgs: existing.extraArgs,
163
183
  keyframes: nextKeyframes,
164
184
  }),
165
- introduced: noIntroducedIdentifiers,
185
+ introduced: {
186
+ calleeName: schemaCalleeName && schemaCalleeName !== existingCalleeName
187
+ ? schemaCalleeName
188
+ : null,
189
+ needsFrameHook: false,
190
+ },
166
191
  };
167
192
  }
168
193
  if (!(0, can_update_sequence_props_1.isStaticValue)(expression)) {
@@ -171,14 +196,19 @@ const addKeyframe = ({ expression, frame, value, }) => {
171
196
  const staticValue = (0, can_update_sequence_props_1.extractStaticValue)(expression);
172
197
  const keyframes = [{ frame, output: newOutput, value }];
173
198
  const callee = getInterpolationCalleeForValues({
199
+ schema,
200
+ key,
174
201
  staticValue,
175
202
  newValue: value,
176
203
  });
204
+ const extraArgs = callee.type === 'Identifier' && callee.name === 'interpolateColors'
205
+ ? []
206
+ : [createClampOptionsExpression()];
177
207
  return {
178
208
  expression: createInterpolateExpression({
179
209
  callee,
180
210
  input: b.identifier('frame'),
181
- extraArgs: [],
211
+ extraArgs,
182
212
  keyframes,
183
213
  }),
184
214
  introduced: {
@@ -209,12 +239,14 @@ const removeKeyframe = ({ expression, frame, }) => {
209
239
  keyframes: nextKeyframes,
210
240
  });
211
241
  };
212
- const applyKeyframeOperation = ({ expression, operation, }) => {
242
+ const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
213
243
  if (operation.type === 'add') {
214
244
  return addKeyframe({
215
245
  expression,
246
+ key,
216
247
  frame: operation.frame,
217
248
  value: operation.value,
249
+ schema,
218
250
  });
219
251
  }
220
252
  return {
@@ -267,6 +299,30 @@ const findObjectProperty = (objExpr, propertyName) => {
267
299
  : objExpr.properties[propIndex],
268
300
  };
269
301
  };
302
+ const findFieldInSchema = (schema, key) => {
303
+ if (key in schema) {
304
+ return schema[key];
305
+ }
306
+ for (const field of Object.values(schema)) {
307
+ if (field.type !== 'enum') {
308
+ continue;
309
+ }
310
+ for (const variant of Object.values(field.variants)) {
311
+ const found = findFieldInSchema(variant, key);
312
+ if (found) {
313
+ return found;
314
+ }
315
+ }
316
+ }
317
+ return undefined;
318
+ };
319
+ const getInitialValueForMissingProp = ({ schema, key, newValue, }) => {
320
+ const field = schema ? findFieldInSchema(schema, key) : undefined;
321
+ if (field && field.type !== 'hidden' && field.default !== undefined) {
322
+ return field.default;
323
+ }
324
+ return newValue;
325
+ };
270
326
  const getObjectExpression = (attr) => {
271
327
  if (!attr.value || attr.value.type !== 'JSXExpressionContainer') {
272
328
  return null;
@@ -276,11 +332,31 @@ const getObjectExpression = (attr) => {
276
332
  }
277
333
  return attr.value.expression;
278
334
  };
279
- const getSequenceWritableProp = ({ attributes, key, }) => {
335
+ const createJsxExpressionAttribute = (key, expression) => {
336
+ return b.jsxAttribute(b.jsxIdentifier(key), b.jsxExpressionContainer(expression));
337
+ };
338
+ const createObjectProperty = (key, value) => b.objectProperty(b.identifier(key), value);
339
+ const createObjectExpressionAttribute = ({ parentKey, childKey, expression, }) => {
340
+ return createJsxExpressionAttribute(parentKey, b.objectExpression([
341
+ createObjectProperty(childKey, expression),
342
+ ]));
343
+ };
344
+ const createMissingPropExpression = (missingPropInitialValue) => {
345
+ return (0, update_nested_prop_1.parseValueExpression)(missingPropInitialValue.value);
346
+ };
347
+ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, }) => {
280
348
  const dotIndex = key.indexOf('.');
281
349
  if (dotIndex === -1) {
282
350
  const { attr: topLevelAttr } = findJsxAttribute(attributes, key);
283
351
  if (!topLevelAttr) {
352
+ if (missingPropInitialValue) {
353
+ return {
354
+ expression: createMissingPropExpression(missingPropInitialValue),
355
+ setExpression: (nextExpression) => {
356
+ attributes.push(createJsxExpressionAttribute(key, nextExpression));
357
+ },
358
+ };
359
+ }
284
360
  throw new Error(`Cannot update keyframes: "${key}" is not set`);
285
361
  }
286
362
  const expression = getExpressionFromJsxAttribute(topLevelAttr);
@@ -298,6 +374,18 @@ const getSequenceWritableProp = ({ attributes, key, }) => {
298
374
  const childKey = key.slice(dotIndex + 1);
299
375
  const { attr: parentAttr } = findJsxAttribute(attributes, parentKey);
300
376
  if (!parentAttr) {
377
+ if (missingPropInitialValue) {
378
+ return {
379
+ expression: createMissingPropExpression(missingPropInitialValue),
380
+ setExpression: (nextExpression) => {
381
+ attributes.push(createObjectExpressionAttribute({
382
+ parentKey,
383
+ childKey,
384
+ expression: nextExpression,
385
+ }));
386
+ },
387
+ };
388
+ }
301
389
  throw new Error(`Cannot update keyframes: "${parentKey}" is not set`);
302
390
  }
303
391
  const objExpr = getObjectExpression(parentAttr);
@@ -306,6 +394,14 @@ const getSequenceWritableProp = ({ attributes, key, }) => {
306
394
  }
307
395
  const { prop } = findObjectProperty(objExpr, childKey);
308
396
  if (!prop) {
397
+ if (missingPropInitialValue) {
398
+ return {
399
+ expression: createMissingPropExpression(missingPropInitialValue),
400
+ setExpression: (nextExpression) => {
401
+ objExpr.properties.push(createObjectProperty(childKey, nextExpression));
402
+ },
403
+ };
404
+ }
309
405
  throw new Error(`Cannot update keyframes: "${key}" is not set`);
310
406
  }
311
407
  return {
@@ -315,7 +411,7 @@ const getSequenceWritableProp = ({ attributes, key, }) => {
315
411
  },
316
412
  };
317
413
  };
318
- const updateSequenceKeyframesAst = ({ input, nodePath, updates, }) => {
414
+ const updateSequenceKeyframesAst = ({ input, nodePath, updates, schema, }) => {
319
415
  var _a;
320
416
  var _b;
321
417
  const ast = (0, parse_ast_1.parseAst)(input);
@@ -335,11 +431,22 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, }) => {
335
431
  const prop = getSequenceWritableProp({
336
432
  attributes: node.attributes,
337
433
  key: update.key,
434
+ missingPropInitialValue: update.operation.type === 'add'
435
+ ? {
436
+ value: getInitialValueForMissingProp({
437
+ schema: schema !== null && schema !== void 0 ? schema : null,
438
+ key: update.key,
439
+ newValue: update.operation.value,
440
+ }),
441
+ }
442
+ : null,
338
443
  });
339
444
  oldValueStrings.push(recast.print(prop.expression).code);
340
445
  const { expression: nextExpression, introduced } = applyKeyframeOperation({
341
446
  expression: prop.expression,
447
+ key: update.key,
342
448
  operation: update.operation,
449
+ schema: schema !== null && schema !== void 0 ? schema : null,
343
450
  });
344
451
  newValueStrings.push(recast.print(nextExpression).code);
345
452
  prop.setExpression(nextExpression);
@@ -371,11 +478,12 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, }) => {
371
478
  };
372
479
  };
373
480
  exports.updateSequenceKeyframesAst = updateSequenceKeyframesAst;
374
- const updateSequenceKeyframes = async ({ input, nodePath, updates, prettierConfigOverride, }) => {
481
+ const updateSequenceKeyframes = async ({ input, nodePath, updates, schema, prettierConfigOverride, }) => {
375
482
  const { serialized, oldValueStrings, newValueStrings, logLine, updatedNodePath, } = (0, exports.updateSequenceKeyframesAst)({
376
483
  input,
377
484
  nodePath,
378
485
  updates,
486
+ schema,
379
487
  });
380
488
  const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
381
489
  input: serialized,
@@ -391,7 +499,7 @@ const updateSequenceKeyframes = async ({ input, nodePath, updates, prettierConfi
391
499
  };
392
500
  };
393
501
  exports.updateSequenceKeyframes = updateSequenceKeyframes;
394
- const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, updates, }) => {
502
+ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, updates, schema, }) => {
395
503
  var _a, _b;
396
504
  var _c, _d, _e;
397
505
  const ast = (0, parse_ast_1.parseAst)(input);
@@ -426,7 +534,9 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
426
534
  oldValueStrings.push(recast.print(prop.value).code);
427
535
  const { expression: nextExpression, introduced } = applyKeyframeOperation({
428
536
  expression: prop.value,
537
+ key: update.key,
429
538
  operation: update.operation,
539
+ schema: schema !== null && schema !== void 0 ? schema : null,
430
540
  });
431
541
  newValueStrings.push(recast.print(nextExpression).code);
432
542
  prop.value = nextExpression;
@@ -459,12 +569,13 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
459
569
  };
460
570
  };
461
571
  exports.updateEffectKeyframesAst = updateEffectKeyframesAst;
462
- const updateEffectKeyframes = async ({ input, sequenceNodePath, effectIndex, updates, prettierConfigOverride, }) => {
572
+ const updateEffectKeyframes = async ({ input, sequenceNodePath, effectIndex, updates, schema, prettierConfigOverride, }) => {
463
573
  const { serialized, oldValueStrings, newValueStrings, logLine, effectCallee, updatedSequenceNodePath, } = (0, exports.updateEffectKeyframesAst)({
464
574
  input,
465
575
  sequenceNodePath,
466
576
  effectIndex,
467
577
  updates,
578
+ schema,
468
579
  });
469
580
  const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
470
581
  input: serialized,
@@ -35,9 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getAstNodePath = void 0;
37
37
  const recast = __importStar(require("recast"));
38
+ const import_agnostic_node_path_1 = require("./import-agnostic-node-path");
38
39
  const getAstNodePath = (ast, nodePath) => {
40
+ const resolvedNodePath = (0, import_agnostic_node_path_1.fromImportAgnosticNodePath)({ ast, nodePath });
41
+ if (!resolvedNodePath) {
42
+ return null;
43
+ }
39
44
  let current = new recast.types.NodePath(ast);
40
- for (const segment of nodePath) {
45
+ for (const segment of resolvedNodePath) {
41
46
  current = current.get(segment);
42
47
  if (current.value === null || current.value === undefined) {
43
48
  return null;
@@ -0,0 +1,10 @@
1
+ import type { File } from '@babel/types';
2
+ import type { SequenceNodePath } from 'remotion';
3
+ export declare const toImportAgnosticNodePath: ({ ast, nodePath, }: {
4
+ ast: File;
5
+ nodePath: SequenceNodePath;
6
+ }) => SequenceNodePath;
7
+ export declare const fromImportAgnosticNodePath: ({ ast, nodePath, }: {
8
+ ast: File;
9
+ nodePath: SequenceNodePath;
10
+ }) => SequenceNodePath | null;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromImportAgnosticNodePath = exports.toImportAgnosticNodePath = void 0;
4
+ const getActualIndex = ({ items, agnosticIndex, shouldIgnore, context, }) => {
5
+ let seenIncludedNodes = 0;
6
+ for (let i = 0; i < items.length; i++) {
7
+ if (shouldIgnore(items[i], context)) {
8
+ continue;
9
+ }
10
+ if (seenIncludedNodes === agnosticIndex) {
11
+ return i;
12
+ }
13
+ seenIncludedNodes++;
14
+ }
15
+ return null;
16
+ };
17
+ const getAgnosticIndex = ({ items, actualIndex, shouldIgnore, context, }) => {
18
+ if (actualIndex < 0 || actualIndex >= items.length) {
19
+ return null;
20
+ }
21
+ let seenIncludedNodes = 0;
22
+ for (let i = 0; i <= actualIndex; i++) {
23
+ if (shouldIgnore(items[i], context)) {
24
+ continue;
25
+ }
26
+ if (i === actualIndex) {
27
+ return seenIncludedNodes;
28
+ }
29
+ seenIncludedNodes++;
30
+ }
31
+ return null;
32
+ };
33
+ const getUseCurrentFrameLocalNames = (ast) => {
34
+ var _a;
35
+ var _b;
36
+ const names = new Set(['useCurrentFrame']);
37
+ for (const statement of ast.program.body) {
38
+ if (statement.type !== 'ImportDeclaration' ||
39
+ statement.source.value !== 'remotion') {
40
+ continue;
41
+ }
42
+ for (const specifier of statement.specifiers) {
43
+ if (specifier.type === 'ImportSpecifier' &&
44
+ specifier.imported.type === 'Identifier' &&
45
+ specifier.imported.name === 'useCurrentFrame') {
46
+ names.add((_b = (_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'useCurrentFrame');
47
+ }
48
+ }
49
+ }
50
+ return names;
51
+ };
52
+ const isUseCurrentFrameCall = (node, useCurrentFrameLocalNames) => {
53
+ return ((node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
54
+ node.callee.type === 'Identifier' &&
55
+ useCurrentFrameLocalNames.has(node.callee.name));
56
+ };
57
+ const isUseCurrentFrameStatement = (node, useCurrentFrameLocalNames) => {
58
+ if (node.type === 'ExpressionStatement') {
59
+ return isUseCurrentFrameCall(node.expression, useCurrentFrameLocalNames);
60
+ }
61
+ if (node.type !== 'VariableDeclaration' || node.declarations.length !== 1) {
62
+ return false;
63
+ }
64
+ return isUseCurrentFrameCall(node.declarations[0].init, useCurrentFrameLocalNames);
65
+ };
66
+ const getIgnoredNodePredicate = (ast) => {
67
+ const useCurrentFrameLocalNames = getUseCurrentFrameLocalNames(ast);
68
+ return (node, { parent, property }) => {
69
+ if (parent.type === 'Program' &&
70
+ property === 'body' &&
71
+ node.type === 'ImportDeclaration') {
72
+ return true;
73
+ }
74
+ if (parent.type === 'BlockStatement' && property === 'body') {
75
+ return isUseCurrentFrameStatement(node, useCurrentFrameLocalNames);
76
+ }
77
+ return false;
78
+ };
79
+ };
80
+ const getChild = (value, segment) => {
81
+ var _a, _b;
82
+ if (value === null || value === undefined) {
83
+ return null;
84
+ }
85
+ if (Array.isArray(value)) {
86
+ return (_a = value[segment]) !== null && _a !== void 0 ? _a : null;
87
+ }
88
+ if (typeof value !== 'object') {
89
+ return null;
90
+ }
91
+ return (_b = value[segment]) !== null && _b !== void 0 ? _b : null;
92
+ };
93
+ const transformNodePathIndices = ({ ast, nodePath, direction, }) => {
94
+ const shouldIgnore = getIgnoredNodePredicate(ast);
95
+ const transformed = [];
96
+ let current = ast;
97
+ let arrayContext = null;
98
+ for (const segment of nodePath) {
99
+ if (typeof segment === 'string') {
100
+ const parent = current;
101
+ current = getChild(current, segment);
102
+ if (Array.isArray(current) &&
103
+ parent &&
104
+ typeof parent === 'object' &&
105
+ 'type' in parent) {
106
+ arrayContext = { parent: parent, property: segment };
107
+ }
108
+ else {
109
+ arrayContext = null;
110
+ }
111
+ transformed.push(segment);
112
+ continue;
113
+ }
114
+ if (!Array.isArray(current) || !arrayContext) {
115
+ current = getChild(current, segment);
116
+ transformed.push(segment);
117
+ continue;
118
+ }
119
+ const mappedIndex = direction === 'to-agnostic'
120
+ ? getAgnosticIndex({
121
+ items: current,
122
+ actualIndex: segment,
123
+ shouldIgnore,
124
+ context: arrayContext,
125
+ })
126
+ : getActualIndex({
127
+ items: current,
128
+ agnosticIndex: segment,
129
+ shouldIgnore,
130
+ context: arrayContext,
131
+ });
132
+ if (mappedIndex === null) {
133
+ if (direction === 'from-agnostic') {
134
+ return null;
135
+ }
136
+ current = getChild(current, segment);
137
+ transformed.push(segment);
138
+ continue;
139
+ }
140
+ current = getChild(current, direction === 'to-agnostic' ? segment : mappedIndex);
141
+ arrayContext = null;
142
+ transformed.push(mappedIndex);
143
+ }
144
+ return transformed;
145
+ };
146
+ const toImportAgnosticNodePath = ({ ast, nodePath, }) => {
147
+ var _a;
148
+ return ((_a = transformNodePathIndices({ ast, nodePath, direction: 'to-agnostic' })) !== null && _a !== void 0 ? _a : nodePath);
149
+ };
150
+ exports.toImportAgnosticNodePath = toImportAgnosticNodePath;
151
+ const fromImportAgnosticNodePath = ({ ast, nodePath, }) => {
152
+ return transformNodePathIndices({ ast, nodePath, direction: 'from-agnostic' });
153
+ };
154
+ exports.fromImportAgnosticNodePath = fromImportAgnosticNodePath;
@@ -0,0 +1,16 @@
1
+ import type { File, ImportDeclaration, ImportSpecifier } from '@babel/types';
2
+ export declare const getImportedName: (specifier: ImportSpecifier) => string;
3
+ export declare const findImportDeclaration: (ast: File, sourcePath: string) => ImportDeclaration | null;
4
+ export declare const insertImportDeclaration: (ast: File, importDeclaration: ImportDeclaration) => void;
5
+ export declare const normalizeImportSpacing: (input: string) => string;
6
+ export declare const ensureNamedImport: ({ ast, importedName, sourcePath, localName, }: {
7
+ ast: File;
8
+ importedName: string;
9
+ sourcePath: string;
10
+ localName: string;
11
+ }) => string;
12
+ export declare const ensureNamedImports: ({ ast, importedNames, sourcePath, }: {
13
+ ast: File;
14
+ importedNames: ReadonlySet<string>;
15
+ sourcePath: string;
16
+ }) => void;
@@ -0,0 +1,145 @@
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.ensureNamedImports = exports.ensureNamedImport = exports.normalizeImportSpacing = exports.insertImportDeclaration = exports.findImportDeclaration = exports.getImportedName = void 0;
37
+ const recast = __importStar(require("recast"));
38
+ const b = recast.types.builders;
39
+ const getImportedName = (specifier) => {
40
+ if (specifier.imported.type === 'Identifier') {
41
+ return specifier.imported.name;
42
+ }
43
+ return specifier.imported.value;
44
+ };
45
+ exports.getImportedName = getImportedName;
46
+ const findImportDeclaration = (ast, sourcePath) => {
47
+ for (const stmt of ast.program.body) {
48
+ if (stmt.type === 'ImportDeclaration' &&
49
+ stmt.source.type === 'StringLiteral' &&
50
+ stmt.source.value === sourcePath) {
51
+ return stmt;
52
+ }
53
+ }
54
+ return null;
55
+ };
56
+ exports.findImportDeclaration = findImportDeclaration;
57
+ const findImportDeclarations = (ast, sourcePath) => {
58
+ return ast.program.body.filter((stmt) => stmt.type === 'ImportDeclaration' &&
59
+ stmt.source.type === 'StringLiteral' &&
60
+ stmt.source.value === sourcePath);
61
+ };
62
+ const insertImportDeclaration = (ast, importDeclaration) => {
63
+ const { body } = ast.program;
64
+ let lastImportIndex = -1;
65
+ for (let i = 0; i < body.length; i++) {
66
+ if (body[i].type === 'ImportDeclaration') {
67
+ lastImportIndex = i;
68
+ }
69
+ }
70
+ body.splice(lastImportIndex + 1, 0, importDeclaration);
71
+ };
72
+ exports.insertImportDeclaration = insertImportDeclaration;
73
+ const normalizeImportSpacing = (input) => {
74
+ return input.replace(/(import[^\n]*\n)\n+(?=import\b)/g, '$1');
75
+ };
76
+ exports.normalizeImportSpacing = normalizeImportSpacing;
77
+ const hasNamespaceSpecifier = (importDeclaration) => {
78
+ var _a;
79
+ return (_a = importDeclaration.specifiers) === null || _a === void 0 ? void 0 : _a.some((specifier) => specifier.type === 'ImportNamespaceSpecifier');
80
+ };
81
+ const ensureNamedImport = ({ ast, importedName, sourcePath, localName, }) => {
82
+ var _a, _b;
83
+ var _c, _d;
84
+ const existingImports = findImportDeclarations(ast, sourcePath);
85
+ for (const existingImportDeclaration of existingImports) {
86
+ const matchingSpecifier = (_a = existingImportDeclaration.specifiers) === null || _a === void 0 ? void 0 : _a.find((importSpecifierCandidate) => importSpecifierCandidate.type === 'ImportSpecifier' &&
87
+ (0, exports.getImportedName)(importSpecifierCandidate) === importedName);
88
+ if (matchingSpecifier) {
89
+ return (_c = (_b = matchingSpecifier.local) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : importedName;
90
+ }
91
+ }
92
+ const existingImport = existingImports.find((candidateImportDeclaration) => !hasNamespaceSpecifier(candidateImportDeclaration));
93
+ if (existingImport) {
94
+ const importSpecifier = b.importSpecifier(b.identifier(importedName), localName === importedName ? null : b.identifier(localName));
95
+ existingImport.specifiers = [
96
+ ...((_d = existingImport.specifiers) !== null && _d !== void 0 ? _d : []),
97
+ importSpecifier,
98
+ ];
99
+ return localName;
100
+ }
101
+ const specifier = b.importSpecifier(b.identifier(importedName), localName === importedName ? null : b.identifier(localName));
102
+ const importDeclaration = b.importDeclaration([specifier], b.stringLiteral(sourcePath));
103
+ (0, exports.insertImportDeclaration)(ast, importDeclaration);
104
+ return localName;
105
+ };
106
+ exports.ensureNamedImport = ensureNamedImport;
107
+ const ensureNamedImports = ({ ast, importedNames, sourcePath, }) => {
108
+ var _a, _b;
109
+ if (importedNames.size === 0) {
110
+ return;
111
+ }
112
+ const existingImports = findImportDeclarations(ast, sourcePath);
113
+ const existingNames = new Set();
114
+ for (const existingImportDeclaration of existingImports) {
115
+ for (const importSpecifierCandidate of (_a = existingImportDeclaration.specifiers) !== null && _a !== void 0 ? _a : []) {
116
+ if (importSpecifierCandidate.type !== 'ImportSpecifier') {
117
+ continue;
118
+ }
119
+ existingNames.add((0, exports.getImportedName)(importSpecifierCandidate));
120
+ }
121
+ }
122
+ const existingImport = existingImports.find((candidateImportDeclaration) => !hasNamespaceSpecifier(candidateImportDeclaration));
123
+ if (existingImport) {
124
+ for (const importedName of importedNames) {
125
+ if (existingNames.has(importedName)) {
126
+ continue;
127
+ }
128
+ existingImport.specifiers = [
129
+ ...((_b = existingImport.specifiers) !== null && _b !== void 0 ? _b : []),
130
+ b.importSpecifier(b.identifier(importedName)),
131
+ ];
132
+ existingNames.add(importedName);
133
+ }
134
+ return;
135
+ }
136
+ const specifiers = [...importedNames]
137
+ .filter((importedName) => !existingNames.has(importedName))
138
+ .map((importedName) => b.importSpecifier(b.identifier(importedName)));
139
+ if (specifiers.length === 0) {
140
+ return;
141
+ }
142
+ const importDeclaration = b.importDeclaration(specifiers, b.stringLiteral(sourcePath));
143
+ (0, exports.insertImportDeclaration)(ast, importDeclaration);
144
+ };
145
+ exports.ensureNamedImports = ensureNamedImports;