@aws/nx-plugin 1.0.0-rc.46 → 1.0.0-rc.47
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 +3 -60
- package/generators.json +1 -1
- package/package.json +7 -3
- package/src/agentcore-gateway/generator.js +12 -2
- package/src/agentcore-gateway/generator.js.map +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +25 -31
- package/src/infra/app/generator.js +9 -6
- package/src/infra/app/generator.js.map +1 -1
- package/src/license/config.js +1 -1
- package/src/license/config.js.map +1 -1
- package/src/mcp-server/schema.d.ts +1 -1
- package/src/mcp-server/tools/general-guidance.js +5 -6
- package/src/mcp-server/tools/general-guidance.js.map +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +38 -7
- package/src/preset/generator.d.ts +1 -1
- package/src/preset/generator.js +4 -2
- package/src/preset/generator.js.map +1 -1
- package/src/preset/schema.d.js.map +1 -1
- package/src/preset/schema.d.ts +1 -0
- package/src/preset/schema.json +5 -0
- package/src/py/agent/generator.js +2 -1
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/mcp-server/generator.js +2 -1
- package/src/py/mcp-server/generator.js.map +1 -1
- package/src/py/project/generator.js +2 -1
- package/src/py/project/generator.js.map +1 -1
- package/src/py/rdb/generator.js +2 -1
- package/src/py/rdb/generator.js.map +1 -1
- package/src/smithy/ts/api/generator.js +5 -2
- package/src/smithy/ts/api/generator.js.map +1 -1
- package/src/terraform/project/generator.js +4 -1
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +6 -6
- package/src/trpc/backend/generator.js +7 -5
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/react/generator.js +4 -4
- package/src/trpc/react/generator.js.map +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/agent/a2a-connection/generator.js +3 -2
- package/src/ts/agent/a2a-connection/generator.js.map +1 -1
- package/src/ts/agent/gateway-connection/generator.js +4 -3
- package/src/ts/agent/gateway-connection/generator.js.map +1 -1
- package/src/ts/agent/generator.js +8 -5
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/agent/mcp-connection/generator.js +4 -3
- package/src/ts/agent/mcp-connection/generator.js.map +1 -1
- package/src/ts/agent/react-connection/generator.js +10 -19
- package/src/ts/agent/react-connection/generator.js.map +1 -1
- package/src/ts/astro-docs/generator.js +12 -3
- package/src/ts/astro-docs/generator.js.map +1 -1
- package/src/ts/dcr-proxy/generator.js +5 -5
- package/src/ts/dcr-proxy/generator.js.map +1 -1
- package/src/ts/dynamodb/generator.js +5 -2
- package/src/ts/dynamodb/generator.js.map +1 -1
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +4 -2
- package/src/ts/lambda-function/files/handler/__lambdaFunctionKebabCase__.ts.template +2 -1
- package/src/ts/lambda-function/generator.js +3 -2
- package/src/ts/lambda-function/generator.js.map +1 -1
- package/src/ts/lib/ts-project-utils.js +17 -10
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- package/src/ts/lib/vitest.js +2 -1
- package/src/ts/lib/vitest.js.map +1 -1
- package/src/ts/mcp-server/generator.js +11 -11
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/nx-generator/generator.js +5 -0
- package/src/ts/nx-generator/generator.js.map +1 -1
- package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +5 -6
- package/src/ts/nx-plugin/files/mcp-server/resources/GENERAL_GUIDANCE.md.template +5 -6
- package/src/ts/nx-plugin/utils.js +2 -1
- package/src/ts/nx-plugin/utils.js.map +1 -1
- package/src/ts/rdb/agent-connection/generator.js +1 -2
- package/src/ts/rdb/agent-connection/generator.js.map +1 -1
- package/src/ts/rdb/generator.js +10 -6
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/rdb/mcp-server-connection/generator.js +1 -2
- package/src/ts/rdb/mcp-server-connection/generator.js.map +1 -1
- package/src/ts/rdb/smithy-connection/generator.js +1 -2
- package/src/ts/rdb/smithy-connection/generator.js.map +1 -1
- package/src/ts/rdb/trpc-connection/generator.js +1 -2
- package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
- package/src/ts/react-website/agui/generator.js +5 -4
- package/src/ts/react-website/agui/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +210 -79
- package/src/ts/react-website/app/generator.js +34 -14
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/ts/react-website/cognito-auth/generator.js +3 -2
- package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
- package/src/ts/react-website/runtime-config/generator.js +2 -2
- package/src/ts/react-website/runtime-config/generator.js.map +1 -1
- package/src/ts/sync/generator.js +81 -3
- package/src/ts/sync/generator.js.map +1 -1
- package/src/utils/agent-connection/agent-connection.d.ts +1 -1
- package/src/utils/agent-connection/agent-connection.js +50 -1
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js +10 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/api-constructs/api-constructs.js +15 -1
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/bundle/bundle.js +2 -1
- package/src/utils/bundle/bundle.js.map +1 -1
- package/src/utils/commands.d.ts +5 -3
- package/src/utils/commands.js +24 -3
- package/src/utils/commands.js.map +1 -1
- package/src/utils/config/index.d.ts +16 -0
- package/src/utils/config/index.js.map +1 -1
- package/src/utils/config/utils.d.ts +3 -2
- package/src/utils/config/utils.js +4 -3
- package/src/utils/config/utils.js.map +1 -1
- package/src/utils/connection/open-api/react.js +3 -2
- package/src/utils/connection/open-api/react.js.map +1 -1
- package/src/utils/containers.js +1 -1
- package/src/utils/containers.js.map +1 -1
- package/src/utils/dependencies.d.ts +18 -0
- package/src/utils/dependencies.js +206 -0
- package/src/utils/dependencies.js.map +1 -0
- package/src/utils/files/common/shadcn/readme/README.md.template +3 -3
- package/src/utils/files/shadcn/components.json.template +1 -1
- package/src/utils/format.d.ts +20 -1
- package/src/utils/format.js +83 -49
- package/src/utils/format.js.map +1 -1
- package/src/utils/fs.d.ts +1 -1
- package/src/utils/fs.js +1 -1
- package/src/utils/fs.js.map +1 -1
- package/src/utils/iac.js +1 -1
- package/src/utils/iac.js.map +1 -1
- package/src/utils/init.d.ts +7 -1
- package/src/utils/init.js +38 -17
- package/src/utils/init.js.map +1 -1
- package/src/utils/install.js +3 -1
- package/src/utils/install.js.map +1 -1
- package/src/utils/module-format.d.ts +5 -8
- package/src/utils/module-format.js +29 -12
- package/src/utils/module-format.js.map +1 -1
- package/src/utils/npm-scope.d.ts +0 -4
- package/src/utils/npm-scope.js +0 -5
- package/src/utils/npm-scope.js.map +1 -1
- package/src/utils/pnpm-workspace.d.ts +1 -12
- package/src/utils/pnpm-workspace.js +3 -30
- package/src/utils/pnpm-workspace.js.map +1 -1
- package/src/utils/project-package-json.d.ts +39 -0
- package/src/utils/project-package-json.js +119 -0
- package/src/utils/project-package-json.js.map +1 -0
- package/src/utils/shared-constructs.js +6 -5
- package/src/utils/shared-constructs.js.map +1 -1
- package/src/utils/shared-dynamodb-scripts.js +4 -2
- package/src/utils/shared-dynamodb-scripts.js.map +1 -1
- package/src/utils/shared-infra-scripts.js +5 -4
- package/src/utils/shared-infra-scripts.js.map +1 -1
- package/src/utils/shared-rdb-scripts.js +14 -1
- package/src/utils/shared-rdb-scripts.js.map +1 -1
- package/src/utils/shared-shadcn.js +11 -8
- package/src/utils/shared-shadcn.js.map +1 -1
- package/src/utils/test.js +8 -3
- package/src/utils/test.js.map +1 -1
- package/src/utils/versions.d.ts +3 -0
- package/src/utils/versions.js +3 -0
- package/src/utils/versions.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/agent/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config';\nimport { AG_UI_LANGGRAPH_EXCEPTIONS } from '../../license/known-exceptions';\nimport { addAgentChatScripts } from '../../utils/agent-chat/agent-chat';\nimport {\n addPythonFrameworkBase,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n} from '../../utils/agent-connection/agent-connection';\nimport { addAgentInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { updateGitIgnore } from '../../utils/git';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { sortObjectKeys } from '../../utils/object';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { assignPort } from '../../utils/port';\nimport {\n addDependenciesToDependencyGroupInPyProjectToml,\n addDependenciesToPyProjectToml,\n addWorkspaceDependencyToPyProject,\n} from '../../utils/py';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport { BASE_IMAGES, withVersions } from '../../utils/versions';\nimport type { PyAgentGeneratorSchema } from './schema';\n\nexport const PY_AGENT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyAgentGenerator = async (\n tree: Tree,\n options: PyAgentGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-agent`,\n );\n const agentTargetPrefix = options.name ? name : 'agent';\n\n const agentNameSnakeCase = toSnakeCase(options.name || 'agent');\n const agentNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n agentNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n const protocol = options.protocol ?? 'http';\n const framework = options.framework ?? 'strands';\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Ensure the shared agent-connection project exists so the server entry\n // point can import `session_id_context` and propagate the AgentCore\n // session ID to any downstream MCP / A2A clients a later connection\n // generator wires into this agent.\n await ensurePythonAgentConnectionProject(tree);\n // The agent server imports the framework base helpers (session cache + model\n // error logging) regardless of whether a connection client is wired in. The\n // langchain framework has no base layer (its AG-UI foundation reuses only the\n // framework-agnostic session context), so this is a no-op for langchain.\n await addPythonFrameworkBase(tree, framework);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n addWorkspaceDependencyToPyProject(\n tree,\n project,\n getPythonAgentConnectionProject(tree),\n );\n\n const templateContext = {\n name,\n agentNameSnakeCase,\n agentNameClassName,\n moduleName,\n agentConnectionModuleName,\n framework,\n };\n\n // Generate common files shared by both protocols. The agent module (agent.py)\n // is framework-specific (Strands yields a contextmanaged Agent; LangChain\n // returns a compiled create_agent graph), so it comes from a per-framework\n // dir. The package __init__.py is framework-agnostic (it stays in `common`).\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n framework === 'langchain' ? 'common-langchain' : 'common',\n ),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n if (framework === 'langchain') {\n // common-langchain only carries agent.py; the empty package __init__.py is\n // framework-agnostic, so emit it from the shared `common` dir.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'common'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\n\n // Generate protocol-specific files. Each protocol's server entry point is\n // framework-specific (Strands yields a contextmanaged Agent; LangChain drives\n // a compiled create_agent graph), so it comes from a per-framework dir\n // `<protocol>-langchain` for LangChain, or `<protocol>` for Strands.\n const protocolLower = protocol.toLowerCase();\n const protocolTemplateDir =\n framework === 'langchain' ? `${protocolLower}-langchain` : protocolLower;\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', protocolTemplateDir),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n // The HTTP server's init.py (the FastAPI app + JsonStreamingResponse) is\n // framework-agnostic and the LangChain http main.py reuses it, so emit it\n // from the shared `http` dir. Emitted after the langchain main.py above so\n // KeepExisting preserves that main.py and only adds init.py (the shared dir's\n // own Strands main.py is skipped).\n if (protocolLower === 'http' && framework === 'langchain') {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'http'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\n\n addDependenciesToPyProjectToml(tree, project.root, [\n 'aws-lambda-powertools',\n 'aws-opentelemetry-distro',\n 'bedrock-agentcore',\n 'boto3',\n 'fastapi',\n 'mcp',\n ...(framework === 'langchain'\n ? // langchain pulls no Strands dependencies — the langchain model binding\n // (langchain, langchain-aws, langgraph) plus the per-protocol server\n // adapter: ag-ui-langgraph for AG-UI, a2a-sdk for A2A, nothing extra for\n // HTTP (FastAPI is added above for every agent).\n ([\n 'langchain',\n 'langchain-aws',\n 'langgraph',\n ...(protocol === 'ag-ui'\n ? (['ag-ui-protocol', 'ag-ui-langgraph'] as const)\n : protocol === 'a2a'\n ? (['a2a-sdk'] as const)\n : ([] as const)),\n ] as const)\n : protocol === 'a2a'\n ? (['strands-agents[a2a]', 'strands-agents-tools'] as const)\n : protocol === 'ag-ui'\n ? ([\n 'strands-agents',\n 'strands-agents-tools',\n 'ag-ui-protocol',\n 'ag-ui-strands',\n ] as const)\n : (['strands-agents', 'strands-agents-tools'] as const)),\n 'uvicorn',\n ]);\n addDependenciesToDependencyGroupInPyProjectToml(tree, project.root, 'dev', [\n 'fastapi[standard]',\n ]);\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n // Add the Dockerfile\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n agentNameSnakeCase,\n moduleName,\n bundleOutputDir,\n protocol,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${agentTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project,\n containerEngine: containers,\n trivyTargetName: `${agentTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n });\n\n // Add shared constructs\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n\n // Add the construct to deploy the agent.\n // AG-UI uses HTTP as the AgentCore protocol type (AG-UI is HTTP-based with SSE over POST).\n const infraProtocol =\n protocol === 'ag-ui' ? ('http' as const) : (protocol as 'http' | 'a2a');\n await addAgentInfra(tree, {\n agentNameKebabCase: name,\n agentNameClassName,\n dockerImageTag,\n dockerOutputDir,\n iac,\n projectName: project.name,\n auth,\n serverProtocol: infraProtocol,\n containers,\n });\n }\n\n // A2A servers use port 9000 as per the Strands A2A SDK default and AgentCore A2A contract.\n // HTTP and AG-UI agents use port 8081+ to avoid conflict with VS Code server on 8080.\n const localDevPortStart = protocol === 'a2a' ? 9000 : 8081;\n const localDevPort = assignPort(tree, project, localDevPortStart, {\n component: { info: PY_AGENT_GENERATOR_INFO, name: agentTargetPrefix },\n });\n\n // All protocols use fastapi dev for hot reload:\n // - HTTP: FastAPI app directly defined in init.py\n // - A2A: A2AServer.to_fastapi_app() creates a FastAPI app in main.py\n // - AG-UI: create_strands_app() creates a FastAPI app in main.py\n const serveCommand = `uv run fastapi dev ${moduleName}/${agentNameSnakeCase}/main.py --port ${localDevPort}`;\n\n // HTTP chat uses the type-safe TypeScript client generated from the\n // agent's OpenAPI spec (same generated client the react-connection\n // generator produces). A2A and AG-UI speak standard protocols, so\n // we can run `agent-chat-cli` directly as a binary.\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const clientGenTargetName = `${agentTargetPrefix}-generate-client`;\n\n const scriptsDir = joinPathFragments(\n project.root,\n 'scripts',\n agentTargetPrefix,\n );\n\n if (protocol === 'http') {\n // Emit the OpenAPI spec generator script (shared with react-connection)\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'react-connection',\n 'files',\n 'agent',\n ),\n project.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ignore the generated client directory\n updateGitIgnore(tree, project.root, (patterns) => [\n ...patterns,\n `scripts/${agentTargetPrefix}/generated/`,\n ]);\n }\n\n // Every protocol gets a standalone `chat.ts`. It connects to the local\n // `dev` server by default, or to the deployed agent (with the\n // appropriate auth) when `RUNTIME_CONFIG_APP_ID` is set.\n addAgentChatScripts(tree, {\n scriptsDir,\n protocol,\n language: 'py',\n agentNameClassName,\n auth,\n });\n\n // TypeScript deps for the chat CLI, which runs standalone via tsx for every\n // protocol and resolves the deployed agent from AppConfig. `agent-chat-cli`\n // transitively bundles the protocol clients (@a2a-js/sdk, @ag-ui/client).\n addDependenciesToPackageJson(\n tree,\n {},\n withVersions([\n 'agent-chat-cli',\n 'tsx',\n '@types/node',\n '@aws-lambda-powertools/parameters',\n '@aws-sdk/client-appconfigdata',\n ...(auth === 'iam'\n ? (['aws4fetch', '@aws-sdk/credential-providers'] as const)\n : ([] as const)),\n ...(protocol === 'a2a' ? (['@a2a-js/sdk'] as const) : ([] as const)),\n ]),\n );\n\n const chatUrl =\n protocol === 'ag-ui'\n ? `http://localhost:${localDevPort}/invocations`\n : `http://localhost:${localDevPort}`;\n const chatCommand = `tsx ./scripts/${agentTargetPrefix}/chat.ts`;\n\n const httpOnlyTargets =\n protocol === 'http'\n ? {\n [openApiTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n [clientGenTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n dependsOn: [openApiTargetName],\n inputs: [\n {\n dependentTasksOutputFiles: '**/*.json',\n },\n ],\n outputs: [`{projectRoot}/scripts/${agentTargetPrefix}/generated`],\n options: {\n commands: [\n `nx g @aws/nx-plugin:open-api#ts-client --openApiSpecPath=\"dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json\" --outputPath=\"${project.root}/scripts/${agentTargetPrefix}/generated\" --no-interactive`,\n ],\n },\n },\n }\n : {};\n\n const agentTargets = {\n ...project.targets,\n ...httpOnlyTargets,\n [`${agentTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${agentTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n // HTTP chat imports the generated client, so ensure it's built first.\n // No dev dependency — chat runs standalone against a local or\n // deployed agent. normalizeTargetKeyOrder keeps the conditional dependsOn\n // in Nx 23's serialization order so re-runs stay byte-identical.\n [`${agentTargetPrefix}-chat`]: normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n options: {\n commands: [chatCommand],\n cwd: '{projectRoot}',\n env: {\n URL: chatUrl,\n },\n },\n ...(protocol === 'http' ? { dependsOn: [clientGenTargetName] } : {}),\n }),\n };\n\n // Aggregate `<agent>-dev` under the project-level `dev` target.\n addComponentDevTarget(agentTargets, `${agentTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: sortObjectKeys(agentTargets),\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_AGENT_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n agentTargetPrefix,\n {\n port: localDevPort,\n rc: agentNameClassName,\n auth,\n protocol,\n // The mcp / gateway connection generators dispatch on this field to pick\n // the Strands vs LangChain Layer-2 client + agent.py transform.\n framework,\n },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_AGENT_GENERATOR_INFO]);\n\n // langchain-core (pulled by every langchain agent regardless of protocol)\n // brings jsonpatch/jsonpointer, whose wheels ship without resolvable SPDX\n // license metadata, so register those exceptions so the workspace license\n // check still passes.\n if (framework === 'langchain') {\n await ensureLicenseExceptions(tree, AG_UI_LANGGRAPH_EXCEPTIONS);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyAgentGenerator;\n"],"names":["addDependenciesToPackageJson","generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","AG_UI_LANGGRAPH_EXCEPTIONS","addAgentChatScripts","addPythonFrameworkBase","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","addAgentInfra","addPythonBundleTarget","resolveContainers","addDockerScanTarget","formatFilesInSubtree","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","sortObjectKeys","toProjectRelativePath","assignPort","addDependenciesToDependencyGroupInPyProjectToml","addDependenciesToPyProjectToml","addWorkspaceDependencyToPyProject","sharedConstructsGenerator","BASE_IMAGES","withVersions","PY_AGENT_GENERATOR_INFO","filename","pyAgentGenerator","tree","options","project","pyProjectPath","root","Error","sourceRoot","sourceParts","split","moduleName","length","name","pop","agentTargetPrefix","agentNameSnakeCase","agentNameClassName","targetSourceDir","infra","protocol","framework","auth","console","warn","agentConnectionModuleName","templateContext","dirname","overwriteStrategy","KeepExisting","protocolLower","toLowerCase","protocolTemplateDir","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","iac","infraProtocol","agentNameKebabCase","projectName","serverProtocol","localDevPortStart","localDevPort","component","info","serveCommand","openApiTargetName","clientGenTargetName","scriptsDir","patterns","language","chatUrl","chatCommand","httpOnlyTargets","outputs","inputs","dependentTasksOutputFiles","agentTargets","continuous","cwd","env","PORT","LOCAL_DEV","URL","port","rc","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/agent/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config';\nimport { AG_UI_LANGGRAPH_EXCEPTIONS } from '../../license/known-exceptions';\nimport { addAgentChatScripts } from '../../utils/agent-chat/agent-chat';\nimport {\n addPythonFrameworkBase,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n} from '../../utils/agent-connection/agent-connection';\nimport { addAgentInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { updateGitIgnore } from '../../utils/git';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { sortObjectKeys } from '../../utils/object';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { assignPort } from '../../utils/port';\nimport {\n addDependenciesToDependencyGroupInPyProjectToml,\n addDependenciesToPyProjectToml,\n addWorkspaceDependencyToPyProject,\n} from '../../utils/py';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport { BASE_IMAGES, withVersions } from '../../utils/versions';\nimport type { PyAgentGeneratorSchema } from './schema';\n\nexport const PY_AGENT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyAgentGenerator = async (\n tree: Tree,\n options: PyAgentGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-agent`,\n );\n const agentTargetPrefix = options.name ? name : 'agent';\n\n const agentNameSnakeCase = toSnakeCase(options.name || 'agent');\n const agentNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n agentNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n const protocol = options.protocol ?? 'http';\n const framework = options.framework ?? 'strands';\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Ensure the shared agent-connection project exists so the server entry\n // point can import `session_id_context` and propagate the AgentCore\n // session ID to any downstream MCP / A2A clients a later connection\n // generator wires into this agent.\n await ensurePythonAgentConnectionProject(tree);\n // The agent server imports the framework base helpers (session cache + model\n // error logging) regardless of whether a connection client is wired in. The\n // langchain framework has no base layer (its AG-UI foundation reuses only the\n // framework-agnostic session context), so this is a no-op for langchain.\n await addPythonFrameworkBase(tree, framework);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n addWorkspaceDependencyToPyProject(\n tree,\n project,\n getPythonAgentConnectionProject(tree),\n );\n\n const templateContext = {\n name,\n agentNameSnakeCase,\n agentNameClassName,\n moduleName,\n agentConnectionModuleName,\n framework,\n };\n\n // Generate common files shared by both protocols. The agent module (agent.py)\n // is framework-specific (Strands yields a contextmanaged Agent; LangChain\n // returns a compiled create_agent graph), so it comes from a per-framework\n // dir. The package __init__.py is framework-agnostic (it stays in `common`).\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n framework === 'langchain' ? 'common-langchain' : 'common',\n ),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n if (framework === 'langchain') {\n // common-langchain only carries agent.py; the empty package __init__.py is\n // framework-agnostic, so emit it from the shared `common` dir.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'common'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\n\n // Generate protocol-specific files. Each protocol's server entry point is\n // framework-specific (Strands yields a contextmanaged Agent; LangChain drives\n // a compiled create_agent graph), so it comes from a per-framework dir\n // `<protocol>-langchain` for LangChain, or `<protocol>` for Strands.\n const protocolLower = protocol.toLowerCase();\n const protocolTemplateDir =\n framework === 'langchain' ? `${protocolLower}-langchain` : protocolLower;\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', protocolTemplateDir),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n // The HTTP server's init.py (the FastAPI app + JsonStreamingResponse) is\n // framework-agnostic and the LangChain http main.py reuses it, so emit it\n // from the shared `http` dir. Emitted after the langchain main.py above so\n // KeepExisting preserves that main.py and only adds init.py (the shared dir's\n // own Strands main.py is skipped).\n if (protocolLower === 'http' && framework === 'langchain') {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'http'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\n\n addDependenciesToPyProjectToml(tree, project.root, [\n 'aws-lambda-powertools',\n 'aws-opentelemetry-distro',\n 'bedrock-agentcore',\n 'boto3',\n 'fastapi',\n 'mcp',\n ...(framework === 'langchain'\n ? // langchain pulls no Strands dependencies — the langchain model binding\n // (langchain, langchain-aws, langgraph) plus the per-protocol server\n // adapter: ag-ui-langgraph for AG-UI, a2a-sdk for A2A, nothing extra for\n // HTTP (FastAPI is added above for every agent).\n ([\n 'langchain',\n 'langchain-aws',\n 'langgraph',\n ...(protocol === 'ag-ui'\n ? (['ag-ui-protocol', 'ag-ui-langgraph'] as const)\n : protocol === 'a2a'\n ? (['a2a-sdk'] as const)\n : ([] as const)),\n ] as const)\n : protocol === 'a2a'\n ? (['strands-agents[a2a]', 'strands-agents-tools'] as const)\n : protocol === 'ag-ui'\n ? ([\n 'strands-agents',\n 'strands-agents-tools',\n 'ag-ui-protocol',\n 'ag-ui-strands',\n ] as const)\n : (['strands-agents', 'strands-agents-tools'] as const)),\n 'uvicorn',\n ]);\n addDependenciesToDependencyGroupInPyProjectToml(tree, project.root, 'dev', [\n 'fastapi[standard]',\n ]);\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n // Add the Dockerfile\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n agentNameSnakeCase,\n moduleName,\n bundleOutputDir,\n protocol,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${agentTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project,\n containerEngine: containers,\n trivyTargetName: `${agentTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n });\n\n // Add shared constructs\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n\n // Add the construct to deploy the agent.\n // AG-UI uses HTTP as the AgentCore protocol type (AG-UI is HTTP-based with SSE over POST).\n const infraProtocol =\n protocol === 'ag-ui' ? ('http' as const) : (protocol as 'http' | 'a2a');\n await addAgentInfra(tree, {\n agentNameKebabCase: name,\n agentNameClassName,\n dockerImageTag,\n dockerOutputDir,\n iac,\n projectName: project.name,\n auth,\n serverProtocol: infraProtocol,\n containers,\n });\n }\n\n // A2A servers use port 9000 as per the Strands A2A SDK default and AgentCore A2A contract.\n // HTTP and AG-UI agents use port 8081+ to avoid conflict with VS Code server on 8080.\n const localDevPortStart = protocol === 'a2a' ? 9000 : 8081;\n const localDevPort = assignPort(tree, project, localDevPortStart, {\n component: { info: PY_AGENT_GENERATOR_INFO, name: agentTargetPrefix },\n });\n\n // All protocols use fastapi dev for hot reload:\n // - HTTP: FastAPI app directly defined in init.py\n // - A2A: A2AServer.to_fastapi_app() creates a FastAPI app in main.py\n // - AG-UI: create_strands_app() creates a FastAPI app in main.py\n const serveCommand = `uv run fastapi dev ${moduleName}/${agentNameSnakeCase}/main.py --port ${localDevPort}`;\n\n // HTTP chat uses the type-safe TypeScript client generated from the\n // agent's OpenAPI spec (same generated client the react-connection\n // generator produces). A2A and AG-UI speak standard protocols, so\n // we can run `agent-chat-cli` directly as a binary.\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const clientGenTargetName = `${agentTargetPrefix}-generate-client`;\n\n const scriptsDir = joinPathFragments(\n project.root,\n 'scripts',\n agentTargetPrefix,\n );\n\n if (protocol === 'http') {\n // Emit the OpenAPI spec generator script (shared with react-connection)\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'react-connection',\n 'files',\n 'agent',\n ),\n project.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ignore the generated client directory\n updateGitIgnore(tree, project.root, (patterns) => [\n ...patterns,\n `scripts/${agentTargetPrefix}/generated/`,\n ]);\n }\n\n // Every protocol gets a standalone `chat.ts`. It connects to the local\n // `dev` server by default, or to the deployed agent (with the\n // appropriate auth) when `RUNTIME_CONFIG_APP_ID` is set.\n addAgentChatScripts(tree, {\n scriptsDir,\n protocol,\n language: 'py',\n agentNameClassName,\n auth,\n });\n\n // TypeScript deps for the chat CLI, which runs standalone via tsx for every\n // protocol and resolves the deployed agent from AppConfig. `agent-chat-cli`\n // transitively bundles the protocol clients (@a2a-js/sdk, @ag-ui/client).\n addDependenciesToPackageJson(\n tree,\n {},\n withVersions([\n 'agent-chat-cli',\n 'tsx',\n '@types/node',\n '@aws-lambda-powertools/parameters',\n '@aws-sdk/client-appconfigdata',\n ...(auth === 'iam'\n ? (['aws4fetch', '@aws-sdk/credential-providers'] as const)\n : ([] as const)),\n ...(protocol === 'a2a' ? (['@a2a-js/sdk'] as const) : ([] as const)),\n ]),\n );\n\n const chatUrl =\n protocol === 'ag-ui'\n ? `http://localhost:${localDevPort}/invocations`\n : `http://localhost:${localDevPort}`;\n const chatCommand = `tsx ./scripts/${agentTargetPrefix}/chat.ts`;\n\n const httpOnlyTargets =\n protocol === 'http'\n ? {\n [openApiTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n [clientGenTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n dependsOn: [openApiTargetName],\n inputs: [\n {\n dependentTasksOutputFiles: '**/*.json',\n },\n ],\n outputs: [`{projectRoot}/scripts/${agentTargetPrefix}/generated`],\n options: {\n commands: [\n `nx g @aws/nx-plugin:open-api#ts-client --openApiSpecPath=\"dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json\" --outputPath=\"${project.root}/scripts/${agentTargetPrefix}/generated\" --no-interactive`,\n ],\n },\n },\n }\n : {};\n\n const agentTargets = {\n ...project.targets,\n ...httpOnlyTargets,\n [`${agentTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${agentTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n // HTTP chat imports the generated client, so ensure it's built first.\n // No dev dependency — chat runs standalone against a local or\n // deployed agent. normalizeTargetKeyOrder keeps the conditional dependsOn\n // in Nx 23's serialization order so re-runs stay byte-identical.\n [`${agentTargetPrefix}-chat`]: normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n options: {\n commands: [chatCommand],\n cwd: '{projectRoot}',\n env: {\n URL: chatUrl,\n },\n },\n ...(protocol === 'http' ? { dependsOn: [clientGenTargetName] } : {}),\n }),\n };\n\n // Aggregate `<agent>-dev` under the project-level `dev` target.\n addComponentDevTarget(agentTargets, `${agentTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: sortObjectKeys(agentTargets),\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_AGENT_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n agentTargetPrefix,\n {\n port: localDevPort,\n rc: agentNameClassName,\n auth,\n protocol,\n // The mcp / gateway connection generators dispatch on this field to pick\n // the Strands vs LangChain Layer-2 client + agent.py transform.\n framework,\n },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_AGENT_GENERATOR_INFO]);\n\n // langchain-core (pulled by every langchain agent regardless of protocol)\n // brings jsonpatch/jsonpointer, whose wheels ship without resolvable SPDX\n // license metadata, so register those exceptions so the workspace license\n // check still passes.\n if (framework === 'langchain') {\n await ensureLicenseExceptions(tree, AG_UI_LANGGRAPH_EXCEPTIONS);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyAgentGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","AG_UI_LANGGRAPH_EXCEPTIONS","addAgentChatScripts","addPythonFrameworkBase","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","addAgentInfra","addPythonBundleTarget","resolveContainers","addDependenciesToPackageJson","addDockerScanTarget","formatFilesInSubtree","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","sortObjectKeys","toProjectRelativePath","assignPort","addDependenciesToDependencyGroupInPyProjectToml","addDependenciesToPyProjectToml","addWorkspaceDependencyToPyProject","sharedConstructsGenerator","BASE_IMAGES","withVersions","PY_AGENT_GENERATOR_INFO","filename","pyAgentGenerator","tree","options","project","pyProjectPath","root","Error","sourceRoot","sourceParts","split","moduleName","length","name","pop","agentTargetPrefix","agentNameSnakeCase","agentNameClassName","targetSourceDir","infra","protocol","framework","auth","console","warn","agentConnectionModuleName","templateContext","dirname","overwriteStrategy","KeepExisting","protocolLower","toLowerCase","protocolTemplateDir","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","iac","infraProtocol","agentNameKebabCase","projectName","serverProtocol","localDevPortStart","localDevPort","component","info","serveCommand","openApiTargetName","clientGenTargetName","scriptsDir","patterns","language","chatUrl","chatCommand","httpOnlyTargets","outputs","inputs","dependentTasksOutputFiles","agentTargets","continuous","cwd","env","PORT","LOCAL_DEV","URL","port","rc","preferInstallDependencies","languages"],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/ import {
|
|
4
|
+
*/ import { generateFiles, joinPathFragments, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
|
|
5
5
|
import { ensureLicenseExceptions } from "../../license/config.js";
|
|
6
6
|
import { MCP_INSPECTOR_EXCEPTIONS } from "../../license/known-exceptions.js";
|
|
7
7
|
import { addMcpServerInfra } from "../../utils/agent-core-constructs/agent-core-constructs.js";
|
|
8
8
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
9
9
|
import { resolveContainers } from "../../utils/containers.js";
|
|
10
|
+
import { addDependenciesToPackageJson } from "../../utils/dependencies.js";
|
|
10
11
|
import { addDockerScanTarget } from "../../utils/docker.js";
|
|
11
12
|
import { formatFilesInSubtree } from "../../utils/format.js";
|
|
12
13
|
import { FsCommands } from "../../utils/fs.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config';\nimport { MCP_INSPECTOR_EXCEPTIONS } from '../../license/known-exceptions';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { assignPort } from '../../utils/port';\nimport { addDependenciesToPyProjectToml } from '../../utils/py';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport { BASE_IMAGES, withVersions } from '../../utils/versions';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n addDependenciesToPyProjectToml(tree, project.root, [\n 'aws-lambda-powertools',\n 'mcp',\n 'uvicorn',\n 'boto3',\n 'aws-opentelemetry-distro',\n ]);\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n });\n\n // Add shared constructs\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addDependenciesToPackageJson(\n tree,\n {},\n withVersions(['@modelcontextprotocol/inspector']),\n );\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await ensureLicenseExceptions(tree, MCP_INSPECTOR_EXCEPTIONS);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["addDependenciesToPackageJson","generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","MCP_INSPECTOR_EXCEPTIONS","addMcpServerInfra","addPythonBundleTarget","resolveContainers","addDockerScanTarget","formatFilesInSubtree","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","assignPort","addDependenciesToPyProjectToml","sharedConstructsGenerator","BASE_IMAGES","withVersions","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","root","Error","sourceRoot","sourceParts","split","moduleName","length","name","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","iac","mcpServerNameKebabCase","projectName","localDevPort","component","info","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","port","rc","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config';\nimport { MCP_INSPECTOR_EXCEPTIONS } from '../../license/known-exceptions';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { assignPort } from '../../utils/port';\nimport { addDependenciesToPyProjectToml } from '../../utils/py';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport { BASE_IMAGES, withVersions } from '../../utils/versions';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n addDependenciesToPyProjectToml(tree, project.root, [\n 'aws-lambda-powertools',\n 'mcp',\n 'uvicorn',\n 'boto3',\n 'aws-opentelemetry-distro',\n ]);\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n });\n\n // Add shared constructs\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addDependenciesToPackageJson(\n tree,\n {},\n withVersions(['@modelcontextprotocol/inspector']),\n );\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await ensureLicenseExceptions(tree, MCP_INSPECTOR_EXCEPTIONS);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","MCP_INSPECTOR_EXCEPTIONS","addMcpServerInfra","addPythonBundleTarget","resolveContainers","addDependenciesToPackageJson","addDockerScanTarget","formatFilesInSubtree","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","assignPort","addDependenciesToPyProjectToml","sharedConstructsGenerator","BASE_IMAGES","withVersions","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","root","Error","sourceRoot","sourceParts","split","moduleName","length","name","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","iac","mcpServerNameKebabCase","projectName","localDevPort","component","info","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","port","rc","preferInstallDependencies","languages"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/ import {
|
|
4
|
+
*/ import { ensurePackage, joinPathFragments, readNxJson, readProjectConfiguration, updateNxJson, updateProjectConfiguration } from "@nx/devkit";
|
|
5
5
|
import { addLicenseCheckToLintTarget, ensurePythonLicenseCollector } from "../../license/config.js";
|
|
6
|
+
import { addDependenciesToPackageJson } from "../../utils/dependencies.js";
|
|
6
7
|
import { updateGitIgnore } from "../../utils/git.js";
|
|
7
8
|
import { installDependencies } from "../../utils/install.js";
|
|
8
9
|
import { addGeneratorMetricsIfApplicable } from "../../utils/metrics.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config';\nimport { updateGitIgnore } from '../../utils/git';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python';\nimport { sortObjectKeys } from '../../utils/object';\nimport { addDependenciesToDependencyGroupInPyProjectToml } from '../../utils/py';\nimport { updateToml } from '../../utils/toml';\nimport { withVersions } from '../../utils/versions';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n const pythonPlugin = withVersions(['@nxlv/python']);\n addDependenciesToPackageJson(tree, {}, pythonPlugin);\n\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n inputs: ['default', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n // Pin ruff to the version generation-time formatting uses (PY_VERSIONS), so\n // generated files stay `ruff format --check`-clean across ruff releases.\n addDependenciesToDependencyGroupInPyProjectToml(tree, '.', 'dev', [\n 'ruff',\n 'ty',\n ]);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["addDependenciesToPackageJson","ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","addDependenciesToDependencyGroupInPyProjectToml","updateToml","withVersions","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","getPyProjectDetails","tree","schema","scope","normalizedName","name","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","nxJson","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","pyenvPythonVersion","pyprojectPythonDependency","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","filter","preferInstallDependencies","languages"],"mappings":"AAAA;;;CAGC,GACD,SACEA,4BAA4B,EAC5BC,aAAa,EAEbC,iBAAiB,EACjBC,UAAU,EACVC,wBAAwB,EAExBC,YAAY,EACZC,0BAA0B,QACrB,aAAa;AACpB,SACEC,2BAA2B,EAC3BC,4BAA4B,QACvB,0BAAuB;AAC9B,SAASC,eAAe,QAAQ,qBAAkB;AAClD,SAASC,mBAAmB,QAAQ,yBAAsB;AAC1D,SAASC,+BAA+B,QAAQ,yBAAsB;AACtE,SAASC,yBAAyB,EAAEC,WAAW,QAAQ,uBAAoB;AAC3E,SAASC,WAAW,QAAQ,2BAAwB;AACpD,SACEC,iCAAiC,EACjCC,oBAAoB,EACpBC,gBAAgB,EAEhBC,aAAa,QACR,oBAAiB;AAExB,SACEC,4BAA4B,EAC5BC,kBAAkB,QACb,6BAA0B;AACjC,SAASC,cAAc,QAAQ,wBAAqB;AACpD,SAASC,+CAA+C,QAAQ,oBAAiB;AACjF,SAASC,UAAU,QAAQ,sBAAmB;AAC9C,SAASC,YAAY,QAAQ,0BAAuB;AAGpD,OAAO,MAAMC,4BAA6CR,iBACxD,YAAYS,QAAQ,EACpB;AAEF,6EAA6E;AAC7E,8EAA8E;AAC9E,iFAAiF;AACjF,uEAAuE;AACvE,gFAAgF;AAChF,4CAA4C;AAC5C,MAAMC,6BAA6B;IACjC;IACA;IACA;IACA;IACA;IACA;CACD;AA8BD;;CAEC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC;IAOA,MAAMC,QAAQlB,YAAYC,YAAYe;IACtC,MAAMG,iBAAiBnB,YAAYiB,OAAOG,IAAI;IAC9C,MAAMC,uBAAuBrB,YAC3BiB,OAAOK,UAAU,IAAI,GAAGJ,MAAM,CAAC,EAAEC,gBAAgB;IAEnD,MAAMI,qBAAqB,GAAGL,MAAM,CAAC,EAAEC,gBAAgB;IACvD,qEAAqE;IACrE,wEAAwE;IACxE,MAAMK,mBAAmBzB,0BAA0BwB;IACnD,yDAAyD;IACzD,MAAME,MAAMpC,kBACV4B,OAAOS,SAAS,IAAI,KACpBT,OAAOU,YAAY,IAAIR;IAEzB,OAAO;QAAEM;QAAKF;QAAoBC;QAAkBH;IAAqB;AAC3E,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMO,qBAAqB,OAChCZ,MACAC;IAEA,MAAM,EAAEQ,GAAG,EAAEJ,oBAAoB,EAAEE,kBAAkB,EAAEC,gBAAgB,EAAE,GACvET,oBAAoBC,MAAMC;IAE5B,MAAMY,eAAelB,aAAa;QAAC;KAAe;IAClDxB,6BAA6B6B,MAAM,CAAC,GAAGa;IAEvCC,OAAOC,OAAO,CAACF,cAAcG,OAAO,CAAC,CAAC,CAACZ,MAAMa,QAAQ,GACnD7C,cAAcgC,MAAMa;IAGtB,MAAMC,SAAS5C,WAAW0B;IAE1B,4EAA4E;IAC5E,gEAAgE;IAChE,IACE,CAACkB,OAAOC,OAAO,EAAEC,KAAK,CAACC,IACrB,OAAOA,MAAM,WACTA,MAAM,iBACNA,EAAEC,MAAM,KAAK,iBAEnB;QACAJ,OAAOC,OAAO,GAAG;eACXD,OAAOC,OAAO,IAAI,EAAE;YACxB;gBACEG,QAAQ;gBACRC,SAAS;oBACPC,gBAAgB;gBAClB;YACF;SACD;QACDhD,aAAawB,MAAMkB;IACrB;IAEA,8EAA8E;IAC9E,8EAA8E;IAC9E,+CAA+C;IAC/C,IAAI,CAAC7B,cAAcW,MAAMO,qBAAqB;QAC5C,IAAI,CAACP,KAAKyB,MAAM,CAAC,YAAY;YAC3B,MAAMnC,6BAA6BU,MAAM;gBACvC0B,cAAc;gBACdF,gBAAgB;gBAChBG,qBAAqB;gBACrBC,oBAAoB;gBACpBC,2BAA2B;YAC7B;QACF;QAEA,MAAMtC,mBAAmBS,MAAM;YAC7B,0EAA0E;YAC1E,0EAA0E;YAC1E,0EAA0E;YAC1E,wEAAwE;YACxE,0EAA0E;YAC1E,yDAAyD;YACzDI,MAAMG;YACNuB,aAAatB;YACbuB,aAAa;YACbC,qBAAqB;YACrBC,8BAA8B;YAC9BC,QAAQ;YACRC,8BAA8B;YAC9BP,oBAAoB;YACpBC,2BAA2B;YAC3BO,aAAanC,OAAOoC,IAAI;YACxBC,0BAA0B;YAC1BhC,YAAYD;YACZK,WAAWD;YACX8B,gBAAgB;YAChBC,cAAc;YACdC,wBAAwB;YACxBC,uBAAuB;YACvBC,oBAAoB;YACpBC,qBAAqB;YACrBC,aAAa;YACbC,QAAQ;QACV;QAEA,qEAAqE;QACrE;YACEzE,kBAAkBoC,KAAKJ,sBAAsB;YAC7ChC,kBAAkBoC,KAAK,SAAS;SACjC,CAACO,OAAO,CAAC,CAAC+B,IAAM/C,KAAKgD,MAAM,CAACD;QAE7B,0EAA0E;QAC1E/C,KAAKiD,KAAK,CACR5E,kBAAkBoC,KAAK,SAAS,iBAChC;IAEJ;IAEA,MAAMyC,aAAa;IACnB,MAAMC,kBAAkB9E,kBAAkB6E,YAAY;IACtD,MAAME,uBAAuB7E,yBAC3ByB,MACAO;IAEF6C,qBAAqBhD,IAAI,GAAGG;IAC5B,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,wCAAwC;IACxC,IAAI,CAAC6C,qBAAqBC,OAAO,CAACC,OAAO,EAAE;QACzC,MAAMC,cAAcH,qBAAqBC,OAAO,CAACG,KAAK;QACtDJ,qBAAqBC,OAAO,CAACC,OAAO,GAAG;YACrC,GAAGC,WAAW;YACdE,QAAQ;gBAAC;gBAAW;aAAc;YAClCC,SAAS;gBAACP;aAAgB;YAC1B5B,SAAS;gBACP,GAAGgC,YAAYhC,OAAO;gBACtB2B,YAAYC;gBACZ,sEAAsE;gBACtE,uEAAuE;gBACvE,+DAA+D;gBAC/DQ,aAAa;oBAAC;oBAAS;oBAAQ;uBAAY7D;iBAA2B;YACxE;QACF;QACAsD,qBAAqBC,OAAO,CAACG,KAAK,GAAG;YACnCC,QAAQ;gBAAC;gBAAW;aAAc;YAClCG,WAAW;gBACT;gBACA;gBACA;gBACA;mBACIL,YAAYK,SAAS,IAAI,EAAE;aAChC;YACDrC,SAAS;gBACP2B;YACF;QACF;IACF;IACAE,qBAAqBC,OAAO,CAACQ,SAAS,GAAG;QACvCC,OAAO;QACPL,QAAQ;YAAC;YAAW;SAAc;QAClCM,UAAU;QACVxC,SAAS;YACPyC,SAAS;YACTC,KAAK;QACP;IACF;IAEA,mEAAmE;IACnEvE,WACEM,MACA3B,kBAAkBoC,KAAK,mBACvB,CAACyD;QACC,IAAKA,cAAcC,IAAI,EAAUC,MAAM;YACpCF,cAAcC,IAAI,CAASC,IAAI,CAAC,cAAc,GAAG;QACpD;QACA,OAAOF;IACT;IAGF,4EAA4E;IAC5E,yEAAyE;IACzEzE,gDAAgDO,MAAM,KAAK,OAAO;QAChE;QACA;KACD;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,iEAAiE;IACjEoD,qBAAqBC,OAAO,CAACgB,MAAM,GAAG;QACpC,GAAGjB,qBAAqBC,OAAO,CAACgB,MAAM;QACtCP,OAAO;QACPL,QAAQ;YAAC;YAAW;SAAc;QAClClC,SAAS;YACP,GAAG6B,qBAAqBC,OAAO,CAACgB,MAAM,EAAE9C,OAAO;YAC/C+C,OAAO;QACT;QACAC,gBAAgB;YACd,GAAGnB,qBAAqBC,OAAO,CAACgB,MAAM,EAAEE,cAAc;YACtDC,KAAK;gBACHF,OAAO;YACT;YACA,aAAa;gBACXA,OAAO;YACT;QACF;IACF;IAEA,kFAAkF;IAClF,yCAAyC;IACzClB,qBAAqBC,OAAO,CAACoB,IAAI,GAAG;QAClC,GAAGrB,qBAAqBC,OAAO,CAACoB,IAAI;QACpCX,OAAO;QACPL,QAAQ;YAAC;YAAW;SAAc;QAClCc,gBAAgB;YACd,GAAGnB,qBAAqBC,OAAO,CAACoB,IAAI,EAAEF,cAAc;YACpDC,KAAK;gBACHA,KAAK;YACP;YACA,aAAa;gBACXE,UAAU;YACZ;QACF;IACF;IACA,2EAA2E;IAC3E,4EAA4E;IAC5ExF,kCAAkCkE,sBAAsB,QAAQ;IAEhEA,qBAAqBC,OAAO,GAAG7D,eAAe4D,qBAAqBC,OAAO;IAC1E5E,2BAA2BuB,MAAMO,oBAAoB6C;IAErDjE,qBAAqBa,MAAMO,oBAAoBX;IAE/C,yBAAyB;IACzBhB,gBAAgBoB,MAAM,KAAK,CAAC2E,WAAa;eAAIA;YAAU;SAAW;IAElE,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,wCAAwC;IACxC/F,gBAAgBoB,MAAMS,KAAK,CAACkE,WAAa;eACpCA;YACH;eACG7E,2BAA2B8E,MAAM,CAAC,CAACvD,IAAMA,MAAM;SACnD;IAED,MAAMvC,gCAAgCkB,MAAM;QAACJ;KAA0B;IAEvE,MAAMjB,6BAA6BqB;IAEnC,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,qDAAqD;IACrDtB,4BAA4BsB,MAAMO;IAElC,OAAO,IACL1B,oBAAoBmB,MAAMC,OAAO4E,yBAAyB,EAAE;YAC1DC,WAAW;gBAAC;gBAAc;aAAS;QACrC;AACJ,EAAE;AACF,eAAelE,mBAAmB"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies';\nimport { updateGitIgnore } from '../../utils/git';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python';\nimport { sortObjectKeys } from '../../utils/object';\nimport { addDependenciesToDependencyGroupInPyProjectToml } from '../../utils/py';\nimport { updateToml } from '../../utils/toml';\nimport { withVersions } from '../../utils/versions';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n const pythonPlugin = withVersions(['@nxlv/python']);\n addDependenciesToPackageJson(tree, {}, pythonPlugin);\n\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n inputs: ['default', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n // Pin ruff to the version generation-time formatting uses (PY_VERSIONS), so\n // generated files stay `ruff format --check`-clean across ruff releases.\n addDependenciesToDependencyGroupInPyProjectToml(tree, '.', 'dev', [\n 'ruff',\n 'ty',\n ]);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","addDependenciesToPackageJson","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","addDependenciesToDependencyGroupInPyProjectToml","updateToml","withVersions","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","getPyProjectDetails","tree","schema","scope","normalizedName","name","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","nxJson","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","pyenvPythonVersion","pyprojectPythonDependency","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","filter","preferInstallDependencies","languages"],"mappings":"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"}
|
package/src/py/rdb/generator.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/ import { relative } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { generateFiles, joinPathFragments, readProjectConfiguration, updateProjectConfiguration } from "@nx/devkit";
|
|
6
6
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
7
7
|
import { resolveContainers } from "../../utils/containers.js";
|
|
8
|
+
import { addDependenciesToPackageJson } from "../../utils/dependencies.js";
|
|
8
9
|
import { addDockerScanTarget } from "../../utils/docker.js";
|
|
9
10
|
import { formatFilesInSubtree } from "../../utils/format.js";
|
|
10
11
|
import { FsCommands } from "../../utils/fs.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n addDependenciesToPackageJson,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport { assignPort } from '../../utils/port';\nimport { addDependenciesToPyProjectToml } from '../../utils/py';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport {\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport { sharedRdbScriptsGenerator } from '../../utils/shared-rdb-scripts';\nimport { PY_VERSIONS, withVersions } from '../../utils/versions';\nimport pyProjectGenerator, { getPyProjectDetails } from '../project/generator';\nimport type { PyRdbGeneratorSchema } from './schema';\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n );\n\n await sharedRdbScriptsGenerator(tree, engine);\n // Used by local dev script wait-for-*-db.ts\n addDependenciesToPackageJson(\n tree,\n withVersions([engine === 'mysql' ? 'mariadb' : 'pg']),\n engine === 'mysql' ? {} : withVersions(['@types/pg']),\n );\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n });\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(tree, fullyQualifiedName, PY_RDB_GENERATOR_INFO, {\n engine,\n });\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addDependenciesToPyProjectToml(tree, dir, [\n 'sqlmodel',\n 'alembic',\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n 'greenlet',\n ...(engine === 'mysql'\n ? (['aiomysql', 'boto3', 'aws-lambda-powertools'] as const)\n : (['asyncpg', 'boto3', 'aws-lambda-powertools'] as const)),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","addDependenciesToPackageJson","generateFiles","joinPathFragments","readProjectConfiguration","updateProjectConfiguration","addPythonBundleTarget","resolveContainers","addDockerScanTarget","formatFilesInSubtree","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addDependenciesToPyProjectToml","addRdbInfra","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","sharedRdbScriptsGenerator","PY_VERSIONS","withVersions","pyProjectGenerator","getPyProjectDetails","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","name","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","engine","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","scriptsDir","fs","migrationBundleDir","root","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","infra","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","iac","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"AAAA;;;CAGC,GACD,SAASA,QAAQ,QAAQ,YAAY;AACrC,SACEC,4BAA4B,EAE5BC,aAAa,EACbC,iBAAiB,EACjBC,wBAAwB,EAExBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,qBAAqB,QAAQ,+BAA4B;AAClE,SAASC,iBAAiB,QAAQ,4BAAyB;AAC3D,SAASC,mBAAmB,QAAQ,wBAAqB;AACzD,SAASC,oBAAoB,QAAQ,wBAAqB;AAC1D,SAASC,UAAU,QAAQ,oBAAiB;AAC5C,SAASC,UAAU,QAAQ,qBAAkB;AAC7C,SAASC,mBAAmB,QAAQ,yBAAsB;AAC1D,SAASC,+BAA+B,QAAQ,yBAAsB;AACtE,SAASC,SAAS,EAAEC,SAAS,EAAEC,WAAW,QAAQ,uBAAoB;AACtE,SAASC,WAAW,QAAQ,2BAAwB;AACpD,SACEC,iCAAiC,EACjCC,oBAAoB,EACpBC,gBAAgB,EAEhBC,aAAa,QACR,oBAAiB;AACxB,SAASC,UAAU,QAAQ,sBAAmB;AAC9C,SAASC,8BAA8B,QAAQ,oBAAiB;AAChE,SAASC,WAAW,QAAQ,+CAA4C;AACxE,SAASC,yBAAyB,QAAQ,mCAAgC;AAC1E,SACEC,YAAY,EACZC,kBAAkB,QACb,6CAA0C;AACjD,SAASC,yBAAyB,QAAQ,oCAAiC;AAC3E,SAASC,WAAW,EAAEC,YAAY,QAAQ,0BAAuB;AACjE,OAAOC,sBAAsBC,mBAAmB,QAAQ,0BAAuB;AAG/E,OAAO,MAAMC,wBAAyCb,iBACpD,YAAYc,QAAQ,EACpB;AAEF,OAAO,MAAMC,iBAAiB,OAC5BC,MACAC;IAEA,MAAMC,gBAAgBtB,YAAYqB,QAAQE,IAAI;IAC9C,MAAMC,eAAeH,QAAQG,YAAY,IAAI;IAC7C,MAAMC,eAAe1B,UAAUsB,QAAQI,YAAY,IAAIJ,QAAQE,IAAI;IACnE,MAAMG,kBAAkB,MAAMnC,kBAAkB6B,MAAM;IAEtD,MAAM,EAAEO,kBAAkB,EAAEC,GAAG,EAAEC,oBAAoB,EAAE,GAAGb,oBACxDI,MACA;QACEG,MAAMF,QAAQE,IAAI;QAClBO,WAAWT,QAAQS,SAAS;QAC5BC,cAAcV,QAAQU,YAAY;IACpC;IAGF,IAAI,CAAC1B,cAAce,MAAMO,qBAAqB;QAC5C,MAAMZ,mBAAmBK,MAAM;YAC7BG,MAAMF,QAAQE,IAAI;YAClBO,WAAWT,QAAQS,SAAS;YAC5BC,cAAcV,QAAQU,YAAY;YAClCC,MAAM;QACR;IACF;IAEA,MAAMC,gBAAgB7C,yBAAyBgC,MAAMO;IAErD,MAAM,EAAEO,MAAM,EAAE,GAAGb;IACnB,MAAMc,cAAc7B,WAClBc,MACAa,eACAC,WAAW,UAAU,OAAO;IAE9B,MAAME,cAAc;IACpB,MAAMC,cAAcH,WAAW,UAAU,SAAS;IAClD,MAAMI,kBAAkB;IACxB,MAAMC,gBAAgB,GAAGtC,YAAYmB,MAAM,CAAC,EAAEK,cAAc;IAC5D,MAAMe,cACJN,WAAW,UACP,+CACA;IAEN,MAAMO,kBAAkB;QACtBlB,MAAMM;QACNa,kBAAkBpB;QAClBY;QACAC;QACAC;QACAO,aAAalB;QACbY;QACAC;QACAZ;QACAa;QACAC;QACAI,iBAAiB/B,YAAYgC,QAAQ;QACrCC,gBAAgBjC,YAAYkC,OAAO;QACnCC,iBAAiBnC,YAAYoC,QAAQ;QACrCC,gBAAgBrC,YAAYsC,OAAO;QACnCC,cAAcvC,YAAYwC,KAAK;QAC/BC,4BAA4BzC,WAAW,CAAC,wBAAwB;IAClE;IAEA3B,cACEkC,MACAjC,kBAAkB,YAAYoE,OAAO,EAAE,UACvC3B,KACAa;IAGF,MAAM7B,0BAA0BQ,MAAMc;IACtC,4CAA4C;IAC5CjD,6BACEmC,MACAN,aAAa;QAACoB,WAAW,UAAU,YAAY;KAAK,GACpDA,WAAW,UAAU,CAAC,IAAIpB,aAAa;QAAC;KAAY;IAEtD,MAAM0C,aAAaxE,SACjB4C,KACAzC,kBAAkBuB,cAAcC,oBAAoB,OAAO;IAE7D,MAAM8C,KAAK,IAAI/D,WAAW0B;IAE1B,MAAMsC,qBAAqBvE,kBACzB,QACA8C,cAAc0B,IAAI,EAClB,UACA;IAEF,MAAMC,wBAAwBzE,kBAC5B,QACA8C,cAAc0B,IAAI,EAClB,UACA;IAEF,MAAME,0BAA0B,GAAG5D,YAAYmB,MAAM,CAAC,EAAEtB,UAAUuB,QAAQE,IAAI,EAAE,iBAAiB,CAAC;IAClG,MAAMuC,6BAA6B,GAAG7D,YAAYmB,MAAM,CAAC,EAAEtB,UACzDuB,QAAQE,IAAI,EACZ,sBAAsB,CAAC;IAEzB,IAAIF,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAM,EAAEC,gBAAgB,EAAEC,eAAe,EAAE,GAAG3E,sBAC5C2C,eACA;YAAEiC,gBAAgB;QAAyB;QAG7CjC,cAAckC,OAAO,CAAC,mBAAmB,GAAG;YAC1CC,OAAO;YACPC,SAAS;gBAAC;aAAsD;YAChEC,UAAU;YACVjD,SAAS;gBACPkD,UAAU;oBACRd,GAAGe,EAAE,CAACd;oBACND,GAAGgB,KAAK,CAACf;oBACTD,GAAGiB,EAAE,CAACT,iBAAiBP;oBACvBD,GAAGiB,EAAE,CACHvF,kBAAkByC,KAAK,eACvBzC,kBAAkBuE,oBAAoB;oBAExCD,GAAGiB,EAAE,CACHvF,kBAAkByC,KAAK,gBACvBzC,kBAAkBuE,oBAAoB;oBAExCD,GAAGiB,EAAE,CACHvF,kBAAkByC,KAAK,yBACvBzC,kBAAkBuE,oBAAoB;iBAEzC;gBACDiB,UAAU;YACZ;YACAC,WAAW;gBAACZ;aAAiB;QAC/B;QACA/B,cAAckC,OAAO,CAAC,wBAAwB,GAAG;YAC/CC,OAAO;YACPC,SAAS;gBAAC;aAA2D;YACrEC,UAAU;YACVjD,SAAS;gBACPkD,UAAU;oBACRd,GAAGe,EAAE,CAACZ;oBACNH,GAAGgB,KAAK,CAACb;oBACTH,GAAGiB,EAAE,CAACT,iBAAiBL;oBACvBH,GAAGiB,EAAE,CACHvF,kBAAkByC,KAAK,8BACvBzC,kBAAkByE,uBAAuB;iBAE5C;gBACDe,UAAU;YACZ;YACAC,WAAW;gBAACZ;aAAiB;QAC/B;QACA9D,kCACE+B,eACA,UACA;QAEF/B,kCACE+B,eACA,UACA;IAEJ;IAEAA,cAAckC,OAAO,CAAC,aAAa,GAAG;QACpCG,UAAU;QACVjD,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,cAAc,CAAC;YAC1CsB,KAAK;QACP;IACF;IACA7C,cAAckC,OAAO,CAAC,MAAM,GAAG;QAC7BG,UAAU;QACVS,YAAY;QACZ1D,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,mBAAmB,CAAC;YAC/CsB,KAAK;QACP;QACAF,WAAW;YAAC;SAAa;IAC3B;IACA3C,cAAckC,OAAO,CAAC,cAAc,GAAG;QACrCG,UAAU;QACVM,WAAW;YAAC;SAAM;QAClBvD,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,UAAU,EAAEtB,OAAO,MAAM,CAAC;YACrD4C,KAAK;QACP;IACF;IACA7C,cAAckC,OAAO,CAACa,OAAO,GAAG;QAC9BV,UAAU;QACVM,WAAW;YAAC;YAAO;SAAc;QACjCvD,SAAS;YACPwD,SAAS;YACTC,KAAK;YACLG,KAAK;gBACHC,WAAW;YACb;QACF;IACF;IACAjD,cAAckC,OAAO,CAACpB,OAAO,GAAG;QAC9BuB,UAAU;QACVM,WAAW;YAAC;YAAO;SAAc;QACjCvD,SAAS;YACPwD,SAAS;YACTC,KAAK;YACLG,KAAK;gBACHC,WAAW;YACb;QACF;IACF;IAEA,IAAI7D,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAMoB,MAAM,MAAMxF,WAAWyB,MAAMC,QAAQ8D,GAAG;QAC9C,IAAIA,QAAQ,aAAa;YACvBlD,cAAckC,OAAO,CAACiB,MAAM,GAAG;gBAC7BhB,OAAO;gBACPE,UAAU;gBACVjD,SAAS;oBACPkD,UAAU;wBACR,GAAG7C,gBAAgB,oDAAoD,EAAEmC,wBAAwB,CAAC,EAAEH,oBAAoB;wBACxH,GAAGhC,gBAAgB,oDAAoD,EAAEoC,2BAA2B,CAAC,EAAEF,uBAAuB;qBAC/H;oBACDe,UAAU;gBACZ;gBACAC,WAAW;oBAAC;oBAAoB;iBAAwB;YAC1D;YACA1E,kCAAkC+B,eAAe,SAAS;YAE1DzC,oBAAoB4B,MAAM;gBACxBiE,SAASpD;gBACTP;gBACA4D,iBAAiB;gBACjBC,kBAAkB;gBAClBC,WAAW;oBAAC3B;oBAAyBC;iBAA2B;YAClE;QACF;QACA5D,kCACE+B,eACA,SACA;QAEF/B,kCACE+B,eACA,SACA;IAEJ;IAEA5C,2BAA2B+B,MAAMO,oBAAoBM;IACrD9B,qBAAqBiB,MAAMO,oBAAoBV,uBAAuB;QACpEiB;IACF;IAEA,IAAIb,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAMoB,MAAM,MAAMxF,WAAWyB,MAAMC,QAAQ8D,GAAG;QAC9C,MAAM1E,0BAA0BW,MAAM;YAAE+D;QAAI;QAC5C,MAAM3E,YAAYY,MAAM;YACtB+D;YACAM,aAAa9D;YACb+D,aAAa9D;YACbN;YACAqE,eAAe7F,UAAUuB,QAAQE,IAAI;YACrCqE,sBAAsB/D;YACtBJ;YACAoE,WAAWrE;YACXU;YACAwB;YACAE;YACAkC,WAAW;YACXhC;YACAD;YACAnC;QACF;IACF;IAEAnB,+BAA+Ba,MAAMQ,KAAK;QACxC;QACA;QACA,qEAAqE;QACrE,0EAA0E;QAC1E,mEAAmE;QACnE,6CAA6C;QAC7C;WACIM,WAAW,UACV;YAAC;YAAY;YAAS;SAAwB,GAC9C;YAAC;YAAW;YAAS;SAAwB;KACnD;IAED,MAAMrC,gCAAgCuB,MAAM;QAACH;KAAsB;IAEnE,MAAMxB,qBAAqB2B;IAC3B,OAAO,IACLxB,oBAAoBwB,MAAMC,QAAQ0E,yBAAyB,EAAE;YAC3DC,WAAW;gBAAC;gBAAc;aAAS;QACrC;AACJ,EAAE;AAEF,eAAe7E,eAAe"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies';\nimport { addDockerScanTarget } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport { assignPort } from '../../utils/port';\nimport { addDependenciesToPyProjectToml } from '../../utils/py';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport {\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport { sharedRdbScriptsGenerator } from '../../utils/shared-rdb-scripts';\nimport { PY_VERSIONS, withVersions } from '../../utils/versions';\nimport pyProjectGenerator, { getPyProjectDetails } from '../project/generator';\nimport type { PyRdbGeneratorSchema } from './schema';\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n );\n\n await sharedRdbScriptsGenerator(tree, engine);\n // Used by local dev script wait-for-*-db.ts\n addDependenciesToPackageJson(\n tree,\n withVersions([engine === 'mysql' ? 'mariadb' : 'pg']),\n engine === 'mysql' ? {} : withVersions(['@types/pg']),\n );\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n\n addDockerScanTarget(tree, {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n });\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(tree, fullyQualifiedName, PY_RDB_GENERATOR_INFO, {\n engine,\n });\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addDependenciesToPyProjectToml(tree, dir, [\n 'sqlmodel',\n 'alembic',\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n 'greenlet',\n ...(engine === 'mysql'\n ? (['aiomysql', 'boto3', 'aws-lambda-powertools'] as const)\n : (['asyncpg', 'boto3', 'aws-lambda-powertools'] as const)),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","generateFiles","joinPathFragments","readProjectConfiguration","updateProjectConfiguration","addPythonBundleTarget","resolveContainers","addDependenciesToPackageJson","addDockerScanTarget","formatFilesInSubtree","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addDependenciesToPyProjectToml","addRdbInfra","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","sharedRdbScriptsGenerator","PY_VERSIONS","withVersions","pyProjectGenerator","getPyProjectDetails","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","name","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","engine","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","scriptsDir","fs","migrationBundleDir","root","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","infra","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","iac","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"AAAA;;;CAGC,GACD,SAASA,QAAQ,QAAQ,YAAY;AACrC,SAEEC,aAAa,EACbC,iBAAiB,EACjBC,wBAAwB,EAExBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,qBAAqB,QAAQ,+BAA4B;AAClE,SAASC,iBAAiB,QAAQ,4BAAyB;AAC3D,SAASC,4BAA4B,QAAQ,8BAA2B;AACxE,SAASC,mBAAmB,QAAQ,wBAAqB;AACzD,SAASC,oBAAoB,QAAQ,wBAAqB;AAC1D,SAASC,UAAU,QAAQ,oBAAiB;AAC5C,SAASC,UAAU,QAAQ,qBAAkB;AAC7C,SAASC,mBAAmB,QAAQ,yBAAsB;AAC1D,SAASC,+BAA+B,QAAQ,yBAAsB;AACtE,SAASC,SAAS,EAAEC,SAAS,EAAEC,WAAW,QAAQ,uBAAoB;AACtE,SAASC,WAAW,QAAQ,2BAAwB;AACpD,SACEC,iCAAiC,EACjCC,oBAAoB,EACpBC,gBAAgB,EAEhBC,aAAa,QACR,oBAAiB;AACxB,SAASC,UAAU,QAAQ,sBAAmB;AAC9C,SAASC,8BAA8B,QAAQ,oBAAiB;AAChE,SAASC,WAAW,QAAQ,+CAA4C;AACxE,SAASC,yBAAyB,QAAQ,mCAAgC;AAC1E,SACEC,YAAY,EACZC,kBAAkB,QACb,6CAA0C;AACjD,SAASC,yBAAyB,QAAQ,oCAAiC;AAC3E,SAASC,WAAW,EAAEC,YAAY,QAAQ,0BAAuB;AACjE,OAAOC,sBAAsBC,mBAAmB,QAAQ,0BAAuB;AAG/E,OAAO,MAAMC,wBAAyCb,iBACpD,YAAYc,QAAQ,EACpB;AAEF,OAAO,MAAMC,iBAAiB,OAC5BC,MACAC;IAEA,MAAMC,gBAAgBtB,YAAYqB,QAAQE,IAAI;IAC9C,MAAMC,eAAeH,QAAQG,YAAY,IAAI;IAC7C,MAAMC,eAAe1B,UAAUsB,QAAQI,YAAY,IAAIJ,QAAQE,IAAI;IACnE,MAAMG,kBAAkB,MAAMpC,kBAAkB8B,MAAM;IAEtD,MAAM,EAAEO,kBAAkB,EAAEC,GAAG,EAAEC,oBAAoB,EAAE,GAAGb,oBACxDI,MACA;QACEG,MAAMF,QAAQE,IAAI;QAClBO,WAAWT,QAAQS,SAAS;QAC5BC,cAAcV,QAAQU,YAAY;IACpC;IAGF,IAAI,CAAC1B,cAAce,MAAMO,qBAAqB;QAC5C,MAAMZ,mBAAmBK,MAAM;YAC7BG,MAAMF,QAAQE,IAAI;YAClBO,WAAWT,QAAQS,SAAS;YAC5BC,cAAcV,QAAQU,YAAY;YAClCC,MAAM;QACR;IACF;IAEA,MAAMC,gBAAgB9C,yBAAyBiC,MAAMO;IAErD,MAAM,EAAEO,MAAM,EAAE,GAAGb;IACnB,MAAMc,cAAc7B,WAClBc,MACAa,eACAC,WAAW,UAAU,OAAO;IAE9B,MAAME,cAAc;IACpB,MAAMC,cAAcH,WAAW,UAAU,SAAS;IAClD,MAAMI,kBAAkB;IACxB,MAAMC,gBAAgB,GAAGtC,YAAYmB,MAAM,CAAC,EAAEK,cAAc;IAC5D,MAAMe,cACJN,WAAW,UACP,+CACA;IAEN,MAAMO,kBAAkB;QACtBlB,MAAMM;QACNa,kBAAkBpB;QAClBY;QACAC;QACAC;QACAO,aAAalB;QACbY;QACAC;QACAZ;QACAa;QACAC;QACAI,iBAAiB/B,YAAYgC,QAAQ;QACrCC,gBAAgBjC,YAAYkC,OAAO;QACnCC,iBAAiBnC,YAAYoC,QAAQ;QACrCC,gBAAgBrC,YAAYsC,OAAO;QACnCC,cAAcvC,YAAYwC,KAAK;QAC/BC,4BAA4BzC,WAAW,CAAC,wBAAwB;IAClE;IAEA5B,cACEmC,MACAlC,kBAAkB,YAAYqE,OAAO,EAAE,UACvC3B,KACAa;IAGF,MAAM7B,0BAA0BQ,MAAMc;IACtC,4CAA4C;IAC5C3C,6BACE6B,MACAN,aAAa;QAACoB,WAAW,UAAU,YAAY;KAAK,GACpDA,WAAW,UAAU,CAAC,IAAIpB,aAAa;QAAC;KAAY;IAEtD,MAAM0C,aAAaxE,SACjB4C,KACA1C,kBAAkBwB,cAAcC,oBAAoB,OAAO;IAE7D,MAAM8C,KAAK,IAAI/D,WAAW0B;IAE1B,MAAMsC,qBAAqBxE,kBACzB,QACA+C,cAAc0B,IAAI,EAClB,UACA;IAEF,MAAMC,wBAAwB1E,kBAC5B,QACA+C,cAAc0B,IAAI,EAClB,UACA;IAEF,MAAME,0BAA0B,GAAG5D,YAAYmB,MAAM,CAAC,EAAEtB,UAAUuB,QAAQE,IAAI,EAAE,iBAAiB,CAAC;IAClG,MAAMuC,6BAA6B,GAAG7D,YAAYmB,MAAM,CAAC,EAAEtB,UACzDuB,QAAQE,IAAI,EACZ,sBAAsB,CAAC;IAEzB,IAAIF,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAM,EAAEC,gBAAgB,EAAEC,eAAe,EAAE,GAAG5E,sBAC5C4C,eACA;YAAEiC,gBAAgB;QAAyB;QAG7CjC,cAAckC,OAAO,CAAC,mBAAmB,GAAG;YAC1CC,OAAO;YACPC,SAAS;gBAAC;aAAsD;YAChEC,UAAU;YACVjD,SAAS;gBACPkD,UAAU;oBACRd,GAAGe,EAAE,CAACd;oBACND,GAAGgB,KAAK,CAACf;oBACTD,GAAGiB,EAAE,CAACT,iBAAiBP;oBACvBD,GAAGiB,EAAE,CACHxF,kBAAkB0C,KAAK,eACvB1C,kBAAkBwE,oBAAoB;oBAExCD,GAAGiB,EAAE,CACHxF,kBAAkB0C,KAAK,gBACvB1C,kBAAkBwE,oBAAoB;oBAExCD,GAAGiB,EAAE,CACHxF,kBAAkB0C,KAAK,yBACvB1C,kBAAkBwE,oBAAoB;iBAEzC;gBACDiB,UAAU;YACZ;YACAC,WAAW;gBAACZ;aAAiB;QAC/B;QACA/B,cAAckC,OAAO,CAAC,wBAAwB,GAAG;YAC/CC,OAAO;YACPC,SAAS;gBAAC;aAA2D;YACrEC,UAAU;YACVjD,SAAS;gBACPkD,UAAU;oBACRd,GAAGe,EAAE,CAACZ;oBACNH,GAAGgB,KAAK,CAACb;oBACTH,GAAGiB,EAAE,CAACT,iBAAiBL;oBACvBH,GAAGiB,EAAE,CACHxF,kBAAkB0C,KAAK,8BACvB1C,kBAAkB0E,uBAAuB;iBAE5C;gBACDe,UAAU;YACZ;YACAC,WAAW;gBAACZ;aAAiB;QAC/B;QACA9D,kCACE+B,eACA,UACA;QAEF/B,kCACE+B,eACA,UACA;IAEJ;IAEAA,cAAckC,OAAO,CAAC,aAAa,GAAG;QACpCG,UAAU;QACVjD,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,cAAc,CAAC;YAC1CsB,KAAK;QACP;IACF;IACA7C,cAAckC,OAAO,CAAC,MAAM,GAAG;QAC7BG,UAAU;QACVS,YAAY;QACZ1D,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,mBAAmB,CAAC;YAC/CsB,KAAK;QACP;QACAF,WAAW;YAAC;SAAa;IAC3B;IACA3C,cAAckC,OAAO,CAAC,cAAc,GAAG;QACrCG,UAAU;QACVM,WAAW;YAAC;SAAM;QAClBvD,SAAS;YACPwD,SAAS,CAAC,IAAI,EAAErB,WAAW,UAAU,EAAEtB,OAAO,MAAM,CAAC;YACrD4C,KAAK;QACP;IACF;IACA7C,cAAckC,OAAO,CAACa,OAAO,GAAG;QAC9BV,UAAU;QACVM,WAAW;YAAC;YAAO;SAAc;QACjCvD,SAAS;YACPwD,SAAS;YACTC,KAAK;YACLG,KAAK;gBACHC,WAAW;YACb;QACF;IACF;IACAjD,cAAckC,OAAO,CAACpB,OAAO,GAAG;QAC9BuB,UAAU;QACVM,WAAW;YAAC;YAAO;SAAc;QACjCvD,SAAS;YACPwD,SAAS;YACTC,KAAK;YACLG,KAAK;gBACHC,WAAW;YACb;QACF;IACF;IAEA,IAAI7D,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAMoB,MAAM,MAAMxF,WAAWyB,MAAMC,QAAQ8D,GAAG;QAC9C,IAAIA,QAAQ,aAAa;YACvBlD,cAAckC,OAAO,CAACiB,MAAM,GAAG;gBAC7BhB,OAAO;gBACPE,UAAU;gBACVjD,SAAS;oBACPkD,UAAU;wBACR,GAAG7C,gBAAgB,oDAAoD,EAAEmC,wBAAwB,CAAC,EAAEH,oBAAoB;wBACxH,GAAGhC,gBAAgB,oDAAoD,EAAEoC,2BAA2B,CAAC,EAAEF,uBAAuB;qBAC/H;oBACDe,UAAU;gBACZ;gBACAC,WAAW;oBAAC;oBAAoB;iBAAwB;YAC1D;YACA1E,kCAAkC+B,eAAe,SAAS;YAE1DzC,oBAAoB4B,MAAM;gBACxBiE,SAASpD;gBACTP;gBACA4D,iBAAiB;gBACjBC,kBAAkB;gBAClBC,WAAW;oBAAC3B;oBAAyBC;iBAA2B;YAClE;QACF;QACA5D,kCACE+B,eACA,SACA;QAEF/B,kCACE+B,eACA,SACA;IAEJ;IAEA7C,2BAA2BgC,MAAMO,oBAAoBM;IACrD9B,qBAAqBiB,MAAMO,oBAAoBV,uBAAuB;QACpEiB;IACF;IAEA,IAAIb,QAAQ0C,KAAK,KAAK,QAAQ;QAC5B,MAAMoB,MAAM,MAAMxF,WAAWyB,MAAMC,QAAQ8D,GAAG;QAC9C,MAAM1E,0BAA0BW,MAAM;YAAE+D;QAAI;QAC5C,MAAM3E,YAAYY,MAAM;YACtB+D;YACAM,aAAa9D;YACb+D,aAAa9D;YACbN;YACAqE,eAAe7F,UAAUuB,QAAQE,IAAI;YACrCqE,sBAAsB/D;YACtBJ;YACAoE,WAAWrE;YACXU;YACAwB;YACAE;YACAkC,WAAW;YACXhC;YACAD;YACAnC;QACF;IACF;IAEAnB,+BAA+Ba,MAAMQ,KAAK;QACxC;QACA;QACA,qEAAqE;QACrE,0EAA0E;QAC1E,mEAAmE;QACnE,6CAA6C;QAC7C;WACIM,WAAW,UACV;YAAC;YAAY;YAAS;SAAwB,GAC9C;YAAC;YAAW;YAAS;SAAwB;KACnD;IAED,MAAMrC,gCAAgCuB,MAAM;QAACH;KAAsB;IAEnE,MAAMxB,qBAAqB2B;IAC3B,OAAO,IACLxB,oBAAoBwB,MAAMC,QAAQ0E,yBAAyB,EAAE;YAC3DC,WAAW;gBAAC;gBAAc;aAAS;QACrC;AACJ,EAAE;AAEF,eAAe7E,eAAe"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/ import {
|
|
4
|
+
*/ import { generateFiles, joinPathFragments, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
|
|
5
5
|
import tsProjectGenerator, { getTsLibDetails } from "../../../ts/lib/generator.js";
|
|
6
6
|
import { addApiGatewayInfra } from "../../../utils/api-constructs/api-constructs.js";
|
|
7
7
|
import { addSharedConstructsOpenApiMetadataGenerateTarget } from "../../../utils/api-constructs/open-api-metadata.js";
|
|
8
8
|
import { addTypeScriptBundleTarget } from "../../../utils/bundle/bundle.js";
|
|
9
|
+
import { addDependenciesToPackageJson } from "../../../utils/dependencies.js";
|
|
9
10
|
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
10
11
|
import { FsCommands } from "../../../utils/fs.js";
|
|
11
12
|
import { updateGitIgnore } from "../../../utils/git.js";
|
|
@@ -214,7 +215,9 @@ export const tsSmithyApiGenerator = async (tree, options)=>{
|
|
|
214
215
|
'@aws-lambda-powertools/parser'
|
|
215
216
|
] : []
|
|
216
217
|
]), withVersions([
|
|
217
|
-
'@types/aws-lambda'
|
|
218
|
+
'@types/aws-lambda'
|
|
219
|
+
]), joinPathFragments(backendProjectConfig.root, 'package.json'));
|
|
220
|
+
addDependenciesToPackageJson(tree, {}, withVersions([
|
|
218
221
|
'tsx'
|
|
219
222
|
]));
|
|
220
223
|
await addGeneratorMetricsIfApplicable(tree, [
|