Skip to content

Replace direct babel usage with magicast #126

Open
@AriPerkkio

Description

@AriPerkkio

Is your feature request related to a problem?

Currently CLI modifies user's astro.config.ts via AST transforms using Babel. This works really well but it quite heavy to maintain.

/**
* In the second pass, we search for a default export which is a call to `defineConfig`
* and we look for our `integrationId` that we just got from the `integrations` field.
*/
visit(ast, {
ExportDefaultDeclaration(path) {
if (!t.isCallExpression(path.node.declaration)) {
return;
}
const configObject = path.node.declaration.arguments[0];
if (!t.isObjectExpression(configObject)) {
throw new Error('TutorialKit is not part of the exported config');
}
const integrationsProp = configObject.properties.find((prop) => {
if (prop.type !== 'ObjectProperty') {
return false;
}
if (prop.key.type === 'Identifier') {
if (prop.key.name === 'integrations') {
return true;
}
}
if (prop.key.type === 'StringLiteral') {
if (prop.key.value === 'integrations') {
return true;
}
}
return false;
}) as t.ObjectProperty | undefined;
if (integrationsProp.value.type !== 'ArrayExpression') {
throw new Error('Unable to parse integrations in Astro config');
}
let integrationCall = integrationsProp.value.elements.find((expr) => {
return t.isCallExpression(expr) && t.isIdentifier(expr.callee) && expr.callee.name === integrationId.name;
}) as t.CallExpression | undefined;
// if the integration wasn't found we add it
if (!integrationCall) {
integrationCall = t.callExpression(integrationId, []);
integrationsProp.value.elements.push(integrationCall);
}
const integrationArgs = integrationCall.arguments;
// if `tutorialkit` is called as `tutorialkit()`
if (integrationArgs.length === 0) {
const objectArgs = fromValue(newTutorialKitArgs) as t.ObjectExpression;
if (objectArgs.properties.length > 0) {
integrationArgs.push(objectArgs);
}
return;
}
if (!t.isObjectExpression(integrationArgs[0])) {
throw new Error('Only updating an existing object literal as the config is supported');
}
// if `tutorialkit` is called with an object literal we update its existing properties
updateObject(newTutorialKitArgs, integrationArgs[0]);
},
});

Describe the solution you'd like.

Check if direct Babel usage could be replaced with magicast. It provides much nicer API to work with AST transforms. This package is also used by Vitest, where we modify user's vitest.config.ts. It's very similar to what TutorialKit does.

https://github.com/vitest-dev/vitest/blob/7012f8c12a3d0004e7e7651bbeee905ac9102098/packages/vitest/src/utils/coverage.ts#L349-L402

We should also add similar unit tests: https://github.com/vitest-dev/vitest/blob/main/test/coverage-test/test/threshold-auto-update.unit.test.ts

Describe alternatives you've considered.

Keep maintaining the direct Babel integration. It's reliable and does exactly what we need it to, but it's not as easy to maintain.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintenanceChange related to maintaining TutorialKit

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions