@nx/next
Version:
83 lines (82 loc) • 4.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateNextConfig = updateNextConfig;
const utils_1 = require("./utils");
const tsquery_1 = require("@phenomnomnominal/tsquery");
const ts = require("typescript");
function updateNextConfig(tree, updatedConfigFileContents, project, migrationLogs) {
const nextConfigPath = (0, utils_1.findNextConfigPath)(tree, project.root);
if (!nextConfigPath) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project ${project.projectName} does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.`,
});
return;
}
const nextConfigContents = tree.read(nextConfigPath, 'utf-8');
let ast = tsquery_1.tsquery.ast(nextConfigContents);
const reservedVarQuery = `
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=configValues]),
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=configuration]),
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=options])
`;
const matches = (0, tsquery_1.tsquery)(ast, reservedVarQuery);
if (matches.length > 0) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project (${project.projectName}) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.`,
});
return;
}
// Query to check for composePlugins in module.exports
const composePluginsQuery = `ExpressionStatement > BinaryExpression > CallExpression > CallExpression:has(Identifier[name=composePlugins])`;
const composePluginNode = (0, tsquery_1.tsquery)(ast, composePluginsQuery)[0];
if (!composePluginNode) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project ${project.projectName} does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.`,
});
return;
}
let lastRequireEndPosition = -1;
const findLastRequire = (node) => {
if (ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === 'require') {
lastRequireEndPosition = node.end;
}
ts.forEachChild(node, findLastRequire);
};
findLastRequire(ast);
let updatedCode = `
${nextConfigContents.slice(0, lastRequireEndPosition)}\n
${updatedConfigFileContents}\n\n
${nextConfigContents.slice(lastRequireEndPosition)}
`;
ast = tsquery_1.tsquery.ast(updatedCode);
const nextConfigNode = (0, tsquery_1.tsquery)(ast, 'VariableDeclaration:has(Identifier[name=nextConfig]) ObjectLiteralExpression')[0];
if (nextConfigNode) {
const nxNode = (0, tsquery_1.tsquery)(nextConfigNode, 'PropertyAssignment:has(Identifier[name=nx]) ObjectLiteralExpression')[0];
if (nxNode) {
const spread = ts.factory.createSpreadAssignment(ts.factory.createIdentifier('options'));
const updatedNxNode = ts.factory.updateObjectLiteralExpression(nxNode, ts.factory.createNodeArray([...nxNode['properties'], spread]));
const transformer = (context) => (rootNode) => {
function visit(node) {
if (node === nxNode) {
return updatedNxNode;
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
const result = ts.transform(ast, [transformer]);
const transformedSourceFile = result.transformed[0];
const printer = ts.createPrinter();
updatedCode = printer.printFile(transformedSourceFile);
}
tree.write(nextConfigPath, updatedCode);
}
}