UNPKG

@nx/gradle

Version:

The Nx Plugin for Gradle allows Gradle tasks to be run through Nx

359 lines (358 loc) • 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.findVersionCatalogFiles = findVersionCatalogFiles; exports.updatePluginVersionInCatalogAst = updatePluginVersionInCatalogAst; exports.getPluginAliasFromCatalogAst = getPluginAliasFromCatalogAst; exports.extractPluginVersionFromCatalogAst = extractPluginVersionFromCatalogAst; exports.updateNxPluginVersionInCatalogsAst = updateNxPluginVersionInCatalogsAst; const devkit_1 = require("@nx/devkit"); const toml_eslint_parser_1 = require("toml-eslint-parser"); const versions_1 = require("./versions"); async function findVersionCatalogFiles(tree) { const versionCatalogPaths = []; const globFiles = await (0, devkit_1.globAsync)(tree, ['**/gradle/*.versions.toml']); for (const filePath of globFiles) { if (!versionCatalogPaths.includes(filePath)) { versionCatalogPaths.push(filePath); } } return versionCatalogPaths; } /** * Reconstructs TOML content from source text with selective replacements * based on AST node ranges. This preserves all original formatting. */ function reconstructTomlWithUpdates(sourceText, updates) { // Sort updates by start position in reverse order to apply from end to beginning const sortedUpdates = updates.sort((a, b) => b.start - a.start); let result = sourceText; for (const update of sortedUpdates) { result = result.slice(0, update.start) + update.replacement + result.slice(update.end); } return result; } /** * Finds a key-value pair in a TOML table by key name */ function findKeyValueInTable(table, keyName) { if (!table.body) return null; for (const item of table.body) { if (item.type === 'TOMLKeyValue') { if (getKeyName(item.key) === keyName) { return item; } } } return null; } /** * Gets the string representation of a TOML key */ function getKeyName(key) { if (key.type === 'TOMLKey' && key.keys && key.keys.length > 0) { // Handle TOMLKey type which contains an array of keys (for dotted keys like version.ref) return key.keys .map((k) => { if (k.type === 'TOMLBare') { return k.name; } else if (k.type === 'TOMLQuoted') { return k.value; } return ''; }) .join('.'); } else if (key.type === 'TOMLBare') { return key.name; } else if (key.type === 'TOMLQuoted') { return key.value; } return ''; } /** * Gets the string value from a TOML value node */ function getStringValue(value) { if (value.type === 'TOMLValue' && value.kind === 'string') { return value.value; } return null; } /** * Finds plugin configuration in the plugins table */ function findPluginConfig(pluginsTable, pluginName) { if (!pluginsTable.body) return null; for (const item of pluginsTable.body) { if (item.type === 'TOMLKeyValue') { const value = item.value; const alias = getKeyName(item.key); if (value.type === 'TOMLValue' && value.kind === 'string') { // Simple format: plugin = "id:version" const stringValue = value.value; if (stringValue.startsWith(`${pluginName}:`)) { return { keyValue: item, format: 'simple', alias }; } } else if (value.type === 'TOMLInlineTable') { // Object format: { id = "plugin.name", version = "1.0.0" } const idKeyValue = findKeyValueInTable(value, 'id'); if (idKeyValue) { const idValue = getStringValue(idKeyValue.value); if (idValue === pluginName) { return { keyValue: item, format: 'object', alias }; } } } } } return null; } /** * Finds the plugins table in the AST */ function findPluginsTable(ast) { // Look through all top-level elements for (const topLevel of ast.body) { if (topLevel.type === 'TOMLTopLevelTable') { // Look through the body of the top-level table for [plugins] table for (const item of topLevel.body) { if (item.type === 'TOMLTable' && item.key && item.key.keys) { const tableName = item.key.keys .map((key) => getKeyName(key)) .join('.'); if (tableName === 'plugins') { return item; } } } // If no [plugins] table found, check if there's a plugins key in the root table const pluginsKeyValue = findKeyValueInTable(topLevel, 'plugins'); if (pluginsKeyValue?.value.type === 'TOMLInlineTable') { return pluginsKeyValue.value; } } } return null; } /** * Finds the versions table in the AST */ function findVersionsTable(ast) { // Look through all top-level elements for (const topLevel of ast.body) { if (topLevel.type === 'TOMLTopLevelTable') { // Look through the body of the top-level table for [versions] table for (const item of topLevel.body) { if (item.type === 'TOMLTable' && item.key && item.key.keys) { const tableName = item.key.keys .map((key) => getKeyName(key)) .join('.'); if (tableName === 'versions') { return item; } } } } } return null; } /** * Updates a plugin version in a TOML catalog while preserving formatting */ function updatePluginVersionInCatalogAst(sourceText, pluginName, newVersion) { try { const ast = (0, toml_eslint_parser_1.parseTOML)(sourceText); const updates = []; const pluginsTable = findPluginsTable(ast); if (!pluginsTable) { return null; // No plugins table found } const pluginConfig = findPluginConfig(pluginsTable, pluginName); if (!pluginConfig) { return null; // Plugin not found } const { keyValue, format } = pluginConfig; if (format === 'simple') { // Update simple format: "plugin:version" -> "plugin:newVersion" const value = keyValue.value; const newValue = `${pluginName}:${newVersion}`; // Preserve the quote style const quote = value.style === 'basic' ? '"' : "'"; const replacement = `${quote}${newValue}${quote}`; updates.push({ start: value.range[0], end: value.range[1], replacement, }); } else if (format === 'object') { // Handle object format const inlineTable = keyValue.value; // First, try to find direct version const versionKeyValue = findKeyValueInTable(inlineTable, 'version'); if (versionKeyValue) { const versionValue = versionKeyValue.value; if (versionValue.type === 'TOMLValue' && versionValue.kind === 'string') { // Direct version update const quote = versionValue.style === 'basic' ? '"' : "'"; const replacement = `${quote}${newVersion}${quote}`; updates.push({ start: versionValue.range[0], end: versionValue.range[1], replacement, }); } } else { // Check for version.ref pattern - look for either quoted or unquoted key let versionRefKeyValue = findKeyValueInTable(inlineTable, 'version.ref'); if (!versionRefKeyValue) { // Try with quotes since TOML inline tables may require quoted keys for dotted keys versionRefKeyValue = findKeyValueInTable(inlineTable, '"version.ref"'); } if (versionRefKeyValue) { // This means we need to update the referenced version in the [versions] table const refValue = getStringValue(versionRefKeyValue.value); if (refValue) { const versionsTable = findVersionsTable(ast); if (versionsTable) { const referencedVersion = findKeyValueInTable(versionsTable, refValue); if (referencedVersion) { const refVersionValue = referencedVersion.value; if (refVersionValue.type === 'TOMLValue' && refVersionValue.kind === 'string') { const quote = refVersionValue.style === 'basic' ? '"' : "'"; const replacement = `${quote}${newVersion}${quote}`; updates.push({ start: refVersionValue.range[0], end: refVersionValue.range[1], replacement, }); } } } } } } } if (updates.length === 0) { return null; } return reconstructTomlWithUpdates(sourceText, updates); } catch (error) { console.error('Error parsing TOML with AST:', error); return null; } } /** * Gets the plugin alias from a version catalog for a given plugin ID * Returns the alias name (e.g., "nxProjectGraph") if found, null otherwise */ function getPluginAliasFromCatalogAst(sourceText, pluginName) { try { const ast = (0, toml_eslint_parser_1.parseTOML)(sourceText); const pluginsTable = findPluginsTable(ast); if (!pluginsTable) { return null; } const pluginConfig = findPluginConfig(pluginsTable, pluginName); if (!pluginConfig) { return null; } return pluginConfig.alias; } catch (error) { console.error('Error parsing TOML with AST:', error); return null; } } /** * Extracts plugin version from catalog using AST parsing */ function extractPluginVersionFromCatalogAst(sourceText, pluginName) { try { const ast = (0, toml_eslint_parser_1.parseTOML)(sourceText); const pluginsTable = findPluginsTable(ast); if (!pluginsTable) { return null; } const pluginConfig = findPluginConfig(pluginsTable, pluginName); if (!pluginConfig) { return null; } const { keyValue, format } = pluginConfig; if (format === 'simple') { // Extract from simple format: "plugin:version" const value = keyValue.value; const stringValue = value.value; return stringValue.split(':')[1] || null; } else if (format === 'object') { // Extract from object format const inlineTable = keyValue.value; // First, try to find direct version const versionKeyValue = findKeyValueInTable(inlineTable, 'version'); if (versionKeyValue) { return getStringValue(versionKeyValue.value); } // Check for version.ref pattern - look for either quoted or unquoted key let versionRefKeyValue = findKeyValueInTable(inlineTable, 'version.ref'); if (!versionRefKeyValue) { // Try with quotes since TOML inline tables may require quoted keys for dotted keys versionRefKeyValue = findKeyValueInTable(inlineTable, '"version.ref"'); } if (versionRefKeyValue) { const refValue = getStringValue(versionRefKeyValue.value); if (refValue) { const versionsTable = findVersionsTable(ast); if (versionsTable) { const referencedVersion = findKeyValueInTable(versionsTable, refValue); if (referencedVersion) { return getStringValue(referencedVersion.value); } } } } } return null; } catch (error) { console.error('Error parsing TOML with AST:', error); return null; } } /** * Updates Nx plugin version in all catalog files using AST-based approach */ async function updateNxPluginVersionInCatalogsAst(tree, expectedVersion) { const catalogFiles = await findVersionCatalogFiles(tree); let updated = false; for (const catalogPath of catalogFiles) { if (!tree.exists(catalogPath)) { continue; } const content = tree.read(catalogPath, 'utf-8'); if (!content) { continue; } const currentVersion = extractPluginVersionFromCatalogAst(content, versions_1.gradleProjectGraphPluginName); if (currentVersion && currentVersion !== expectedVersion) { const updatedContent = updatePluginVersionInCatalogAst(content, versions_1.gradleProjectGraphPluginName, expectedVersion); if (updatedContent) { tree.write(catalogPath, updatedContent); updated = true; } } } return updated; }