chore: refactor codemod for better readability

This commit is contained in:
Christian Capeans 2024-01-19 11:23:52 +01:00
parent 0ef18ac1b5
commit 64888d3fa8
2 changed files with 142 additions and 254 deletions

View File

@ -1,156 +0,0 @@
import { Transform, ASTPath, Property, ArrowFunctionExpression } from 'jscodeshift';
import path from 'node:path';
/**
* This codemod only affects users that are using the `aws-s3` provider.
* It will wrap the `accessKeyId` and `secretAccessKey` properties inside a `credentials` object.
*/
const transform: Transform = (file, api) => {
// Check if the current file is 'config/plugins.js'
const cwd = process.cwd();
const jsPluginsPath = path.join(cwd, 'config/plugins.js');
const tsPluginsPath = path.join(cwd, 'config/plugins.ts');
if (file.path !== jsPluginsPath && file.path !== tsPluginsPath) {
return file.source;
}
const { j } = api;
const root = j(file.source);
root
.find(j.ArrowFunctionExpression)
.forEach((arrowFunctionPath: ASTPath<ArrowFunctionExpression>) => {
const body = arrowFunctionPath.node.body;
if (j.ObjectExpression.check(body)) {
const uploadProperty = body.properties.find(
(prop) =>
j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === 'upload'
);
if (j.Property.check(uploadProperty) && j.ObjectExpression.check(uploadProperty.value)) {
const configProperty = uploadProperty.value.properties.find(
(prop) =>
j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === 'config'
);
if (j.Property.check(configProperty) && j.ObjectExpression.check(configProperty.value)) {
const providerProperty = configProperty.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'provider' &&
j.Literal.check(prop.value) &&
prop.value.value === 'aws-s3'
);
if (providerProperty) {
const providerOptions = configProperty.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'providerOptions'
);
if (
j.Property.check(providerOptions) &&
j.ObjectExpression.check(providerOptions.value)
) {
let accessKeyId: Property | undefined;
let secretAccessKey: Property | undefined;
// Check for accessKeyId and secretAccessKey directly under providerOptions
const directAccessKeyId = providerOptions.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'accessKeyId'
) as Property;
const directSecretAccessKey = providerOptions.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'secretAccessKey'
) as Property;
let s3Options = providerOptions.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 's3Options'
);
if (!s3Options) {
// Create s3Options if it doesn't exist
s3Options = j.property('init', j.identifier('s3Options'), j.objectExpression([]));
providerOptions.value.properties.push(s3Options);
}
if (directAccessKeyId && directSecretAccessKey) {
accessKeyId = directAccessKeyId;
secretAccessKey = directSecretAccessKey;
// Remove these properties from providerOptions
providerOptions.value.properties = providerOptions.value.properties.filter(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
} else if (
j.Property.check(s3Options) &&
j.ObjectExpression.check(s3Options.value)
) {
// Look inside s3Options
accessKeyId = s3Options.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'accessKeyId'
) as Property;
secretAccessKey = s3Options.value.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'secretAccessKey'
) as Property;
}
if (
accessKeyId &&
secretAccessKey &&
j.Property.check(s3Options) &&
j.ObjectExpression.check(s3Options.value)
) {
// Create the credentials object
const credentials = j.objectExpression([
j.property('init', j.identifier('accessKeyId'), accessKeyId.value),
j.property('init', j.identifier('secretAccessKey'), secretAccessKey.value),
]);
// Remove the old properties from s3Options
s3Options.value.properties = s3Options.value.properties.filter(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
// Add the new credentials object to s3Options
s3Options.value.properties.push(
j.property('init', j.identifier('credentials'), credentials)
);
}
}
}
}
}
}
});
return root.toSource();
};
export default transform;

View File

@ -1,6 +1,49 @@
import { Transform, ASTPath, Property } from 'jscodeshift'; import core, {
Transform,
ASTPath,
Property,
ArrowFunctionExpression,
ObjectExpression,
} from 'jscodeshift';
import path from 'node:path'; import path from 'node:path';
const findUploadPropertyInBody = (j: core.JSCodeshift, body: ObjectExpression) => {
return body.properties.find(
(prop: any) =>
j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === 'upload'
);
};
const findConfigInUpload = (j: core.JSCodeshift, upload: ObjectExpression) => {
return upload.properties.find(
(prop) => j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === 'config'
);
};
const getProviderProperty = (j: core.JSCodeshift, config: ObjectExpression) => {
return config.properties.find(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name === 'provider' &&
j.Literal.check(prop.value) &&
prop.value.value === 'aws-s3'
);
};
const getProviderOptions = (j: core.JSCodeshift, config: ObjectExpression) => {
return config.properties.find(
(prop) =>
j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === 'providerOptions'
);
};
const getPropertyByKeyName = (j: core.JSCodeshift, object: ObjectExpression, keyName: string) => {
return object.properties.find(
(prop) => j.Property.check(prop) && j.Identifier.check(prop.key) && prop.key.name === keyName
) as Property;
};
/** /**
* This codemod only affects users that are using the `aws-s3` provider. * This codemod only affects users that are using the `aws-s3` provider.
* It will wrap the `accessKeyId` and `secretAccessKey` properties inside a `credentials` object. * It will wrap the `accessKeyId` and `secretAccessKey` properties inside a `credentials` object.
@ -8,116 +51,117 @@ import path from 'node:path';
const transform: Transform = (file, api) => { const transform: Transform = (file, api) => {
// Check if the current file is 'config/plugins.js' // Check if the current file is 'config/plugins.js'
const cwd = process.cwd(); const cwd = process.cwd();
const pluginsPath = path.join(cwd, 'config/plugins.js'); const jsPluginsPath = path.join(cwd, 'config/plugins.js');
const tsPluginsPath = path.join(cwd, 'config/plugins.ts');
if (file.path !== pluginsPath) { if (file.path !== jsPluginsPath && file.path !== tsPluginsPath) {
return file.source; return file.source;
} }
const { j } = api; const { j } = api;
const root = j(file.source); const root = j(file.source);
root.find(j.ArrowFunctionExpression).forEach((arrowFunctionPath: ASTPath<any>) => { root
const body = arrowFunctionPath.node.body; .find(j.ArrowFunctionExpression)
.forEach((arrowFunctionPath: ASTPath<ArrowFunctionExpression>) => {
const body = arrowFunctionPath.node.body;
if (body.type === 'ObjectExpression') { // Check that the body of the arrow function is an object
const uploadProperty = body.properties.find( if (!j.ObjectExpression.check(body)) {
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 'upload' return file.source;
}
const uploadProperty = findUploadPropertyInBody(j, body);
// Check that we found an upload property and that it is an object
if (!j.Property.check(uploadProperty) || !j.ObjectExpression.check(uploadProperty.value)) {
return file.source;
}
const configProperty = findConfigInUpload(j, uploadProperty.value);
if (!j.Property.check(configProperty) || !j.ObjectExpression.check(configProperty.value)) {
return file.source;
}
const providerProperty = getProviderProperty(j, configProperty.value);
// If there is not a provider property or it is not 'aws-s3', return the source
if (!providerProperty) {
return file.source;
}
const providerOptions = getProviderOptions(j, configProperty.value);
if (!j.Property.check(providerOptions) || !j.ObjectExpression.check(providerOptions.value)) {
return file.source;
}
let accessKeyId: Property | undefined;
let secretAccessKey: Property | undefined;
// Check for accessKeyId and secretAccessKey directly under providerOptions
const directAccessKeyId = getPropertyByKeyName(j, providerOptions.value, 'accessKeyId');
const directSecretAccessKey = getPropertyByKeyName(
j,
providerOptions.value,
'secretAccessKey'
); );
if (uploadProperty && uploadProperty.value.type === 'ObjectExpression') { let s3Options = getPropertyByKeyName(j, providerOptions.value, 's3Options');
const configProperty = uploadProperty.value.properties.find(
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 'config' if (!s3Options) {
// Create s3Options if it doesn't exist
s3Options = j.property('init', j.identifier('s3Options'), j.objectExpression([]));
providerOptions.value.properties.push(s3Options);
}
if (directAccessKeyId && directSecretAccessKey) {
accessKeyId = directAccessKeyId;
secretAccessKey = directSecretAccessKey;
// Remove these properties from providerOptions
providerOptions.value.properties = providerOptions.value.properties.filter(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
} else if (j.Property.check(s3Options) && j.ObjectExpression.check(s3Options.value)) {
// Look inside s3Options
accessKeyId = getPropertyByKeyName(j, s3Options.value, 'accessKeyId');
secretAccessKey = getPropertyByKeyName(j, s3Options.value, 'secretAccessKey');
}
if (
accessKeyId &&
secretAccessKey &&
j.Property.check(s3Options) &&
j.ObjectExpression.check(s3Options.value)
) {
// Create the credentials object
const credentials = j.objectExpression([
j.property('init', j.identifier('accessKeyId'), accessKeyId.value),
j.property('init', j.identifier('secretAccessKey'), secretAccessKey.value),
]);
// Remove the old properties from s3Options
s3Options.value.properties = s3Options.value.properties.filter(
(prop) =>
j.Property.check(prop) &&
j.Identifier.check(prop.key) &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
); );
if (configProperty && configProperty.value.type === 'ObjectExpression') { // Add the new credentials object to s3Options
const providerProperty = configProperty.value.properties.find( s3Options.value.properties.push(
(prop: Property) => j.property('init', j.identifier('credentials'), credentials)
prop.key.type === 'Identifier' && );
prop.key.name === 'provider' &&
prop.value.type === 'Literal' &&
prop.value.value === 'aws-s3'
);
if (providerProperty) {
const providerOptions = configProperty.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'providerOptions'
);
if (providerOptions && providerOptions.value.type === 'ObjectExpression') {
let accessKeyId: Property | undefined;
let secretAccessKey: Property | undefined;
// Check for accessKeyId and secretAccessKey directly under providerOptions
const directAccessKeyId = providerOptions.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'accessKeyId'
);
const directSecretAccessKey = providerOptions.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'secretAccessKey'
);
let s3Options = providerOptions.value.properties.find(
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 's3Options'
);
if (!s3Options) {
// Create s3Options if it doesn't exist
s3Options = j.property('init', j.identifier('s3Options'), j.objectExpression([]));
providerOptions.value.properties.push(s3Options);
}
if (directAccessKeyId && directSecretAccessKey) {
accessKeyId = directAccessKeyId;
secretAccessKey = directSecretAccessKey;
// Remove these properties from providerOptions
providerOptions.value.properties = providerOptions.value.properties.filter(
(prop: Property) =>
prop.key.type === 'Identifier' &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
} else if (s3Options.value.type === 'ObjectExpression') {
// Look inside s3Options
accessKeyId = s3Options.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'accessKeyId'
);
secretAccessKey = s3Options.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'secretAccessKey'
);
}
if (accessKeyId && secretAccessKey && s3Options.value.type === 'ObjectExpression') {
// Create the credentials object
const credentials = j.objectExpression([
j.property('init', j.identifier('accessKeyId'), accessKeyId.value),
j.property('init', j.identifier('secretAccessKey'), secretAccessKey.value),
]);
// Remove the old properties from s3Options
s3Options.value.properties = s3Options.value.properties.filter(
(prop: Property) =>
prop.key.type === 'Identifier' &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
// Add the new credentials object to s3Options
s3Options.value.properties.push(
j.property('init', j.identifier('credentials'), credentials)
);
}
}
}
}
} }
} });
});
return root.toSource(); return root.toSource();
}; };