@aws/nx-plugin 1.0.0-rc.47 → 1.0.0-rc.49
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.
- package/LICENSE-THIRD-PARTY +15 -0
- package/generators.json +7 -0
- package/migrations.json +5 -0
- package/package.json +4 -4
- package/src/mcp-server/dev-server.d.ts +1 -0
- package/src/mcp-server/dev-server.js +18 -0
- package/src/mcp-server/dev-server.js.map +1 -0
- package/src/mcp-server/guide-pipeline.js +1 -1
- package/src/mcp-server/guide-pipeline.js.map +1 -1
- package/src/mcp-server/server.js +2 -0
- package/src/mcp-server/server.js.map +1 -1
- package/src/mcp-server/tools/general-guidance.d.ts +1 -1
- package/src/mcp-server/tools/general-guidance.js +1 -0
- package/src/mcp-server/tools/general-guidance.js.map +1 -1
- package/src/mcp-server/tools/upgrade-workspace.d.ts +11 -0
- package/src/mcp-server/tools/upgrade-workspace.js +32 -0
- package/src/mcp-server/tools/upgrade-workspace.js.map +1 -0
- package/src/preset/__snapshots__/generator.spec.ts.snap +6 -0
- package/src/sdk/ts.d.ts +4 -2
- package/src/sdk/ts.js +4 -2
- package/src/sdk/ts.js.map +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +9 -4
- package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +1 -0
- package/src/ts/agent/files/ag-ui/index.ts.template +25 -9
- package/src/ts/agent/files/common/agent.ts.template +2 -1
- package/src/ts/agent/files/deploy/Dockerfile.template +7 -3
- package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +1 -0
- package/src/ts/agent/generator.js +2 -2
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +1 -0
- package/src/ts/mcp-server/files/Dockerfile.template +7 -3
- package/src/ts/mcp-server/generator.js +2 -2
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/nx-migration/files/migration.spec.ts.template +26 -0
- package/src/ts/nx-migration/files/migration.ts.template +55 -0
- package/src/ts/nx-migration/files/prompt.md.template +46 -0
- package/src/ts/nx-migration/generator.d.ts +24 -0
- package/src/ts/nx-migration/generator.js +122 -0
- package/src/ts/nx-migration/generator.js.map +1 -0
- package/src/ts/nx-migration/schema.d.js +6 -0
- package/src/ts/nx-migration/schema.d.js.map +1 -0
- package/src/ts/nx-migration/schema.d.ts +13 -0
- package/src/ts/nx-migration/schema.json +63 -0
- package/src/ts/nx-plugin/utils.d.ts +21 -1
- package/src/ts/nx-plugin/utils.js +46 -35
- package/src/ts/nx-plugin/utils.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +11 -3
- package/src/ts/rdb/files/Dockerfile.template +5 -1
- package/src/ts/rdb/files/src/migration-handler.ts.template +3 -1
- package/src/ts/rdb/generator.js +2 -2
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/utils/agent-connection/agent-connection.js +4 -0
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-connection/files/core-strands/base/tool-errors-strands.ts.template +22 -0
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +19 -1
- package/src/utils/commands.d.ts +4 -3
- package/src/utils/commands.js +6 -2
- package/src/utils/commands.js.map +1 -1
- package/src/utils/docker.d.ts +8 -0
- package/src/utils/docker.js +8 -1
- package/src/utils/docker.js.map +1 -1
- package/src/utils/format.js +54 -25
- package/src/utils/format.js.map +1 -1
- package/src/utils/init.js +7 -2
- package/src/utils/init.js.map +1 -1
- package/src/utils/mcp.d.ts +9 -0
- package/src/utils/mcp.js +9 -1
- package/src/utils/mcp.js.map +1 -1
- package/src/utils/migration-versions.d.ts +95 -0
- package/src/utils/migration-versions.js +128 -0
- package/src/utils/migration-versions.js.map +1 -0
- package/src/utils/nx.d.ts +18 -0
- package/src/utils/nx.js +24 -1
- package/src/utils/nx.js.map +1 -1
- package/src/utils/test-git.d.ts +39 -0
- package/src/utils/test-git.js +117 -0
- package/src/utils/test-git.js.map +1 -0
- package/src/utils/versions.d.ts +4 -1
- package/src/utils/versions.js +10 -2
- package/src/utils/versions.js.map +1 -1
- package/src/bin/aws-nx-mcp.d.ts +0 -2
- package/src/bin/aws-nx-mcp.js +0 -14
- package/src/bin/aws-nx-mcp.js.map +0 -1
package/src/utils/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/format.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Biome } from '@biomejs/js-api/nodejs';\nimport { getProjects, type Tree } from '@nx/devkit';\nimport { execFileSync, execSync } from 'child_process';\nimport { existsSync, readFileSync } from 'fs';\nimport { createRequire } from 'module';\nimport path from 'path';\nimport { uvxCommand } from './py';\nimport { readToml } from './toml';\nimport { TS_VERSIONS } from './versions';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * The biome.json vended into a new workspace. The pnpm catalog resolver is only\n * included on pnpm workspaces, since `experimentalPnpmCatalogs` is Biome's only\n * catalog resolver and reads `pnpm-workspace.yaml` exclusively — it does nothing\n * for yarn or bun catalogs, so vending it there would be misleading.\n */\nexport const getDefaultBiomeConfig = (tree: Tree) => ({\n $schema: `https://biomejs.dev/schemas/${TS_VERSIONS['@biomejs/biome']}/schema.json`,\n root: true,\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n lineWidth: 80,\n },\n javascript: {\n formatter: {\n quoteStyle: 'single',\n trailingCommas: 'all',\n },\n // Resolve `catalog:` versions from pnpm-workspace.yaml (pnpm workspaces only).\n ...(tree.exists('pnpm-workspace.yaml')\n ? { resolver: { experimentalPnpmCatalogs: true } }\n : {}),\n },\n css: {\n formatter: {\n quoteStyle: 'single',\n },\n linter: {\n enabled: false,\n },\n },\n linter: {\n enabled: true,\n rules: {\n preset: 'none',\n correctness: {\n // Every project must declare the third-party dependencies its source\n // code imports in its own package.json.\n noUndeclaredDependencies: 'error',\n },\n },\n },\n assist: {\n actions: {\n source: {\n organizeImports: 'on',\n },\n },\n },\n files: {\n includes: [\n '**',\n '!**/dist',\n '!**/out-tsc',\n '!**/node_modules',\n '!**/.nx',\n '!**/.venv',\n // GritQL codemod cache written by generators — its sample sources\n // otherwise pollute a bare `biome check .` with parse errors.\n '!**/.grit',\n '!**/*.css',\n '!**/*.gen.*',\n '!**/generated/**',\n '!**/tsconfig*.json',\n ],\n },\n // Config files, build scripts and tests use root tooling rather than\n // declaring it per-project, so the undeclared-dependency rule is off for them.\n overrides: [\n {\n includes: [\n '**/*.config.{ts,mts,cts,js,mjs,cjs}',\n '**/*.{spec,test}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}',\n '**/*.stories.{ts,tsx}',\n ],\n linter: {\n rules: {\n correctness: {\n noUndeclaredDependencies: 'off',\n },\n },\n },\n },\n ],\n});\n\nconst BIOME_FORMATTABLE_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n '.json',\n '.jsonc',\n '.css',\n]);\n\n/** Matches `tsconfig.json` and variants like `tsconfig.lib.json`. */\nconst isTsConfig = (filePath: string): boolean =>\n /(^|\\/)tsconfig[^/]*\\.json$/.test(filePath);\n\n/**\n * Format files in the given directory within the tree.\n * Handles both TypeScript/JavaScript/JSON (via biome) and Python (via ruff) files.\n * See https://github.com/nrwl/nx/blob/4cd640a9187954505d12de5b6d76a90d8ce4c2eb/packages/devkit/src/generators/format-files.ts#L11\n */\nexport async function formatFilesInSubtree(\n tree: Tree,\n dir?: string,\n): Promise<void> {\n const changedFiles = tree\n .listChanges()\n .filter((file) => file.type !== 'DELETE')\n .filter((file) => (dir ? file.path.startsWith(dir) : true));\n\n const pyFiles = changedFiles.filter((file) => file.path.endsWith('.py'));\n const otherFiles = changedFiles.filter(\n (file) =>\n BIOME_FORMATTABLE_EXTENSIONS.has(path.extname(file.path)) &&\n // tsconfigs are not biome-managed: they're excluded from the vended\n // format target (Nx's typescript-sync rewrites them without formatting),\n // so formatting them at generation would only diverge from the form\n // written on later runs. Leave them as updateJson/writeJson emit them so\n // repeated generation stays idempotent.\n !isTsConfig(file.path),\n );\n\n // Resolve each project's ruff settings (module names, line-length) so files\n // are formatted to match the on-disk build (see getPythonProjectRuffConfigs).\n const pythonProjectConfigs = pyFiles.length\n ? getPythonProjectRuffConfigs(tree)\n : [];\n\n // Format Python files with ruff (lint fixes + formatting)\n for (const file of pyFiles) {\n try {\n const content = ruffFixAndFormat(\n file.content.toString('utf-8'),\n file.path,\n hasRuffConfigOnDisk(tree, file.path),\n getOwningProjectRuffConfig(file.path, pythonProjectConfigs),\n );\n tree.write(file.path, content);\n } catch {\n // Silently skip ruff formatting failures\n }\n }\n\n if (otherFiles.length === 0) return;\n\n // Use the workspace's own Biome CLI (its version and config) when biome.json\n // exists on disk; otherwise format via the bundled library API with the\n // in-memory tree config. The CLI path does not see in-tree config changes.\n if (existsSync(path.join(tree.root, 'biome.json'))) {\n formatWithBiomeCli(tree, otherFiles);\n } else {\n formatWithBiomeApi(tree, otherFiles);\n }\n}\n\n/**\n * Format files via the workspace's Biome CLI, run from the workspace root so it\n * discovers the on-disk biome.json.\n */\nfunction formatWithBiomeCli(\n tree: Tree,\n files: { path: string; content: Buffer | null }[],\n): void {\n const biome = getBiomeCommand(tree.root);\n if (!biome) {\n // Fall back to the library API if the CLI cannot be resolved\n formatWithBiomeApi(tree, files);\n return;\n }\n\n for (const file of files) {\n try {\n const content = execFileSync(\n biome.command,\n [...biome.args, 'format', `--stdin-file-path=${file.path}`],\n {\n input: file.content?.toString('utf-8') ?? '',\n encoding: 'utf-8',\n cwd: tree.root,\n stdio: ['pipe', 'pipe', 'pipe'],\n },\n );\n tree.write(file.path, content);\n } catch {\n // Leave individual files that fail to format untouched\n }\n }\n}\n\n/**\n * Format files via the bundled Biome library API, applying the in-memory tree\n * config.\n */\nfunction formatWithBiomeApi(\n tree: Tree,\n files: { path: string; content: Buffer | null }[],\n): void {\n try {\n const biome = new Biome();\n const { projectKey } = biome.openProject();\n // Apply the workspace biome.json if it exists in the tree, otherwise the defaults.\n const treeConfig = tree.read('biome.json', 'utf-8');\n biome.applyConfiguration(\n projectKey,\n treeConfig ? JSON.parse(treeConfig) : getDefaultBiomeConfig(tree),\n );\n\n for (const file of files) {\n try {\n const { content } = biome.formatContent(\n projectKey,\n file.content?.toString('utf-8') ?? '',\n { filePath: file.path },\n );\n tree.write(file.path, content);\n } catch {\n // Leave individual files that fail to format untouched\n }\n }\n } catch {\n // Silently skip formatting failures\n }\n}\n\ninterface BiomeCommand {\n command: string;\n args: string[];\n}\n\n/**\n * Resolve the `@biomejs/biome` CLI from the user's workspace, falling back to a\n * `biome` binary on the PATH.\n */\nconst _biomeCommands = new Map<string, BiomeCommand | null>();\nfunction getBiomeCommand(root: string): BiomeCommand | undefined {\n if (_biomeCommands.has(root)) {\n return _biomeCommands.get(root) ?? undefined;\n }\n\n // Run via node for cross-platform execution of the bin shim.\n try {\n const pkgJsonPath = require.resolve('@biomejs/biome/package.json', {\n paths: [root, import.meta.dirname],\n });\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n const binRelative =\n typeof pkgJson.bin === 'string' ? pkgJson.bin : pkgJson.bin?.biome;\n if (binRelative) {\n const binPath = path.join(path.dirname(pkgJsonPath), binRelative);\n const command = { command: process.execPath, args: [binPath] };\n _biomeCommands.set(root, command);\n return command;\n }\n } catch {\n // Fall back to a biome binary on the PATH\n }\n\n try {\n execSync('biome --version', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n const command = { command: 'biome', args: [] };\n _biomeCommands.set(root, command);\n return command;\n } catch {\n _biomeCommands.set(root, null);\n return undefined;\n }\n}\n\n/**\n * Find the ruff command: `uvx --from ruff==<version> ruff`. uvx works\n * regardless of workspace resolution state (unlike `uv run ruff`, which fails\n * while installs are deferred), and the version pin matches the project's\n * `format` target (PY_VERSIONS) so generation and check format identically.\n * Only a successful probe is cached — ruff can become available mid-run in the\n * long-lived Nx daemon, so a cached failure would skip formatting thereafter.\n */\nlet _ruffCommand: string | undefined;\nfunction getRuffCommand(): string | undefined {\n if (_ruffCommand) {\n return _ruffCommand;\n }\n const cmd = uvxCommand('ruff');\n try {\n execSync(`${cmd} --version`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n _ruffCommand = cmd;\n return cmd;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Whether ruff would discover a config on disk for a file, by walking from its\n * directory up to the workspace root looking for `.ruff.toml`, `ruff.toml`, or a\n * `pyproject.toml` with a `[tool.ruff]` section — the same files ruff itself\n * resolves. The walk stops at `tree.root` so a stray config in a parent of the\n * workspace (or the home directory) is never treated as the project's. Used to\n * decide whether to nudge ruff towards import sorting (see\n * {@link ruffFixAndFormat}).\n */\nfunction hasRuffConfigOnDisk(tree: Tree, filePath: string): boolean {\n const root = path.resolve(tree.root);\n let dir = path.resolve(root, path.dirname(filePath));\n while (true) {\n if (\n existsSync(path.join(dir, '.ruff.toml')) ||\n existsSync(path.join(dir, 'ruff.toml'))\n ) {\n return true;\n }\n const pyproject = path.join(dir, 'pyproject.toml');\n if (\n existsSync(pyproject) &&\n readFileSync(pyproject, 'utf-8').includes('[tool.ruff')\n ) {\n return true;\n }\n const parent = path.dirname(dir);\n // Stop once the workspace root has been checked (or we hit the FS root).\n if (dir === root || parent === dir) {\n return false;\n }\n dir = parent;\n }\n}\n\ninterface PythonProjectRuffConfig {\n /** Project root, normalised to use forward slashes. */\n readonly root: string;\n /** Top-level importable module names declared by the project. */\n readonly modules: string[];\n /** The project's `[tool.ruff].line-length`, if set. */\n readonly lineLength?: number;\n /**\n * Ruff `target-version` (eg `py314`) derived from `[project].requires-python`.\n * Generation formats via stdin with no pyproject, so it must be passed\n * explicitly — ruff's formatting differs by target.\n */\n readonly targetVersion?: string;\n}\n\n/**\n * Derive ruff's `target-version` (eg `py314`) from a PEP 508\n * `requires-python` specifier (eg `>=3.14`). Ruff targets the minimum\n * supported version, so take the lowest `major.minor` mentioned.\n */\nexport const requiresPythonToRuffTarget = (\n requiresPython: unknown,\n): string | undefined => {\n if (typeof requiresPython !== 'string') {\n return undefined;\n }\n let min: { major: number; minor: number } | undefined;\n for (const match of requiresPython.matchAll(/(\\d+)\\.(\\d+)/g)) {\n const major = Number(match[1]);\n const minor = Number(match[2]);\n if (\n !min ||\n major < min.major ||\n (major === min.major && minor < min.minor)\n ) {\n min = { major, minor };\n }\n }\n return min ? `py${min.major}${min.minor}` : undefined;\n};\n\n/**\n * Map each Nx project with a `pyproject.toml` to the ruff settings the on-disk\n * build enforces for it: its top-level module names (from\n * `[tool.hatch.build.targets.wheel].packages`) and its `[tool.ruff].line-length`.\n */\nfunction getPythonProjectRuffConfigs(tree: Tree): PythonProjectRuffConfig[] {\n const configs: PythonProjectRuffConfig[] = [];\n\n for (const project of getProjects(tree).values()) {\n const pyprojectPath = path.join(project.root, 'pyproject.toml');\n if (tree.exists(pyprojectPath)) {\n try {\n const pyproject = readToml(tree, pyprojectPath) as any;\n const wheelPackages: unknown =\n pyproject?.tool?.hatch?.build?.targets?.wheel?.packages;\n // Record the top-level module segment (`pkg/sub` -> `pkg`), which is\n // all `known-first-party` keys off.\n const modules = Array.isArray(wheelPackages)\n ? wheelPackages\n .filter((pkg): pkg is string => typeof pkg === 'string' && !!pkg)\n .map((pkg) => pkg.split('/')[0])\n : [];\n const lineLength: unknown = pyproject?.tool?.ruff?.['line-length'];\n const targetVersion = requiresPythonToRuffTarget(\n pyproject?.project?.['requires-python'],\n );\n if (modules.length || typeof lineLength === 'number' || targetVersion) {\n configs.push({\n root: project.root.split(path.sep).join('/'),\n modules,\n lineLength: typeof lineLength === 'number' ? lineLength : undefined,\n targetVersion,\n });\n }\n } catch {\n // Skip projects whose pyproject.toml cannot be parsed\n }\n }\n }\n\n return configs;\n}\n\n/**\n * Resolve the ruff config for the project that owns a file (the project with\n * the longest root that is a prefix of the file path). Ruff runs per-project on\n * disk, so a file's settings come from its own project — only its own module is\n * first-party (sibling workspace packages are third-party) and its own\n * line-length applies — and scoping this way keeps in-tree formatting\n * consistent with the on-disk build.\n */\nfunction getOwningProjectRuffConfig(\n filePath: string,\n configs: PythonProjectRuffConfig[],\n): PythonProjectRuffConfig | undefined {\n let owner: PythonProjectRuffConfig | undefined;\n for (const config of configs) {\n if (\n (filePath === config.root || filePath.startsWith(`${config.root}/`)) &&\n (!owner || config.root.length > owner.root.length)\n ) {\n owner = config;\n }\n }\n return owner;\n}\n\n/**\n * Run ruff check --fix and ruff format on Python file content via stdin.\n * Applies all configured lint fixes (including import sorting) and formatting.\n *\n * When no ruff config exists on disk (`hasConfig` false) ruff falls back to its\n * defaults, which omit isort — but generated projects enable rule `I` and their\n * build fails on unsorted imports (I001). In that case we add `--extend-select\n * I` so import sorting matches what the build enforces. When a config does\n * exist we defer to it entirely, honouring the user's rule selection.\n *\n * `projectConfig` carries the owning project's ruff settings, which ruff cannot\n * detect from the filesystem during generation because the project lives only\n * in the tree. We pass them via `--config` so in-tree formatting matches the\n * on-disk build: `known-first-party` (the project's own modules) keeps its\n * imports in their own group, and `line-length` keeps wrapping consistent (the\n * generated config raises it above ruff's default of 88). These are additive to\n * any on-disk config, so they are safe to pass regardless of `hasConfig`.\n */\nfunction ruffFixAndFormat(\n content: string,\n filePath: string,\n hasConfig: boolean,\n projectConfig?: PythonProjectRuffConfig,\n): string {\n const ruff = getRuffCommand();\n if (!ruff) return content;\n\n const extendSelect = hasConfig ? '' : ' --extend-select I';\n const configArgs: string[] = [];\n if (projectConfig?.modules.length) {\n configArgs.push(\n `lint.isort.known-first-party = ${JSON.stringify(projectConfig.modules)}`,\n );\n }\n if (typeof projectConfig?.lineLength === 'number') {\n configArgs.push(`line-length = ${projectConfig.lineLength}`);\n }\n if (projectConfig?.targetVersion) {\n configArgs.push(`target-version = \"${projectConfig.targetVersion}\"`);\n }\n const config = configArgs\n .map((arg) => ` --config ${JSON.stringify(arg)}`)\n .join('');\n\n // First apply lint fixes (import sorting, unused imports, etc.)\n try {\n const result = execSync(\n `${ruff} check --fix${extendSelect}${config} --stdin-filename ${filePath} -`,\n { input: content, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n );\n content = result;\n } catch (e: any) {\n // ruff check exits non-zero when it finds unfixable issues,\n // but stdout still contains the fixed content\n if (e.stdout) {\n content = e.stdout;\n }\n }\n\n // Then apply formatting\n try {\n content = execSync(\n `${ruff} format${config} --stdin-filename ${filePath} -`,\n {\n input: content,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n },\n );\n } catch {\n // Fall through with whatever content we have\n }\n\n return content;\n}\n"],"names":["Biome","getProjects","execFileSync","execSync","existsSync","readFileSync","createRequire","path","uvxCommand","readToml","TS_VERSIONS","require","url","getDefaultBiomeConfig","tree","$schema","root","formatter","enabled","indentStyle","indentWidth","lineWidth","javascript","quoteStyle","trailingCommas","exists","resolver","experimentalPnpmCatalogs","css","linter","rules","preset","correctness","noUndeclaredDependencies","assist","actions","source","organizeImports","files","includes","overrides","BIOME_FORMATTABLE_EXTENSIONS","Set","isTsConfig","filePath","test","formatFilesInSubtree","dir","changedFiles","listChanges","filter","file","type","startsWith","pyFiles","endsWith","otherFiles","has","extname","pythonProjectConfigs","length","getPythonProjectRuffConfigs","content","ruffFixAndFormat","toString","hasRuffConfigOnDisk","getOwningProjectRuffConfig","write","join","formatWithBiomeCli","formatWithBiomeApi","biome","getBiomeCommand","command","args","input","encoding","cwd","stdio","projectKey","openProject","treeConfig","read","applyConfiguration","JSON","parse","formatContent","_biomeCommands","Map","get","undefined","pkgJsonPath","resolve","paths","dirname","pkgJson","binRelative","bin","binPath","process","execPath","set","_ruffCommand","getRuffCommand","cmd","pyproject","parent","requiresPythonToRuffTarget","requiresPython","min","match","matchAll","major","Number","minor","configs","project","values","pyprojectPath","wheelPackages","tool","hatch","build","targets","wheel","packages","modules","Array","isArray","pkg","map","split","lineLength","ruff","targetVersion","push","sep","owner","config","hasConfig","projectConfig","extendSelect","configArgs","stringify","arg","result","e","stdout"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/format.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Biome } from '@biomejs/js-api/nodejs';\nimport { getProjects, type Tree } from '@nx/devkit';\nimport {\n type ExecSyncOptionsWithStringEncoding,\n execFileSync,\n execSync,\n} from 'child_process';\nimport { existsSync, readFileSync } from 'fs';\nimport { createRequire } from 'module';\nimport path from 'path';\nimport { uvxCommand } from './py';\nimport { readToml } from './toml';\nimport { TS_VERSIONS } from './versions';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * The biome.json vended into a new workspace. The pnpm catalog resolver is only\n * included on pnpm workspaces, since `experimentalPnpmCatalogs` is Biome's only\n * catalog resolver and reads `pnpm-workspace.yaml` exclusively — it does nothing\n * for yarn or bun catalogs, so vending it there would be misleading.\n */\nexport const getDefaultBiomeConfig = (tree: Tree) => ({\n $schema: `https://biomejs.dev/schemas/${TS_VERSIONS['@biomejs/biome']}/schema.json`,\n root: true,\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n lineWidth: 80,\n },\n javascript: {\n formatter: {\n quoteStyle: 'single',\n trailingCommas: 'all',\n },\n // Resolve `catalog:` versions from pnpm-workspace.yaml (pnpm workspaces only).\n ...(tree.exists('pnpm-workspace.yaml')\n ? { resolver: { experimentalPnpmCatalogs: true } }\n : {}),\n },\n css: {\n formatter: {\n quoteStyle: 'single',\n },\n linter: {\n enabled: false,\n },\n },\n linter: {\n enabled: true,\n rules: {\n preset: 'none',\n correctness: {\n // Every project must declare the third-party dependencies its source\n // code imports in its own package.json.\n noUndeclaredDependencies: 'error',\n },\n },\n },\n assist: {\n actions: {\n source: {\n organizeImports: 'on',\n },\n },\n },\n files: {\n includes: [\n '**',\n '!**/dist',\n '!**/out-tsc',\n '!**/node_modules',\n '!**/.nx',\n '!**/.venv',\n // GritQL codemod cache written by generators — its sample sources\n // otherwise pollute a bare `biome check .` with parse errors.\n '!**/.grit',\n '!**/*.css',\n '!**/*.gen.*',\n '!**/generated/**',\n '!**/tsconfig*.json',\n ],\n },\n // Config files, build scripts and tests use root tooling rather than\n // declaring it per-project, so the undeclared-dependency rule is off for them.\n overrides: [\n {\n includes: [\n '**/*.config.{ts,mts,cts,js,mjs,cjs}',\n '**/*.{spec,test}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}',\n '**/*.stories.{ts,tsx}',\n ],\n linter: {\n rules: {\n correctness: {\n noUndeclaredDependencies: 'off',\n },\n },\n },\n },\n ],\n});\n\nconst BIOME_FORMATTABLE_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n '.json',\n '.jsonc',\n '.css',\n]);\n\n/** Matches `tsconfig.json` and variants like `tsconfig.lib.json`. */\nconst isTsConfig = (filePath: string): boolean =>\n /(^|\\/)tsconfig[^/]*\\.json$/.test(filePath);\n\n/**\n * Format files in the given directory within the tree.\n * Handles both TypeScript/JavaScript/JSON (via biome) and Python (via ruff) files.\n * See https://github.com/nrwl/nx/blob/4cd640a9187954505d12de5b6d76a90d8ce4c2eb/packages/devkit/src/generators/format-files.ts#L11\n */\nexport async function formatFilesInSubtree(\n tree: Tree,\n dir?: string,\n): Promise<void> {\n const changedFiles = tree\n .listChanges()\n .filter((file) => file.type !== 'DELETE')\n .filter((file) => (dir ? file.path.startsWith(dir) : true));\n\n const pyFiles = changedFiles.filter((file) => file.path.endsWith('.py'));\n const otherFiles = changedFiles.filter(\n (file) =>\n BIOME_FORMATTABLE_EXTENSIONS.has(path.extname(file.path)) &&\n // tsconfigs are not biome-managed: they're excluded from the vended\n // format target (Nx's typescript-sync rewrites them without formatting),\n // so formatting them at generation would only diverge from the form\n // written on later runs. Leave them as updateJson/writeJson emit them so\n // repeated generation stays idempotent.\n !isTsConfig(file.path),\n );\n\n // Resolve each project's ruff settings (module names, line-length) so files\n // are formatted to match the on-disk build (see getPythonProjectRuffConfigs).\n const pythonProjectConfigs = pyFiles.length\n ? getPythonProjectRuffConfigs(tree)\n : [];\n\n // Run ruff from the workspace root so it resolves the same on-disk config\n // hasRuffConfigOnDisk probed for. An in-memory tree has no root on disk, in\n // which case there is no config to find and the process cwd is left alone.\n const ruffCwd =\n pyFiles.length && existsSync(tree.root) ? tree.root : undefined;\n\n // Format Python files with ruff (lint fixes + formatting)\n for (const file of pyFiles) {\n try {\n const content = ruffFixAndFormat(\n file.content.toString('utf-8'),\n file.path,\n hasRuffConfigOnDisk(tree, file.path),\n ruffCwd,\n getOwningProjectRuffConfig(file.path, pythonProjectConfigs),\n );\n tree.write(file.path, content);\n } catch {\n // Silently skip ruff formatting failures\n }\n }\n\n if (otherFiles.length === 0) return;\n\n // Use the workspace's own Biome CLI (its version and config) when biome.json\n // exists on disk; otherwise format via the bundled library API with the\n // in-memory tree config. The CLI path does not see in-tree config changes.\n if (existsSync(path.join(tree.root, 'biome.json'))) {\n formatWithBiomeCli(tree, otherFiles);\n } else {\n formatWithBiomeApi(tree, otherFiles);\n }\n}\n\n/**\n * Format files via the workspace's Biome CLI, run from the workspace root so it\n * discovers the on-disk biome.json.\n */\nfunction formatWithBiomeCli(\n tree: Tree,\n files: { path: string; content: Buffer | null }[],\n): void {\n const biome = getBiomeCommand(tree.root);\n if (!biome) {\n // Fall back to the library API if the CLI cannot be resolved\n formatWithBiomeApi(tree, files);\n return;\n }\n\n for (const file of files) {\n try {\n const content = execFileSync(\n biome.command,\n [...biome.args, 'format', `--stdin-file-path=${file.path}`],\n {\n input: file.content?.toString('utf-8') ?? '',\n encoding: 'utf-8',\n cwd: tree.root,\n stdio: ['pipe', 'pipe', 'pipe'],\n },\n );\n tree.write(file.path, content);\n } catch {\n // Leave individual files that fail to format untouched\n }\n }\n}\n\n/**\n * Format files via the bundled Biome library API, applying the in-memory tree\n * config.\n */\nfunction formatWithBiomeApi(\n tree: Tree,\n files: { path: string; content: Buffer | null }[],\n): void {\n try {\n const biome = new Biome();\n const { projectKey } = biome.openProject();\n // Apply the workspace biome.json if it exists in the tree, otherwise the defaults.\n const treeConfig = tree.read('biome.json', 'utf-8');\n biome.applyConfiguration(\n projectKey,\n treeConfig ? JSON.parse(treeConfig) : getDefaultBiomeConfig(tree),\n );\n\n for (const file of files) {\n try {\n const { content } = biome.formatContent(\n projectKey,\n file.content?.toString('utf-8') ?? '',\n { filePath: file.path },\n );\n tree.write(file.path, content);\n } catch {\n // Leave individual files that fail to format untouched\n }\n }\n } catch {\n // Silently skip formatting failures\n }\n}\n\ninterface BiomeCommand {\n command: string;\n args: string[];\n}\n\n/**\n * Resolve the `@biomejs/biome` CLI from the user's workspace, falling back to a\n * `biome` binary on the PATH.\n */\nconst _biomeCommands = new Map<string, BiomeCommand | null>();\nfunction getBiomeCommand(root: string): BiomeCommand | undefined {\n if (_biomeCommands.has(root)) {\n return _biomeCommands.get(root) ?? undefined;\n }\n\n // Run via node for cross-platform execution of the bin shim.\n try {\n const pkgJsonPath = require.resolve('@biomejs/biome/package.json', {\n paths: [root, import.meta.dirname],\n });\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n const binRelative =\n typeof pkgJson.bin === 'string' ? pkgJson.bin : pkgJson.bin?.biome;\n if (binRelative) {\n const binPath = path.join(path.dirname(pkgJsonPath), binRelative);\n const command = { command: process.execPath, args: [binPath] };\n _biomeCommands.set(root, command);\n return command;\n }\n } catch {\n // Fall back to a biome binary on the PATH\n }\n\n try {\n execSync('biome --version', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n const command = { command: 'biome', args: [] };\n _biomeCommands.set(root, command);\n return command;\n } catch {\n _biomeCommands.set(root, null);\n return undefined;\n }\n}\n\n/**\n * Find the ruff command: `uvx --from ruff==<version> ruff`. uvx works\n * regardless of workspace resolution state (unlike `uv run ruff`, which fails\n * while installs are deferred), and the version pin matches the project's\n * `format` target (PY_VERSIONS) so generation and check format identically.\n * Only a successful probe is cached — ruff can become available mid-run in the\n * long-lived Nx daemon, so a cached failure would skip formatting thereafter.\n */\nlet _ruffCommand: string | undefined;\nfunction getRuffCommand(): string | undefined {\n if (_ruffCommand) {\n return _ruffCommand;\n }\n const cmd = uvxCommand('ruff');\n try {\n execSync(`${cmd} --version`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n _ruffCommand = cmd;\n return cmd;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Whether ruff would discover a config on disk for a file, by walking from its\n * directory up to the workspace root looking for `.ruff.toml`, `ruff.toml`, or a\n * `pyproject.toml` with a `[tool.ruff]` section — the same files ruff itself\n * resolves. The walk stops at `tree.root` so a stray config in a parent of the\n * workspace (or the home directory) is never treated as the project's. Used to\n * decide whether to nudge ruff towards import sorting (see\n * {@link ruffFixAndFormat}).\n */\nfunction hasRuffConfigOnDisk(tree: Tree, filePath: string): boolean {\n const root = path.resolve(tree.root);\n let dir = path.resolve(root, path.dirname(filePath));\n while (true) {\n if (\n existsSync(path.join(dir, '.ruff.toml')) ||\n existsSync(path.join(dir, 'ruff.toml'))\n ) {\n return true;\n }\n const pyproject = path.join(dir, 'pyproject.toml');\n if (\n existsSync(pyproject) &&\n readFileSync(pyproject, 'utf-8').includes('[tool.ruff')\n ) {\n return true;\n }\n const parent = path.dirname(dir);\n // Stop once the workspace root has been checked (or we hit the FS root).\n if (dir === root || parent === dir) {\n return false;\n }\n dir = parent;\n }\n}\n\n/**\n * The `[tool.ruff.lint].select` generated Python projects vend. Generation\n * formats before that config lands on disk, so it is pinned here to keep\n * generated files clean under the project's own `lint` target rather than under\n * whatever ruff's defaults happen to be for the pinned release.\n */\nconst DEFAULT_RUFF_SELECT = ['E', 'F', 'UP', 'B', 'SIM', 'I'];\n\ninterface PythonProjectRuffConfig {\n /** Project root, normalised to use forward slashes. */\n readonly root: string;\n /** Top-level importable module names declared by the project. */\n readonly modules: string[];\n /** The project's `[tool.ruff].line-length`, if set. */\n readonly lineLength?: number;\n /**\n * Ruff `target-version` (eg `py314`) derived from `[project].requires-python`.\n * Generation formats via stdin with no pyproject, so it must be passed\n * explicitly — ruff's formatting differs by target.\n */\n readonly targetVersion?: string;\n /** The project's `[tool.ruff.lint].select`, if set. */\n readonly select?: string[];\n}\n\n/**\n * Derive ruff's `target-version` (eg `py314`) from a PEP 508\n * `requires-python` specifier (eg `>=3.14`). Ruff targets the minimum\n * supported version, so take the lowest `major.minor` mentioned.\n */\nexport const requiresPythonToRuffTarget = (\n requiresPython: unknown,\n): string | undefined => {\n if (typeof requiresPython !== 'string') {\n return undefined;\n }\n let min: { major: number; minor: number } | undefined;\n for (const match of requiresPython.matchAll(/(\\d+)\\.(\\d+)/g)) {\n const major = Number(match[1]);\n const minor = Number(match[2]);\n if (\n !min ||\n major < min.major ||\n (major === min.major && minor < min.minor)\n ) {\n min = { major, minor };\n }\n }\n return min ? `py${min.major}${min.minor}` : undefined;\n};\n\n/**\n * Map each Nx project with a `pyproject.toml` to the ruff settings the on-disk\n * build enforces for it: its top-level module names (from\n * `[tool.hatch.build.targets.wheel].packages`), its `[tool.ruff].line-length`\n * and its `[tool.ruff.lint].select`.\n */\nfunction getPythonProjectRuffConfigs(tree: Tree): PythonProjectRuffConfig[] {\n const configs: PythonProjectRuffConfig[] = [];\n\n for (const project of getProjects(tree).values()) {\n const pyprojectPath = path.join(project.root, 'pyproject.toml');\n if (tree.exists(pyprojectPath)) {\n try {\n const pyproject = readToml(tree, pyprojectPath) as any;\n const wheelPackages: unknown =\n pyproject?.tool?.hatch?.build?.targets?.wheel?.packages;\n // Record the top-level module segment (`pkg/sub` -> `pkg`), which is\n // all `known-first-party` keys off.\n const modules = Array.isArray(wheelPackages)\n ? wheelPackages\n .filter((pkg): pkg is string => typeof pkg === 'string' && !!pkg)\n .map((pkg) => pkg.split('/')[0])\n : [];\n const lineLength: unknown = pyproject?.tool?.ruff?.['line-length'];\n const targetVersion = requiresPythonToRuffTarget(\n pyproject?.project?.['requires-python'],\n );\n const selected: unknown = pyproject?.tool?.ruff?.lint?.select;\n const select = Array.isArray(selected)\n ? selected.filter(\n (rule): rule is string => typeof rule === 'string' && !!rule,\n )\n : undefined;\n if (\n modules.length ||\n typeof lineLength === 'number' ||\n targetVersion ||\n select?.length\n ) {\n configs.push({\n root: project.root.split(path.sep).join('/'),\n modules,\n lineLength: typeof lineLength === 'number' ? lineLength : undefined,\n targetVersion,\n select: select?.length ? select : undefined,\n });\n }\n } catch {\n // Skip projects whose pyproject.toml cannot be parsed\n }\n }\n }\n\n return configs;\n}\n\n/**\n * Resolve the ruff config for the project that owns a file (the project with\n * the longest root that is a prefix of the file path). Ruff runs per-project on\n * disk, so a file's settings come from its own project — only its own module is\n * first-party (sibling workspace packages are third-party) and its own\n * line-length applies — and scoping this way keeps in-tree formatting\n * consistent with the on-disk build.\n */\nfunction getOwningProjectRuffConfig(\n filePath: string,\n configs: PythonProjectRuffConfig[],\n): PythonProjectRuffConfig | undefined {\n let owner: PythonProjectRuffConfig | undefined;\n for (const config of configs) {\n if (\n (filePath === config.root || filePath.startsWith(`${config.root}/`)) &&\n (!owner || config.root.length > owner.root.length)\n ) {\n owner = config;\n }\n }\n return owner;\n}\n\n/**\n * Run ruff check --fix and ruff format on Python file content via stdin.\n * Applies all configured lint fixes (including import sorting) and formatting.\n *\n * When no ruff config exists on disk (`hasConfig` false) ruff would fall back to\n * its own defaults, which change between releases — 0.16 widened them from `E`\n * and `F` to 36 rule prefixes — so generation would apply fixes the project's\n * build never asks for (eg `RUF022` reordering `__all__`). Instead run\n * `--isolated` with the project's own `lint.select` pinned, so generation\n * enforces exactly what `lint` does and nothing more. `--isolated` also stops\n * ruff walking above the workspace to a stray config on the host.\n *\n * When a config does exist we defer to it entirely, honouring the user's rule\n * selection, and run from `tree.root` so ruff discovers it.\n *\n * `projectConfig` carries the owning project's ruff settings, which ruff cannot\n * detect from the filesystem during generation because the project lives only\n * in the tree. We pass them via `--config` so in-tree formatting matches the\n * on-disk build: `known-first-party` (the project's own modules) keeps its\n * imports in their own group, and `line-length` keeps wrapping consistent (the\n * generated config raises it above ruff's default of 88). These are additive to\n * any on-disk config, so they are safe to pass regardless of `hasConfig`.\n */\nfunction ruffFixAndFormat(\n content: string,\n filePath: string,\n hasConfig: boolean,\n cwd: string | undefined,\n projectConfig?: PythonProjectRuffConfig,\n): string {\n const ruff = getRuffCommand();\n if (!ruff) return content;\n\n const configArgs: string[] = [];\n // Pin the rule selection only when deferring to ruff's defaults would\n // otherwise apply rules the project's build does not enforce.\n const isolated = !hasConfig;\n if (isolated) {\n configArgs.push(\n `lint.select = ${JSON.stringify(projectConfig?.select ?? DEFAULT_RUFF_SELECT)}`,\n );\n }\n if (projectConfig?.modules.length) {\n configArgs.push(\n `lint.isort.known-first-party = ${JSON.stringify(projectConfig.modules)}`,\n );\n }\n if (typeof projectConfig?.lineLength === 'number') {\n configArgs.push(`line-length = ${projectConfig.lineLength}`);\n }\n if (projectConfig?.targetVersion) {\n configArgs.push(`target-version = \"${projectConfig.targetVersion}\"`);\n }\n const config = configArgs\n .map((arg) => ` --config ${JSON.stringify(arg)}`)\n .join('');\n const flags = `${isolated ? ' --isolated' : ''}${config}`;\n // Built per invocation: `input` carries the content the previous step emitted.\n const options = (input: string): ExecSyncOptionsWithStringEncoding => ({\n input,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n ...(cwd ? { cwd } : {}),\n });\n\n // First apply lint fixes (import sorting, unused imports, etc.)\n try {\n const result = execSync(\n `${ruff} check --fix${flags} --stdin-filename ${filePath} -`,\n options(content),\n );\n content = result;\n } catch (e: any) {\n // ruff check exits non-zero when it finds unfixable issues,\n // but stdout still contains the fixed content\n if (e.stdout) {\n content = e.stdout;\n }\n }\n\n // Then apply formatting\n try {\n content = execSync(\n `${ruff} format${flags} --stdin-filename ${filePath} -`,\n options(content),\n );\n } catch {\n // Fall through with whatever content we have\n }\n\n return content;\n}\n"],"names":["Biome","getProjects","execFileSync","execSync","existsSync","readFileSync","createRequire","path","uvxCommand","readToml","TS_VERSIONS","require","url","getDefaultBiomeConfig","tree","$schema","root","formatter","enabled","indentStyle","indentWidth","lineWidth","javascript","quoteStyle","trailingCommas","exists","resolver","experimentalPnpmCatalogs","css","linter","rules","preset","correctness","noUndeclaredDependencies","assist","actions","source","organizeImports","files","includes","overrides","BIOME_FORMATTABLE_EXTENSIONS","Set","isTsConfig","filePath","test","formatFilesInSubtree","dir","changedFiles","listChanges","filter","file","type","startsWith","pyFiles","endsWith","otherFiles","has","extname","pythonProjectConfigs","length","getPythonProjectRuffConfigs","ruffCwd","undefined","content","ruffFixAndFormat","toString","hasRuffConfigOnDisk","getOwningProjectRuffConfig","write","join","formatWithBiomeCli","formatWithBiomeApi","biome","getBiomeCommand","command","args","input","encoding","cwd","stdio","projectKey","openProject","treeConfig","read","applyConfiguration","JSON","parse","formatContent","_biomeCommands","Map","get","pkgJsonPath","resolve","paths","dirname","pkgJson","binRelative","bin","binPath","process","execPath","set","_ruffCommand","getRuffCommand","cmd","pyproject","parent","DEFAULT_RUFF_SELECT","requiresPythonToRuffTarget","requiresPython","min","match","matchAll","major","Number","minor","configs","project","values","pyprojectPath","wheelPackages","tool","hatch","build","targets","wheel","packages","modules","Array","isArray","pkg","map","split","lineLength","ruff","targetVersion","selected","lint","select","rule","push","sep","owner","config","hasConfig","projectConfig","configArgs","isolated","stringify","arg","flags","options","result","e","stdout"],"mappings":"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"}
|
package/src/utils/init.js
CHANGED
|
@@ -16,7 +16,7 @@ import { addDependenciesToPackageJson, detectWorkspacePackageManager } from "./d
|
|
|
16
16
|
import { getDefaultBiomeConfig } from "./format.js";
|
|
17
17
|
import { configureMcpServers } from "./mcp.js";
|
|
18
18
|
import { getNpmScope } from "./npm-scope.js";
|
|
19
|
-
import { mergeTargetDefault } from "./nx.js";
|
|
19
|
+
import { mergeTargetDefault, nxPluginMcpDependency, nxPluginSelfDependency } from "./nx.js";
|
|
20
20
|
import { getPackageManagerDisplayCommands } from "./pkg-manager.js";
|
|
21
21
|
import { workspaceGlobs } from "./project-package-json.js";
|
|
22
22
|
import { withVersions } from "./versions.js";
|
|
@@ -246,7 +246,12 @@ export const PNPM_BUILT_DEPENDENCIES = [
|
|
|
246
246
|
...withVersions([
|
|
247
247
|
'typescript',
|
|
248
248
|
'@biomejs/biome'
|
|
249
|
-
])
|
|
249
|
+
]),
|
|
250
|
+
// Declare the plugin the generators are running from, plus the MCP server
|
|
251
|
+
// package the vended config runs, so both are pinned in the workspace's
|
|
252
|
+
// lockfile and upgrading them upgrades what the agents use.
|
|
253
|
+
...nxPluginSelfDependency(tree),
|
|
254
|
+
...nxPluginMcpDependency(tree)
|
|
250
255
|
});
|
|
251
256
|
// Write biome.json for formatting and linting
|
|
252
257
|
if (!tree.exists('biome.json')) {
|
package/src/utils/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/init.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport { readModulePackageJson } from 'nx/src/utils/package-json';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport { BASE_TSCONFIG_COMPILER_OPTIONS } from './base-tsconfig';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from './config/utils';\nimport { type Containers, inferContainers } from './containers';\nimport {\n addDependenciesToPackageJson,\n detectWorkspacePackageManager,\n} from './dependencies';\nimport { getDefaultBiomeConfig } from './format';\nimport type { Iac } from './iac';\nimport { configureMcpServers } from './mcp';\nimport { getNpmScope } from './npm-scope';\nimport { mergeTargetDefault } from './nx';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport { workspaceGlobs } from './project-package-json';\nimport { withVersions } from './versions';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nexport const PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\n/**\n * Options controlling how the workspace is initialised. These mirror the\n * preset schema so a workspace created via the preset and one initialised via\n * the `init` generator end up in the same shape.\n */\nexport interface ApplyWorkspaceInitOptions {\n /** The IaC provider to record in the plugin config. */\n readonly iac: Iac;\n /**\n * The container engine to record. `undefined`/`'infer'` picks docker when\n * installed, else finch.\n */\n readonly containers?: Containers | 'infer';\n /** Whether to configure MCP servers for coding agents. Defaults to true. */\n readonly mcp?: boolean;\n /**\n * How to treat the generated workspace README. The preset owns the README of\n * a greenfield workspace (`Overwrite`); the `init` generator must not clobber\n * an existing workspace's README (`KeepExisting`, the default).\n */\n readonly readmeOverwriteStrategy?: OverwriteStrategy;\n /**\n * Whether to overwrite root package.json scripts that already exist. The\n * preset owns a greenfield workspace's scripts (`true`); the `init`\n * generator must not clobber an existing workspace's scripts (`false`,\n * the default) — it only adds the convenience scripts that are absent.\n */\n readonly overwriteScripts?: boolean;\n /**\n * Whether generators use the package manager's dependency catalog. On pnpm\n * this also sets `catalogMode: strict` so `pnpm add` records new deps in the\n * catalog. Defaults to true.\n */\n readonly catalogs?: boolean;\n}\n\n/**\n * Add or repair the pnpm `allowBuilds` / `onlyBuiltDependencies` allowlist for\n * the workspace's `packages` globs, without clobbering any packages the user\n * has already declared.\n *\n * A workspace not created by the preset commonly has either no\n * `pnpm-workspace.yaml`, one missing the `packages` globs, or one carrying the\n * broken `set this to true or false` placeholder pnpm writes when it skips a\n * build script. This makes the file self-consistent so the first generator's\n * install doesn't fail with `ERR_PNPM_IGNORED_BUILDS`.\n */\nconst setUpPnpmWorkspace = (tree: Tree, catalogs: boolean) => {\n const existing = tree.exists('pnpm-workspace.yaml')\n ? ((yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {})\n : {};\n\n // Preserve any packages globs the user already has, ensuring ours are present.\n const packages = Array.from(\n new Set([...((existing.packages as string[]) ?? []), ...WORKSPACES]),\n );\n\n const allowBuilds = {\n ...(typeof existing.allowBuilds === 'object' && existing.allowBuilds\n ? (existing.allowBuilds as Record<string, unknown>)\n : {}),\n // Overwrite any non-boolean (e.g. the \"set this to true or false\"\n // placeholder) with an explicit true for the deps we trust.\n ...Object.fromEntries(PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true])),\n };\n\n // `strict` makes `pnpm add` record new deps in the catalog; it only gates\n // that flow, so pre-declared direct ranges (e.g. tslib) still install.\n // Preserve an explicit user choice.\n const catalogMode = catalogs\n ? (existing.catalogMode ?? 'strict')\n : existing.catalogMode;\n\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n ...existing,\n packages,\n allowBuilds,\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n ...(catalogMode ? { catalogMode } : {}),\n },\n { quotingType: \"'\" },\n ),\n );\n};\n\n/**\n * Configure the workspace's package manager for a monorepo layout.\n *\n * pnpm workspaces are declared in `pnpm-workspace.yaml`; every other package\n * manager reads the `workspaces` field of the root `package.json`.\n */\nconst setUpWorkspaces = (tree: Tree, catalogs: boolean) => {\n if (detectWorkspacePackageManager(tree) === 'pnpm') {\n setUpPnpmWorkspace(tree, catalogs);\n } else {\n updateJson(tree, 'package.json', (json) => {\n // The `workspaces` field may be the object form ({ \"packages\": [...] })\n // accepted by yarn and bun — extend the globs while preserving the form.\n const globs = Array.from(\n new Set([...workspaceGlobs(json.workspaces), ...WORKSPACES]),\n );\n return {\n ...json,\n workspaces:\n json.workspaces !== undefined && !Array.isArray(json.workspaces)\n ? { ...json.workspaces, packages: globs }\n : globs,\n };\n });\n }\n};\n\n/**\n * Ensure the workspace has a `tsconfig.base.json`.\n *\n * `@nx/js` `initGenerator` (with `addTsPlugin`) normally creates this, but it\n * short-circuits when the workspace already has a root `tsconfig.json` — in\n * which case no base file is written and the next project generator fails with\n * `Cannot find tsconfig.base.json`. So we create a compatible one when it's\n * absent. An existing base is left untouched: the user may have tuned it, and\n * rewriting shared compiler options can break other projects (see the\n * \"add to an existing workspace\" guide).\n */\nconst ensureBaseTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.base.json')) {\n return;\n }\n tree.write(\n 'tsconfig.base.json',\n JSON.stringify(\n {\n compilerOptions: {\n ...BASE_TSCONFIG_COMPILER_OPTIONS,\n customConditions: [getNpmScope(tree)],\n },\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Ensure the workspace has a root `tsconfig.json`.\n *\n * Nx's `@nx/js:typescript-sync` generator hard-fails with\n * `Missing root \"tsconfig.json\"` when it's absent. The plugin's TypeScript\n * projects reference each other via this file, so we guarantee a minimal one\n * exists (sync populates its `references`).\n */\nconst ensureRootTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.json')) {\n return;\n }\n tree.write(\n 'tsconfig.json',\n JSON.stringify(\n {\n extends: './tsconfig.base.json',\n files: [],\n references: [],\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Transform an Nx workspace into one ready to run `@aws/nx-plugin` generators.\n *\n * This is the deterministic core shared by the workspace preset and the `init`\n * generator. It is safe to re-run: every step is idempotent (config merges,\n * keyed nx.json / package.json entries, create-if-missing files), so running\n * it against an already-initialised workspace is a no-op.\n *\n * It preserves the workspace's module format: the root package.json `type`\n * field is owned by the preset (written from its `--module` option) and left\n * untouched here. It does NOT rewrite an existing `tsconfig.base.json`'s\n * compiler options, migrate a workspace's package manager, or restructure\n * existing projects — those are decisions for the user (see the \"add to an\n * existing workspace\" guide).\n */\nexport const applyWorkspaceInit = async (\n tree: Tree,\n {\n iac,\n containers,\n mcp,\n readmeOverwriteStrategy = OverwriteStrategy.KeepExisting,\n overwriteScripts = false,\n catalogs = true,\n }: ApplyWorkspaceInitOptions,\n) => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n\n // The catalogs flag is written explicitly (even when true) so the workspace\n // records its dependency-management choice.\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n packageManager: { catalogs },\n });\n\n // Set up the TypeScript plugin, base tsconfig, formatter etc. `@nx/js`\n // creates `tsconfig.base.json` when absent, but skips it when a root\n // `tsconfig.json` already exists — so we ensure both explicitly below.\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n ensureBaseTsConfig(tree);\n ensureRootTsConfig(tree);\n\n setUpWorkspaces(tree, catalogs);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n // Preserve an explicit analytics choice in an existing workspace.\n analytics: (nxJson as { analytics?: boolean }).analytics ?? false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: mergeTargetDefault(nxJson.targetDefaults?.compile, (base) => ({\n ...base,\n syncGenerators: [\n ...(base.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n })),\n },\n });\n\n const CONVENIENCE_SCRIPTS = {\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n // Trivy container image scanning is not part of `build` (its result\n // depends on the ever-changing vulnerability database); run it explicitly,\n // e.g. in CI.\n trivy: 'nx run-many --target trivy --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n };\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n // The root `type` field is owned by the preset (written explicitly from\n // its `--module` option). `init` preserves an existing workspace's field\n // as-is: an ESM workspace already carries `type: \"module\"` (that is how\n // the format is inferred), and introducing a `type` into a CommonJS\n // workspace that lacks one changes behaviour for frameworks that parse it\n // (e.g. Next.js starts treating the app's ESM source as CJS).\n scripts: overwriteScripts\n ? { ...packageJson.scripts, ...CONVENIENCE_SCRIPTS }\n : { ...CONVENIENCE_SCRIPTS, ...packageJson.scripts },\n }));\n\n // Pin the workspace's `nx` to the version the plugin's @nx/* packages are\n // built against. A mismatched workspace nx (even a patch apart) hoists a\n // second nested nx under @nx/js, and the two instances deadlock `nx sync`.\n // `@nx/js` must be a root dependency for the `@nx/js:typescript-sync`\n // generator registered in nx.json to resolve (npm doesn't hoist the\n // plugin's own copy reliably).\n const nxVersion = readModulePackageJson('@nx/js').packageJson.version;\n addDependenciesToPackageJson(\n tree,\n {},\n {\n nx: nxVersion,\n '@nx/js': nxVersion,\n '@nx/workspace': nxVersion,\n ...withVersions(['typescript', '@biomejs/biome']),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write(\n 'biome.json',\n JSON.stringify(getDefaultBiomeConfig(tree), null, 2),\n );\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, '..', 'preset', 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: readmeOverwriteStrategy,\n },\n );\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","yaml","readModulePackageJson","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","BASE_TSCONFIG_COMPILER_OPTIONS","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","addDependenciesToPackageJson","detectWorkspacePackageManager","getDefaultBiomeConfig","configureMcpServers","getNpmScope","mergeTargetDefault","getPackageManagerDisplayCommands","workspaceGlobs","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","PNPM_BUILT_DEPENDENCIES","setUpPnpmWorkspace","tree","catalogs","existing","exists","load","read","packages","Array","from","Set","allowBuilds","Object","fromEntries","map","dep","catalogMode","write","dump","onlyBuiltDependencies","quotingType","setUpWorkspaces","json","globs","workspaces","undefined","isArray","ensureBaseTsConfig","JSON","stringify","compilerOptions","customConditions","ensureRootTsConfig","extends","files","references","applyWorkspaceInit","iac","containers","mcp","readmeOverwriteStrategy","KeepExisting","overwriteScripts","resolvedContainers","provider","engine","packageManager","formatter","addTsPlugin","nxJson","analytics","targetDefaults","compile","base","syncGenerators","filter","g","includes","CONVENIENCE_SCRIPTS","dev","build","lint","test","trivy","packageJson","scripts","nxVersion","version","nx","dirname","projectName","generators","entries","_","v","k","name","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,EACjBC,UAAU,EAEVC,UAAU,EACVC,YAAY,QACP,aAAa;AACpB,SAASC,aAAa,QAAQ,SAAS;AAEvC,OAAOC,UAAU,UAAU;AAC3B,SAASC,qBAAqB,QAAQ,4BAA4B;AAClE,OAAOC,oBAAoB,6BAA6B;IAAEC,MAAM;AAAO,EAAE;AACzE,SAASC,uBAAuBC,sBAAsB,QAAQ,0BAAuB;AACrF,SAASC,8BAA8B,QAAQ,qBAAkB;AACjE,SACEC,uBAAuB,EACvBC,uBAAuB,QAClB,oBAAiB;AACxB,SAA0BC,eAAe,QAAQ,kBAAe;AAChE,SACEC,4BAA4B,EAC5BC,6BAA6B,QACxB,oBAAiB;AACxB,SAASC,qBAAqB,QAAQ,cAAW;AAEjD,SAASC,mBAAmB,QAAQ,WAAQ;AAC5C,SAASC,WAAW,QAAQ,iBAAc;AAC1C,SAASC,kBAAkB,QAAQ,UAAO;AAC1C,SAASC,gCAAgC,QAAQ,mBAAgB;AACjE,SAASC,cAAc,QAAQ,4BAAyB;AACxD,SAASC,YAAY,QAAQ,gBAAa;AAE1C,MAAMC,aAAa;IAAC;CAAa;AACjC,MAAMC,+BAA+B;AAErC,2EAA2E;AAC3E,4EAA4E;AAC5E,0EAA0E;AAC1E,uEAAuE;AACvE,0EAA0E;AAC1E,OAAO,MAAMC,0BAA0B;IAAC;IAAa;IAAW;IAAM;CAAQ,CAAC;AAsC/E;;;;;;;;;;CAUC,GACD,MAAMC,qBAAqB,CAACC,MAAYC;IACtC,MAAMC,WAAWF,KAAKG,MAAM,CAAC,yBACxB,AAAC1B,KAAK2B,IAAI,CAACJ,KAAKK,IAAI,CAAC,uBAAuB,YAAY,OAGnD,CAAC,IACP,CAAC;IAEL,+EAA+E;IAC/E,MAAMC,WAAWC,MAAMC,IAAI,CACzB,IAAIC,IAAI;WAAK,AAACP,SAASI,QAAQ,IAAiB,EAAE;WAAMV;KAAW;IAGrE,MAAMc,cAAc;QAClB,GAAI,OAAOR,SAASQ,WAAW,KAAK,YAAYR,SAASQ,WAAW,GAC/DR,SAASQ,WAAW,GACrB,CAAC,CAAC;QACN,kEAAkE;QAClE,4DAA4D;QAC5D,GAAGC,OAAOC,WAAW,CAACd,wBAAwBe,GAAG,CAAC,CAACC,MAAQ;gBAACA;gBAAK;aAAK,EAAE;IAC1E;IAEA,0EAA0E;IAC1E,uEAAuE;IACvE,oCAAoC;IACpC,MAAMC,cAAcd,WACfC,SAASa,WAAW,IAAI,WACzBb,SAASa,WAAW;IAExBf,KAAKgB,KAAK,CACR,uBACAvC,KAAKwC,IAAI,CACP;QACE,GAAGf,QAAQ;QACXI;QACAI;QACAQ,uBAAuBpB;QACvB,GAAIiB,cAAc;YAAEA;QAAY,IAAI,CAAC,CAAC;IACxC,GACA;QAAEI,aAAa;IAAI;AAGzB;AAEA;;;;;CAKC,GACD,MAAMC,kBAAkB,CAACpB,MAAYC;IACnC,IAAIb,8BAA8BY,UAAU,QAAQ;QAClDD,mBAAmBC,MAAMC;IAC3B,OAAO;QACL3B,WAAW0B,MAAM,gBAAgB,CAACqB;YAChC,wEAAwE;YACxE,yEAAyE;YACzE,MAAMC,QAAQf,MAAMC,IAAI,CACtB,IAAIC,IAAI;mBAAIf,eAAe2B,KAAKE,UAAU;mBAAM3B;aAAW;YAE7D,OAAO;gBACL,GAAGyB,IAAI;gBACPE,YACEF,KAAKE,UAAU,KAAKC,aAAa,CAACjB,MAAMkB,OAAO,CAACJ,KAAKE,UAAU,IAC3D;oBAAE,GAAGF,KAAKE,UAAU;oBAAEjB,UAAUgB;gBAAM,IACtCA;YACR;QACF;IACF;AACF;AAEA;;;;;;;;;;CAUC,GACD,MAAMI,qBAAqB,CAAC1B;IAC1B,IAAIA,KAAKG,MAAM,CAAC,uBAAuB;QACrC;IACF;IACAH,KAAKgB,KAAK,CACR,sBACAW,KAAKC,SAAS,CACZ;QACEC,iBAAiB;YACf,GAAG9C,8BAA8B;YACjC+C,kBAAkB;gBAACvC,YAAYS;aAAM;QACvC;IACF,GACA,MACA;AAGN;AAEA;;;;;;;CAOC,GACD,MAAM+B,qBAAqB,CAAC/B;IAC1B,IAAIA,KAAKG,MAAM,CAAC,kBAAkB;QAChC;IACF;IACAH,KAAKgB,KAAK,CACR,iBACAW,KAAKC,SAAS,CACZ;QACEI,SAAS;QACTC,OAAO,EAAE;QACTC,YAAY,EAAE;IAChB,GACA,MACA;AAGN;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,qBAAqB,OAChCnC,MACA,EACEoC,GAAG,EACHC,UAAU,EACVC,GAAG,EACHC,0BAA0BnE,kBAAkBoE,YAAY,EACxDC,mBAAmB,KAAK,EACxBxC,WAAW,IAAI,EACW;IAE5B,MAAMyC,qBACJ,CAACL,cAAcA,eAAe,UAAUnD,oBAAoBmD;IAE9D,4EAA4E;IAC5E,4CAA4C;IAC5C,MAAMrD,wBAAwBgB;IAC9B,MAAMf,wBAAwBe,MAAM;QAClCoC,KAAK;YAAEO,UAAUP;QAAI;QACrBC,YAAY;YAAEO,QAAQF;QAAmB;QACzCG,gBAAgB;YAAE5C;QAAS;IAC7B;IAEA,uEAAuE;IACvE,qEAAqE;IACrE,uEAAuE;IACvE,MAAMzB,cAAcwB,MAAM;QACxB8C,WAAW;QACXC,aAAa;IACf;IAEArB,mBAAmB1B;IACnB+B,mBAAmB/B;IAEnBoB,gBAAgBpB,MAAMC;IAEtB,MAAM+C,SAAS3E,WAAW2B;IAC1BzB,aAAayB,MAAM;QACjB,GAAGgD,MAAM;QACT,kEAAkE;QAClEC,WAAW,AAACD,OAAmCC,SAAS,IAAI;QAC5DC,gBAAgB;YACd,GAAGF,OAAOE,cAAc;YACxBC,SAAS3D,mBAAmBwD,OAAOE,cAAc,EAAEC,SAAS,CAACC,OAAU,CAAA;oBACrE,GAAGA,IAAI;oBACPC,gBAAgB;2BACX,AAACD,CAAAA,KAAKC,cAAc,IAAI,EAAE,AAAD,EAAGC,MAAM,CACnC,CAACC,IACC,CAAC;gCAACzE;gCAAwBe;6BAA6B,CAAC2D,QAAQ,CAC9DD;wBAGN1D;wBACAf;qBACD;gBACH,CAAA;QACF;IACF;IAEA,MAAM2E,sBAAsB;QAC1BC,KAAK;QACLC,OAAO;QACPC,MAAM;QACNC,MAAM;QACN,oEAAoE;QACpE,2EAA2E;QAC3E,cAAc;QACdC,OAAO;QACP,mBAAmB;QACnB,aAAa;QACb,gBAAgB;IAClB;IACAxF,WAAW0B,MAAM,gBAAgB,CAAC+D,cAAiB,CAAA;YACjD,GAAGA,WAAW;YACd,wEAAwE;YACxE,yEAAyE;YACzE,wEAAwE;YACxE,oEAAoE;YACpE,0EAA0E;YAC1E,8DAA8D;YAC9DC,SAASvB,mBACL;gBAAE,GAAGsB,YAAYC,OAAO;gBAAE,GAAGP,mBAAmB;YAAC,IACjD;gBAAE,GAAGA,mBAAmB;gBAAE,GAAGM,YAAYC,OAAO;YAAC;QACvD,CAAA;IAEA,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,sEAAsE;IACtE,oEAAoE;IACpE,+BAA+B;IAC/B,MAAMC,YAAYvF,sBAAsB,UAAUqF,WAAW,CAACG,OAAO;IACrE/E,6BACEa,MACA,CAAC,GACD;QACEmE,IAAIF;QACJ,UAAUA;QACV,iBAAiBA;QACjB,GAAGtE,aAAa;YAAC;YAAc;SAAiB,CAAC;IACnD;IAGF,8CAA8C;IAC9C,IAAI,CAACK,KAAKG,MAAM,CAAC,eAAe;QAC9BH,KAAKgB,KAAK,CACR,cACAW,KAAKC,SAAS,CAACvC,sBAAsBW,OAAO,MAAM;IAEtD;IAEA9B,cACE8B,MACA7B,kBAAkB,YAAYiG,OAAO,EAAE,MAAM,UAAU,UACvD,KACA;QACEC,aAAa9E,YAAYS;QACzBsE,YAAY3D,OAAO4D,OAAO,CAAC5F,eAAe2F,UAAU,EACjDhB,MAAM,CAAC,CAAC,CAACkB,GAAGC,EAAE,GAAK,CAACA,CAAC,CAAC,SAAS,EAC/B5D,GAAG,CAAC,CAAC,CAAC6D,GAAGD,EAAE,GAAM,CAAA;gBAAEE,MAAMD;gBAAGE,aAAaH,EAAEG,WAAW;YAAC,CAAA;QAC1D,GAAG,AAAC,CAAA;YACF,MAAMC,OAAOpF;YACb,OAAO;gBACLqF,WAAWD,KAAKE,IAAI;gBACpBC,UAAU,GAAGH,KAAKI,GAAG,CAAC,MAAM,CAAC;gBAC7BC,SAAS,GAAGL,KAAKI,GAAG,CAAC,KAAK,CAAC;YAC7B;QACF,CAAA,GAAI;IACN,GACA;QACEE,mBAAmB5C;IACrB;IAGF,IAAID,QAAQ,OAAO;QACjBhD,oBAAoBU;IACtB;AACF,EAAE"}
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/init.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport { readModulePackageJson } from 'nx/src/utils/package-json';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport { BASE_TSCONFIG_COMPILER_OPTIONS } from './base-tsconfig';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from './config/utils';\nimport { type Containers, inferContainers } from './containers';\nimport {\n addDependenciesToPackageJson,\n detectWorkspacePackageManager,\n} from './dependencies';\nimport { getDefaultBiomeConfig } from './format';\nimport type { Iac } from './iac';\nimport { configureMcpServers } from './mcp';\nimport { getNpmScope } from './npm-scope';\nimport {\n mergeTargetDefault,\n nxPluginMcpDependency,\n nxPluginSelfDependency,\n} from './nx';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport { workspaceGlobs } from './project-package-json';\nimport { withVersions } from './versions';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nexport const PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\n/**\n * Options controlling how the workspace is initialised. These mirror the\n * preset schema so a workspace created via the preset and one initialised via\n * the `init` generator end up in the same shape.\n */\nexport interface ApplyWorkspaceInitOptions {\n /** The IaC provider to record in the plugin config. */\n readonly iac: Iac;\n /**\n * The container engine to record. `undefined`/`'infer'` picks docker when\n * installed, else finch.\n */\n readonly containers?: Containers | 'infer';\n /** Whether to configure MCP servers for coding agents. Defaults to true. */\n readonly mcp?: boolean;\n /**\n * How to treat the generated workspace README. The preset owns the README of\n * a greenfield workspace (`Overwrite`); the `init` generator must not clobber\n * an existing workspace's README (`KeepExisting`, the default).\n */\n readonly readmeOverwriteStrategy?: OverwriteStrategy;\n /**\n * Whether to overwrite root package.json scripts that already exist. The\n * preset owns a greenfield workspace's scripts (`true`); the `init`\n * generator must not clobber an existing workspace's scripts (`false`,\n * the default) — it only adds the convenience scripts that are absent.\n */\n readonly overwriteScripts?: boolean;\n /**\n * Whether generators use the package manager's dependency catalog. On pnpm\n * this also sets `catalogMode: strict` so `pnpm add` records new deps in the\n * catalog. Defaults to true.\n */\n readonly catalogs?: boolean;\n}\n\n/**\n * Add or repair the pnpm `allowBuilds` / `onlyBuiltDependencies` allowlist for\n * the workspace's `packages` globs, without clobbering any packages the user\n * has already declared.\n *\n * A workspace not created by the preset commonly has either no\n * `pnpm-workspace.yaml`, one missing the `packages` globs, or one carrying the\n * broken `set this to true or false` placeholder pnpm writes when it skips a\n * build script. This makes the file self-consistent so the first generator's\n * install doesn't fail with `ERR_PNPM_IGNORED_BUILDS`.\n */\nconst setUpPnpmWorkspace = (tree: Tree, catalogs: boolean) => {\n const existing = tree.exists('pnpm-workspace.yaml')\n ? ((yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {})\n : {};\n\n // Preserve any packages globs the user already has, ensuring ours are present.\n const packages = Array.from(\n new Set([...((existing.packages as string[]) ?? []), ...WORKSPACES]),\n );\n\n const allowBuilds = {\n ...(typeof existing.allowBuilds === 'object' && existing.allowBuilds\n ? (existing.allowBuilds as Record<string, unknown>)\n : {}),\n // Overwrite any non-boolean (e.g. the \"set this to true or false\"\n // placeholder) with an explicit true for the deps we trust.\n ...Object.fromEntries(PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true])),\n };\n\n // `strict` makes `pnpm add` record new deps in the catalog; it only gates\n // that flow, so pre-declared direct ranges (e.g. tslib) still install.\n // Preserve an explicit user choice.\n const catalogMode = catalogs\n ? (existing.catalogMode ?? 'strict')\n : existing.catalogMode;\n\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n ...existing,\n packages,\n allowBuilds,\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n ...(catalogMode ? { catalogMode } : {}),\n },\n { quotingType: \"'\" },\n ),\n );\n};\n\n/**\n * Configure the workspace's package manager for a monorepo layout.\n *\n * pnpm workspaces are declared in `pnpm-workspace.yaml`; every other package\n * manager reads the `workspaces` field of the root `package.json`.\n */\nconst setUpWorkspaces = (tree: Tree, catalogs: boolean) => {\n if (detectWorkspacePackageManager(tree) === 'pnpm') {\n setUpPnpmWorkspace(tree, catalogs);\n } else {\n updateJson(tree, 'package.json', (json) => {\n // The `workspaces` field may be the object form ({ \"packages\": [...] })\n // accepted by yarn and bun — extend the globs while preserving the form.\n const globs = Array.from(\n new Set([...workspaceGlobs(json.workspaces), ...WORKSPACES]),\n );\n return {\n ...json,\n workspaces:\n json.workspaces !== undefined && !Array.isArray(json.workspaces)\n ? { ...json.workspaces, packages: globs }\n : globs,\n };\n });\n }\n};\n\n/**\n * Ensure the workspace has a `tsconfig.base.json`.\n *\n * `@nx/js` `initGenerator` (with `addTsPlugin`) normally creates this, but it\n * short-circuits when the workspace already has a root `tsconfig.json` — in\n * which case no base file is written and the next project generator fails with\n * `Cannot find tsconfig.base.json`. So we create a compatible one when it's\n * absent. An existing base is left untouched: the user may have tuned it, and\n * rewriting shared compiler options can break other projects (see the\n * \"add to an existing workspace\" guide).\n */\nconst ensureBaseTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.base.json')) {\n return;\n }\n tree.write(\n 'tsconfig.base.json',\n JSON.stringify(\n {\n compilerOptions: {\n ...BASE_TSCONFIG_COMPILER_OPTIONS,\n customConditions: [getNpmScope(tree)],\n },\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Ensure the workspace has a root `tsconfig.json`.\n *\n * Nx's `@nx/js:typescript-sync` generator hard-fails with\n * `Missing root \"tsconfig.json\"` when it's absent. The plugin's TypeScript\n * projects reference each other via this file, so we guarantee a minimal one\n * exists (sync populates its `references`).\n */\nconst ensureRootTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.json')) {\n return;\n }\n tree.write(\n 'tsconfig.json',\n JSON.stringify(\n {\n extends: './tsconfig.base.json',\n files: [],\n references: [],\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Transform an Nx workspace into one ready to run `@aws/nx-plugin` generators.\n *\n * This is the deterministic core shared by the workspace preset and the `init`\n * generator. It is safe to re-run: every step is idempotent (config merges,\n * keyed nx.json / package.json entries, create-if-missing files), so running\n * it against an already-initialised workspace is a no-op.\n *\n * It preserves the workspace's module format: the root package.json `type`\n * field is owned by the preset (written from its `--module` option) and left\n * untouched here. It does NOT rewrite an existing `tsconfig.base.json`'s\n * compiler options, migrate a workspace's package manager, or restructure\n * existing projects — those are decisions for the user (see the \"add to an\n * existing workspace\" guide).\n */\nexport const applyWorkspaceInit = async (\n tree: Tree,\n {\n iac,\n containers,\n mcp,\n readmeOverwriteStrategy = OverwriteStrategy.KeepExisting,\n overwriteScripts = false,\n catalogs = true,\n }: ApplyWorkspaceInitOptions,\n) => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n\n // The catalogs flag is written explicitly (even when true) so the workspace\n // records its dependency-management choice.\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n packageManager: { catalogs },\n });\n\n // Set up the TypeScript plugin, base tsconfig, formatter etc. `@nx/js`\n // creates `tsconfig.base.json` when absent, but skips it when a root\n // `tsconfig.json` already exists — so we ensure both explicitly below.\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n ensureBaseTsConfig(tree);\n ensureRootTsConfig(tree);\n\n setUpWorkspaces(tree, catalogs);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n // Preserve an explicit analytics choice in an existing workspace.\n analytics: (nxJson as { analytics?: boolean }).analytics ?? false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: mergeTargetDefault(nxJson.targetDefaults?.compile, (base) => ({\n ...base,\n syncGenerators: [\n ...(base.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n })),\n },\n });\n\n const CONVENIENCE_SCRIPTS = {\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n // Trivy container image scanning is not part of `build` (its result\n // depends on the ever-changing vulnerability database); run it explicitly,\n // e.g. in CI.\n trivy: 'nx run-many --target trivy --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n };\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n // The root `type` field is owned by the preset (written explicitly from\n // its `--module` option). `init` preserves an existing workspace's field\n // as-is: an ESM workspace already carries `type: \"module\"` (that is how\n // the format is inferred), and introducing a `type` into a CommonJS\n // workspace that lacks one changes behaviour for frameworks that parse it\n // (e.g. Next.js starts treating the app's ESM source as CJS).\n scripts: overwriteScripts\n ? { ...packageJson.scripts, ...CONVENIENCE_SCRIPTS }\n : { ...CONVENIENCE_SCRIPTS, ...packageJson.scripts },\n }));\n\n // Pin the workspace's `nx` to the version the plugin's @nx/* packages are\n // built against. A mismatched workspace nx (even a patch apart) hoists a\n // second nested nx under @nx/js, and the two instances deadlock `nx sync`.\n // `@nx/js` must be a root dependency for the `@nx/js:typescript-sync`\n // generator registered in nx.json to resolve (npm doesn't hoist the\n // plugin's own copy reliably).\n const nxVersion = readModulePackageJson('@nx/js').packageJson.version;\n addDependenciesToPackageJson(\n tree,\n {},\n {\n nx: nxVersion,\n '@nx/js': nxVersion,\n '@nx/workspace': nxVersion,\n ...withVersions(['typescript', '@biomejs/biome']),\n // Declare the plugin the generators are running from, plus the MCP server\n // package the vended config runs, so both are pinned in the workspace's\n // lockfile and upgrading them upgrades what the agents use.\n ...nxPluginSelfDependency(tree),\n ...nxPluginMcpDependency(tree),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write(\n 'biome.json',\n JSON.stringify(getDefaultBiomeConfig(tree), null, 2),\n );\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, '..', 'preset', 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: readmeOverwriteStrategy,\n },\n );\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","yaml","readModulePackageJson","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","BASE_TSCONFIG_COMPILER_OPTIONS","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","addDependenciesToPackageJson","detectWorkspacePackageManager","getDefaultBiomeConfig","configureMcpServers","getNpmScope","mergeTargetDefault","nxPluginMcpDependency","nxPluginSelfDependency","getPackageManagerDisplayCommands","workspaceGlobs","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","PNPM_BUILT_DEPENDENCIES","setUpPnpmWorkspace","tree","catalogs","existing","exists","load","read","packages","Array","from","Set","allowBuilds","Object","fromEntries","map","dep","catalogMode","write","dump","onlyBuiltDependencies","quotingType","setUpWorkspaces","json","globs","workspaces","undefined","isArray","ensureBaseTsConfig","JSON","stringify","compilerOptions","customConditions","ensureRootTsConfig","extends","files","references","applyWorkspaceInit","iac","containers","mcp","readmeOverwriteStrategy","KeepExisting","overwriteScripts","resolvedContainers","provider","engine","packageManager","formatter","addTsPlugin","nxJson","analytics","targetDefaults","compile","base","syncGenerators","filter","g","includes","CONVENIENCE_SCRIPTS","dev","build","lint","test","trivy","packageJson","scripts","nxVersion","version","nx","dirname","projectName","generators","entries","_","v","k","name","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy"],"mappings":"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"}
|
package/src/utils/mcp.d.ts
CHANGED
|
@@ -11,8 +11,17 @@ export declare const NX_PLUGIN_MCP_SERVER_NAME = "nx-plugin-for-aws";
|
|
|
11
11
|
* Command used to launch the Nx Plugin for AWS MCP server.
|
|
12
12
|
*/
|
|
13
13
|
export declare const NX_PLUGIN_MCP_SERVER_COMMAND = "npx";
|
|
14
|
+
/**
|
|
15
|
+
* Package providing the Nx Plugin for AWS MCP server.
|
|
16
|
+
*/
|
|
17
|
+
export declare const NX_PLUGIN_MCP_PACKAGE_NAME = "@aws/nx-plugin-mcp";
|
|
14
18
|
/**
|
|
15
19
|
* Arguments used to launch the Nx Plugin for AWS MCP server.
|
|
20
|
+
*
|
|
21
|
+
* npx prefers a locally installed package over the registry, and generators
|
|
22
|
+
* declare this package as a workspace devDependency, so the server tracks the
|
|
23
|
+
* version in the workspace's lockfile. `-y` falls back to fetching from the
|
|
24
|
+
* registry for a workspace where it isn't installed.
|
|
16
25
|
*/
|
|
17
26
|
export declare const NX_PLUGIN_MCP_SERVER_ARGS: string[];
|
|
18
27
|
/**
|
package/src/utils/mcp.js
CHANGED
|
@@ -9,11 +9,19 @@ import { updateToml } from "./toml.js";
|
|
|
9
9
|
/**
|
|
10
10
|
* Command used to launch the Nx Plugin for AWS MCP server.
|
|
11
11
|
*/ export const NX_PLUGIN_MCP_SERVER_COMMAND = 'npx';
|
|
12
|
+
/**
|
|
13
|
+
* Package providing the Nx Plugin for AWS MCP server.
|
|
14
|
+
*/ export const NX_PLUGIN_MCP_PACKAGE_NAME = '@aws/nx-plugin-mcp';
|
|
12
15
|
/**
|
|
13
16
|
* Arguments used to launch the Nx Plugin for AWS MCP server.
|
|
17
|
+
*
|
|
18
|
+
* npx prefers a locally installed package over the registry, and generators
|
|
19
|
+
* declare this package as a workspace devDependency, so the server tracks the
|
|
20
|
+
* version in the workspace's lockfile. `-y` falls back to fetching from the
|
|
21
|
+
* registry for a workspace where it isn't installed.
|
|
14
22
|
*/ export const NX_PLUGIN_MCP_SERVER_ARGS = [
|
|
15
23
|
'-y',
|
|
16
|
-
|
|
24
|
+
NX_PLUGIN_MCP_PACKAGE_NAME
|
|
17
25
|
];
|
|
18
26
|
/**
|
|
19
27
|
* A single stdio MCP server entry, shared by agents that use the `mcpServers` config shape.
|
package/src/utils/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/mcp.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readJson, type Tree, writeJson } from '@nx/devkit';\nimport { updateToml } from './toml';\n\n/**\n * Name of the Nx Plugin for AWS MCP server, used as the key in each agent's config.\n */\nexport const NX_PLUGIN_MCP_SERVER_NAME = 'nx-plugin-for-aws';\n\n/**\n * Command used to launch the Nx Plugin for AWS MCP server.\n */\nexport const NX_PLUGIN_MCP_SERVER_COMMAND = 'npx';\n\n/**\n * Arguments used to launch the Nx Plugin for AWS MCP server.\n */\nexport const NX_PLUGIN_MCP_SERVER_ARGS = ['-y',
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/mcp.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readJson, type Tree, writeJson } from '@nx/devkit';\nimport { updateToml } from './toml';\n\n/**\n * Name of the Nx Plugin for AWS MCP server, used as the key in each agent's config.\n */\nexport const NX_PLUGIN_MCP_SERVER_NAME = 'nx-plugin-for-aws';\n\n/**\n * Command used to launch the Nx Plugin for AWS MCP server.\n */\nexport const NX_PLUGIN_MCP_SERVER_COMMAND = 'npx';\n\n/**\n * Package providing the Nx Plugin for AWS MCP server.\n */\nexport const NX_PLUGIN_MCP_PACKAGE_NAME = '@aws/nx-plugin-mcp';\n\n/**\n * Arguments used to launch the Nx Plugin for AWS MCP server.\n *\n * npx prefers a locally installed package over the registry, and generators\n * declare this package as a workspace devDependency, so the server tracks the\n * version in the workspace's lockfile. `-y` falls back to fetching from the\n * registry for a workspace where it isn't installed.\n */\nexport const NX_PLUGIN_MCP_SERVER_ARGS = ['-y', NX_PLUGIN_MCP_PACKAGE_NAME];\n\n/**\n * A single stdio MCP server entry, shared by agents that use the `mcpServers` config shape.\n */\nconst stdioServerEntry = () => ({\n command: NX_PLUGIN_MCP_SERVER_COMMAND,\n args: NX_PLUGIN_MCP_SERVER_ARGS,\n});\n\n/**\n * Merge the Nx Plugin for AWS MCP server into a JSON config file under the given key,\n * preserving any other servers already configured. Creates the file if it does not exist.\n */\nconst mergeJsonMcpConfig = (\n tree: Tree,\n filePath: string,\n key: 'mcpServers' | 'servers',\n entry: Record<string, unknown>,\n) => {\n const config = tree.exists(filePath) ? readJson(tree, filePath) : {};\n config[key] = {\n ...config[key],\n [NX_PLUGIN_MCP_SERVER_NAME]: entry,\n };\n writeJson(tree, filePath, config);\n};\n\n/**\n * Configure the Nx Plugin for AWS MCP server across the project-level config locations\n * used by common coding agents, so agents working in the workspace can use it to scaffold\n * AWS projects with the Nx Plugin for AWS.\n *\n * Existing servers and unrelated config in each file are preserved.\n */\nexport const configureMcpServers = (tree: Tree) => {\n // Agents using the `mcpServers` config shape (Claude Code, Cursor, Kiro, Gemini CLI)\n const mcpServersFiles = [\n '.mcp.json', // Claude Code\n '.cursor/mcp.json', // Cursor\n '.kiro/settings/mcp.json', // Kiro\n '.gemini/settings.json', // Gemini CLI\n ];\n for (const filePath of mcpServersFiles) {\n mergeJsonMcpConfig(tree, filePath, 'mcpServers', stdioServerEntry());\n }\n\n // GitHub Copilot uses the `servers` key with an explicit `type`\n mergeJsonMcpConfig(tree, '.vscode/mcp.json', 'servers', {\n type: 'stdio',\n ...stdioServerEntry(),\n });\n\n // OpenAI Codex CLI uses TOML under the `mcp_servers` table\n const codexConfig = '.codex/config.toml';\n if (!tree.exists(codexConfig)) {\n tree.write(codexConfig, '');\n }\n updateToml(tree, codexConfig, (prev) => ({\n ...prev,\n mcp_servers: {\n ...(prev.mcp_servers as object),\n [NX_PLUGIN_MCP_SERVER_NAME]: {\n command: NX_PLUGIN_MCP_SERVER_COMMAND,\n args: NX_PLUGIN_MCP_SERVER_ARGS,\n },\n },\n }));\n};\n"],"names":["readJson","writeJson","updateToml","NX_PLUGIN_MCP_SERVER_NAME","NX_PLUGIN_MCP_SERVER_COMMAND","NX_PLUGIN_MCP_PACKAGE_NAME","NX_PLUGIN_MCP_SERVER_ARGS","stdioServerEntry","command","args","mergeJsonMcpConfig","tree","filePath","key","entry","config","exists","configureMcpServers","mcpServersFiles","type","codexConfig","write","prev","mcp_servers"],"mappings":"AAAA;;;CAGC,GACD,SAASA,QAAQ,EAAaC,SAAS,QAAQ,aAAa;AAC5D,SAASC,UAAU,QAAQ,YAAS;AAEpC;;CAEC,GACD,OAAO,MAAMC,4BAA4B,oBAAoB;AAE7D;;CAEC,GACD,OAAO,MAAMC,+BAA+B,MAAM;AAElD;;CAEC,GACD,OAAO,MAAMC,6BAA6B,qBAAqB;AAE/D;;;;;;;CAOC,GACD,OAAO,MAAMC,4BAA4B;IAAC;IAAMD;CAA2B,CAAC;AAE5E;;CAEC,GACD,MAAME,mBAAmB,IAAO,CAAA;QAC9BC,SAASJ;QACTK,MAAMH;IACR,CAAA;AAEA;;;CAGC,GACD,MAAMI,qBAAqB,CACzBC,MACAC,UACAC,KACAC;IAEA,MAAMC,SAASJ,KAAKK,MAAM,CAACJ,YAAYZ,SAASW,MAAMC,YAAY,CAAC;IACnEG,MAAM,CAACF,IAAI,GAAG;QACZ,GAAGE,MAAM,CAACF,IAAI;QACd,CAACV,0BAA0B,EAAEW;IAC/B;IACAb,UAAUU,MAAMC,UAAUG;AAC5B;AAEA;;;;;;CAMC,GACD,OAAO,MAAME,sBAAsB,CAACN;IAClC,qFAAqF;IACrF,MAAMO,kBAAkB;QACtB;QACA;QACA;QACA;KACD;IACD,KAAK,MAAMN,YAAYM,gBAAiB;QACtCR,mBAAmBC,MAAMC,UAAU,cAAcL;IACnD;IAEA,gEAAgE;IAChEG,mBAAmBC,MAAM,oBAAoB,WAAW;QACtDQ,MAAM;QACN,GAAGZ,kBAAkB;IACvB;IAEA,2DAA2D;IAC3D,MAAMa,cAAc;IACpB,IAAI,CAACT,KAAKK,MAAM,CAACI,cAAc;QAC7BT,KAAKU,KAAK,CAACD,aAAa;IAC1B;IACAlB,WAAWS,MAAMS,aAAa,CAACE,OAAU,CAAA;YACvC,GAAGA,IAAI;YACPC,aAAa;gBACX,GAAID,KAAKC,WAAW;gBACpB,CAACpB,0BAA0B,EAAE;oBAC3BK,SAASJ;oBACTK,MAAMH;gBACR;YACF;QACF,CAAA;AACF,EAAE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { compare } from 'semver';
|
|
6
|
+
/**
|
|
7
|
+
* Version stamping for migrations.
|
|
8
|
+
*
|
|
9
|
+
* A new migration is committed with no `version` — releases are calculated from
|
|
10
|
+
* conventional commits and written only to `dist/` and a git tag, so versions
|
|
11
|
+
* reach the published `migrations.json` two ways:
|
|
12
|
+
*
|
|
13
|
+
* - At release time (`scripts/stamp-migrations.ts`) entries still missing a
|
|
14
|
+
* version are stamped into the compiled `migrations.json`: an already shipped
|
|
15
|
+
* one gets the earliest release tag registering it, and a net-new one gets the
|
|
16
|
+
* version the release is about to publish, which the release job passes in
|
|
17
|
+
* after `nx release version` writes it to the dist manifests.
|
|
18
|
+
* - The weekly `update-versions` PR backfills the version of the release that
|
|
19
|
+
* shipped each migration, moving and re-keying it accordingly
|
|
20
|
+
* (`scripts/backfill-migration-versions.ts`), so source converges on the
|
|
21
|
+
* versions of everything already released.
|
|
22
|
+
*
|
|
23
|
+
* A version already in source always wins, so backfilled entries are stable.
|
|
24
|
+
*/
|
|
25
|
+
export interface MigrationsJson {
|
|
26
|
+
generators?: Record<string, {
|
|
27
|
+
version?: string;
|
|
28
|
+
} & Record<string, unknown>>;
|
|
29
|
+
}
|
|
30
|
+
/** Ascending semver comparator for `Array.prototype.sort`. */
|
|
31
|
+
export declare const compareVersions: typeof compare;
|
|
32
|
+
/** Whether a string is an exact semver version. */
|
|
33
|
+
export declare const isValidVersion: (version: string) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Map of migration key -> version of the earliest release that registers it,
|
|
36
|
+
* resolved only for the entries still missing a `version` (one already recorded
|
|
37
|
+
* in source wins, so its history doesn't need reading). A migration that hasn't
|
|
38
|
+
* been released is absent.
|
|
39
|
+
*
|
|
40
|
+
* Walks releases newest first and stops as soon as every entry is resolved: an
|
|
41
|
+
* entry that has disappeared from a release's `migrations.json` was first
|
|
42
|
+
* registered by the release after it, which is the one that shipped it.
|
|
43
|
+
*
|
|
44
|
+
* @param migrations parsed source migrations.json
|
|
45
|
+
* @param versions released versions in descending semver order
|
|
46
|
+
* @param readReleasedMigrations reads the `migrations.json` published by a given
|
|
47
|
+
* version, or undefined if it predates the manifest
|
|
48
|
+
*/
|
|
49
|
+
export declare const readShippedMigrationVersions: (migrations: MigrationsJson, versions: string[], readReleasedMigrations: (version: string) => MigrationsJson | undefined) => Record<string, string>;
|
|
50
|
+
/**
|
|
51
|
+
* Return a copy of the migrations collection with a `version` stamped onto
|
|
52
|
+
* every generator entry, preserving any already present.
|
|
53
|
+
*
|
|
54
|
+
* @param migrations parsed migrations.json to stamp
|
|
55
|
+
* @param shippedVersions migration key -> version of the earliest release
|
|
56
|
+
* tag that registers it (absent for migrations that haven't shipped)
|
|
57
|
+
* @param pendingVersion version the release is about to publish, stamped onto
|
|
58
|
+
* unshipped migrations so their version is one that really shipped
|
|
59
|
+
*/
|
|
60
|
+
export declare const stampMigrationVersions: (migrations: MigrationsJson, shippedVersions: Record<string, string>, pendingVersion: string) => MigrationsJson;
|
|
61
|
+
/** Directory a newly scaffolded migration lands in, before a release claims it. */
|
|
62
|
+
export declare const LATEST_MIGRATIONS_DIR = "latest";
|
|
63
|
+
/** Directory holding the migrations shipped by a given release. */
|
|
64
|
+
export declare const versionMigrationsDir: (version: string) => string;
|
|
65
|
+
/**
|
|
66
|
+
* Key a migration is registered under in `migrations.json`. Prefixed with its
|
|
67
|
+
* directory so reusing a name in a later release can't silently overwrite the
|
|
68
|
+
* one that already shipped.
|
|
69
|
+
*/
|
|
70
|
+
export declare const migrationKey: (dir: string, name: string) => string;
|
|
71
|
+
/** A migration directory move the caller needs to make on disk. */
|
|
72
|
+
export interface MigrationDirMove {
|
|
73
|
+
name: string;
|
|
74
|
+
version: string;
|
|
75
|
+
from: string;
|
|
76
|
+
to: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Record the release that shipped each migration on entries without a version,
|
|
80
|
+
* re-keying them and re-pointing their paths at that release's folder, and
|
|
81
|
+
* return the collection alongside the keys that changed and the directory moves
|
|
82
|
+
* to make on disk.
|
|
83
|
+
*
|
|
84
|
+
* Unlike `stampMigrationVersions` this only records already-released versions,
|
|
85
|
+
* leaving the release to decide what a net-new migration gets.
|
|
86
|
+
*
|
|
87
|
+
* @param migrations parsed migrations.json to backfill
|
|
88
|
+
* @param shippedVersions migration key -> version of the earliest release tag
|
|
89
|
+
* that registers it (absent for migrations that haven't shipped)
|
|
90
|
+
*/
|
|
91
|
+
export declare const backfillMigrationVersions: (migrations: MigrationsJson, shippedVersions: Record<string, string>) => {
|
|
92
|
+
migrations: MigrationsJson;
|
|
93
|
+
backfilled: string[];
|
|
94
|
+
moves: MigrationDirMove[];
|
|
95
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { compare, valid } from "semver";
|
|
5
|
+
/** Ascending semver comparator for `Array.prototype.sort`. */ export const compareVersions = compare;
|
|
6
|
+
/** Whether a string is an exact semver version. */ export const isValidVersion = (version)=>valid(version) !== null;
|
|
7
|
+
/**
|
|
8
|
+
* Map of migration key -> version of the earliest release that registers it,
|
|
9
|
+
* resolved only for the entries still missing a `version` (one already recorded
|
|
10
|
+
* in source wins, so its history doesn't need reading). A migration that hasn't
|
|
11
|
+
* been released is absent.
|
|
12
|
+
*
|
|
13
|
+
* Walks releases newest first and stops as soon as every entry is resolved: an
|
|
14
|
+
* entry that has disappeared from a release's `migrations.json` was first
|
|
15
|
+
* registered by the release after it, which is the one that shipped it.
|
|
16
|
+
*
|
|
17
|
+
* @param migrations parsed source migrations.json
|
|
18
|
+
* @param versions released versions in descending semver order
|
|
19
|
+
* @param readReleasedMigrations reads the `migrations.json` published by a given
|
|
20
|
+
* version, or undefined if it predates the manifest
|
|
21
|
+
*/ export const readShippedMigrationVersions = (migrations, versions, readReleasedMigrations)=>{
|
|
22
|
+
const shippedVersions = {};
|
|
23
|
+
let unresolved = Object.entries(migrations.generators ?? {}).filter(([, entry])=>!entry.version).map(([key])=>key);
|
|
24
|
+
for (const version of versions){
|
|
25
|
+
if (unresolved.length === 0) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
const registered = new Set(Object.keys(readReleasedMigrations(version)?.generators ?? {}));
|
|
29
|
+
// Entries gone at this release keep the version recorded from the release
|
|
30
|
+
// after it (if any) and stop being looked up.
|
|
31
|
+
unresolved = unresolved.filter((key)=>registered.has(key));
|
|
32
|
+
for (const key of unresolved){
|
|
33
|
+
shippedVersions[key] = version;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return shippedVersions;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Return a copy of the migrations collection with a `version` stamped onto
|
|
40
|
+
* every generator entry, preserving any already present.
|
|
41
|
+
*
|
|
42
|
+
* @param migrations parsed migrations.json to stamp
|
|
43
|
+
* @param shippedVersions migration key -> version of the earliest release
|
|
44
|
+
* tag that registers it (absent for migrations that haven't shipped)
|
|
45
|
+
* @param pendingVersion version the release is about to publish, stamped onto
|
|
46
|
+
* unshipped migrations so their version is one that really shipped
|
|
47
|
+
*/ export const stampMigrationVersions = (migrations, shippedVersions, pendingVersion)=>({
|
|
48
|
+
...migrations,
|
|
49
|
+
generators: Object.fromEntries(Object.entries(migrations.generators ?? {}).map(([name, entry])=>[
|
|
50
|
+
name,
|
|
51
|
+
{
|
|
52
|
+
version: shippedVersions[name] ?? pendingVersion,
|
|
53
|
+
...entry
|
|
54
|
+
}
|
|
55
|
+
]))
|
|
56
|
+
});
|
|
57
|
+
/** Directory a newly scaffolded migration lands in, before a release claims it. */ export const LATEST_MIGRATIONS_DIR = 'latest';
|
|
58
|
+
/** Directory holding the migrations shipped by a given release. */ export const versionMigrationsDir = (version)=>`v${version}`;
|
|
59
|
+
/**
|
|
60
|
+
* Key a migration is registered under in `migrations.json`. Prefixed with its
|
|
61
|
+
* directory so reusing a name in a later release can't silently overwrite the
|
|
62
|
+
* one that already shipped.
|
|
63
|
+
*/ export const migrationKey = (dir, name)=>`${dir}-${name}`;
|
|
64
|
+
const LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;
|
|
65
|
+
/**
|
|
66
|
+
* Record the release that shipped each migration on entries without a version,
|
|
67
|
+
* re-keying them and re-pointing their paths at that release's folder, and
|
|
68
|
+
* return the collection alongside the keys that changed and the directory moves
|
|
69
|
+
* to make on disk.
|
|
70
|
+
*
|
|
71
|
+
* Unlike `stampMigrationVersions` this only records already-released versions,
|
|
72
|
+
* leaving the release to decide what a net-new migration gets.
|
|
73
|
+
*
|
|
74
|
+
* @param migrations parsed migrations.json to backfill
|
|
75
|
+
* @param shippedVersions migration key -> version of the earliest release tag
|
|
76
|
+
* that registers it (absent for migrations that haven't shipped)
|
|
77
|
+
*/ export const backfillMigrationVersions = (migrations, shippedVersions)=>{
|
|
78
|
+
const generators = {};
|
|
79
|
+
const backfilled = [];
|
|
80
|
+
const moves = [];
|
|
81
|
+
for (const [key, entry] of Object.entries(migrations.generators ?? {})){
|
|
82
|
+
const version = shippedVersions[key];
|
|
83
|
+
if (entry.version || !version) {
|
|
84
|
+
generators[key] = entry;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const name = key.startsWith(LATEST_KEY_PREFIX) ? key.slice(LATEST_KEY_PREFIX.length) : key;
|
|
88
|
+
const versionDir = versionMigrationsDir(version);
|
|
89
|
+
const latestSegment = `/${LATEST_MIGRATIONS_DIR}/${name}/`;
|
|
90
|
+
const versionSegment = `/${versionDir}/${name}/`;
|
|
91
|
+
// Re-point each path field at the version folder, recording the move the
|
|
92
|
+
// caller needs to make on disk the first time one is found.
|
|
93
|
+
const repointed = {};
|
|
94
|
+
let moved = false;
|
|
95
|
+
for (const [field, value] of Object.entries(entry)){
|
|
96
|
+
if (typeof value !== 'string' || !value.includes(latestSegment)) {
|
|
97
|
+
repointed[field] = value;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
repointed[field] = value.replace(latestSegment, versionSegment);
|
|
101
|
+
if (!moved) {
|
|
102
|
+
moved = true;
|
|
103
|
+
const dir = value.slice(0, value.indexOf(latestSegment));
|
|
104
|
+
moves.push({
|
|
105
|
+
name,
|
|
106
|
+
version,
|
|
107
|
+
from: `${dir}${latestSegment}`.replace(/^\.\/|\/$/g, ''),
|
|
108
|
+
to: `${dir}${versionSegment}`.replace(/^\.\/|\/$/g, '')
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
generators[migrationKey(versionDir, name)] = {
|
|
113
|
+
version,
|
|
114
|
+
...repointed
|
|
115
|
+
};
|
|
116
|
+
backfilled.push(key);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
migrations: {
|
|
120
|
+
...migrations,
|
|
121
|
+
generators
|
|
122
|
+
},
|
|
123
|
+
backfilled,
|
|
124
|
+
moves
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=migration-versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/migration-versions.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { compare, valid } from 'semver';\n\n/**\n * Version stamping for migrations.\n *\n * A new migration is committed with no `version` — releases are calculated from\n * conventional commits and written only to `dist/` and a git tag, so versions\n * reach the published `migrations.json` two ways:\n *\n * - At release time (`scripts/stamp-migrations.ts`) entries still missing a\n * version are stamped into the compiled `migrations.json`: an already shipped\n * one gets the earliest release tag registering it, and a net-new one gets the\n * version the release is about to publish, which the release job passes in\n * after `nx release version` writes it to the dist manifests.\n * - The weekly `update-versions` PR backfills the version of the release that\n * shipped each migration, moving and re-keying it accordingly\n * (`scripts/backfill-migration-versions.ts`), so source converges on the\n * versions of everything already released.\n *\n * A version already in source always wins, so backfilled entries are stable.\n */\n\nexport interface MigrationsJson {\n generators?: Record<string, { version?: string } & Record<string, unknown>>;\n}\n\n/** Ascending semver comparator for `Array.prototype.sort`. */\nexport const compareVersions = compare;\n\n/** Whether a string is an exact semver version. */\nexport const isValidVersion = (version: string): boolean =>\n valid(version) !== null;\n\n/**\n * Map of migration key -> version of the earliest release that registers it,\n * resolved only for the entries still missing a `version` (one already recorded\n * in source wins, so its history doesn't need reading). A migration that hasn't\n * been released is absent.\n *\n * Walks releases newest first and stops as soon as every entry is resolved: an\n * entry that has disappeared from a release's `migrations.json` was first\n * registered by the release after it, which is the one that shipped it.\n *\n * @param migrations parsed source migrations.json\n * @param versions released versions in descending semver order\n * @param readReleasedMigrations reads the `migrations.json` published by a given\n * version, or undefined if it predates the manifest\n */\nexport const readShippedMigrationVersions = (\n migrations: MigrationsJson,\n versions: string[],\n readReleasedMigrations: (version: string) => MigrationsJson | undefined,\n): Record<string, string> => {\n const shippedVersions: Record<string, string> = {};\n let unresolved = Object.entries(migrations.generators ?? {})\n .filter(([, entry]) => !entry.version)\n .map(([key]) => key);\n\n for (const version of versions) {\n if (unresolved.length === 0) {\n break;\n }\n const registered = new Set(\n Object.keys(readReleasedMigrations(version)?.generators ?? {}),\n );\n // Entries gone at this release keep the version recorded from the release\n // after it (if any) and stop being looked up.\n unresolved = unresolved.filter((key) => registered.has(key));\n for (const key of unresolved) {\n shippedVersions[key] = version;\n }\n }\n\n return shippedVersions;\n};\n\n/**\n * Return a copy of the migrations collection with a `version` stamped onto\n * every generator entry, preserving any already present.\n *\n * @param migrations parsed migrations.json to stamp\n * @param shippedVersions migration key -> version of the earliest release\n * tag that registers it (absent for migrations that haven't shipped)\n * @param pendingVersion version the release is about to publish, stamped onto\n * unshipped migrations so their version is one that really shipped\n */\nexport const stampMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n pendingVersion: string,\n): MigrationsJson => ({\n ...migrations,\n generators: Object.fromEntries(\n Object.entries(migrations.generators ?? {}).map(([name, entry]) => [\n name,\n { version: shippedVersions[name] ?? pendingVersion, ...entry },\n ]),\n ),\n});\n\n/** Directory a newly scaffolded migration lands in, before a release claims it. */\nexport const LATEST_MIGRATIONS_DIR = 'latest';\n\n/** Directory holding the migrations shipped by a given release. */\nexport const versionMigrationsDir = (version: string) => `v${version}`;\n\n/**\n * Key a migration is registered under in `migrations.json`. Prefixed with its\n * directory so reusing a name in a later release can't silently overwrite the\n * one that already shipped.\n */\nexport const migrationKey = (dir: string, name: string) => `${dir}-${name}`;\n\nconst LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;\n\n/** A migration directory move the caller needs to make on disk. */\nexport interface MigrationDirMove {\n name: string;\n version: string;\n from: string;\n to: string;\n}\n\n/**\n * Record the release that shipped each migration on entries without a version,\n * re-keying them and re-pointing their paths at that release's folder, and\n * return the collection alongside the keys that changed and the directory moves\n * to make on disk.\n *\n * Unlike `stampMigrationVersions` this only records already-released versions,\n * leaving the release to decide what a net-new migration gets.\n *\n * @param migrations parsed migrations.json to backfill\n * @param shippedVersions migration key -> version of the earliest release tag\n * that registers it (absent for migrations that haven't shipped)\n */\nexport const backfillMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n): {\n migrations: MigrationsJson;\n backfilled: string[];\n moves: MigrationDirMove[];\n} => {\n const generators: NonNullable<MigrationsJson['generators']> = {};\n const backfilled: string[] = [];\n const moves: MigrationDirMove[] = [];\n\n for (const [key, entry] of Object.entries(migrations.generators ?? {})) {\n const version = shippedVersions[key];\n if (entry.version || !version) {\n generators[key] = entry;\n continue;\n }\n\n const name = key.startsWith(LATEST_KEY_PREFIX)\n ? key.slice(LATEST_KEY_PREFIX.length)\n : key;\n const versionDir = versionMigrationsDir(version);\n const latestSegment = `/${LATEST_MIGRATIONS_DIR}/${name}/`;\n const versionSegment = `/${versionDir}/${name}/`;\n\n // Re-point each path field at the version folder, recording the move the\n // caller needs to make on disk the first time one is found.\n const repointed: Record<string, unknown> = {};\n let moved = false;\n for (const [field, value] of Object.entries(entry)) {\n if (typeof value !== 'string' || !value.includes(latestSegment)) {\n repointed[field] = value;\n continue;\n }\n repointed[field] = value.replace(latestSegment, versionSegment);\n if (!moved) {\n moved = true;\n const dir = value.slice(0, value.indexOf(latestSegment));\n moves.push({\n name,\n version,\n from: `${dir}${latestSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n to: `${dir}${versionSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n });\n }\n }\n\n generators[migrationKey(versionDir, name)] = { version, ...repointed };\n backfilled.push(key);\n }\n\n return { migrations: { ...migrations, generators }, backfilled, moves };\n};\n"],"names":["compare","valid","compareVersions","isValidVersion","version","readShippedMigrationVersions","migrations","versions","readReleasedMigrations","shippedVersions","unresolved","Object","entries","generators","filter","entry","map","key","length","registered","Set","keys","has","stampMigrationVersions","pendingVersion","fromEntries","name","LATEST_MIGRATIONS_DIR","versionMigrationsDir","migrationKey","dir","LATEST_KEY_PREFIX","backfillMigrationVersions","backfilled","moves","startsWith","slice","versionDir","latestSegment","versionSegment","repointed","moved","field","value","includes","replace","indexOf","push","from","to"],"mappings":"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"}
|