@aws/nx-plugin 1.0.0-rc.96 → 1.0.0-rc.97
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/migrations.json +33 -3
- package/package.json +1 -1
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/agentcore-gateway/generator.js +6 -0
- package/src/agentcore-gateway/generator.js.map +1 -1
- package/src/agentcore-gateway/react-connection/__snapshots__/generator.spec.ts.snap +4 -1
- package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +68 -4
- package/src/agentcore-harness/generator.js +6 -0
- package/src/agentcore-harness/generator.js.map +1 -1
- package/src/connection/gateway-runtime-config.js +1 -1
- package/src/connection/gateway-runtime-config.js.map +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +6 -6
- package/src/infra/app/generator.js +34 -7
- package/src/infra/app/generator.js.map +1 -1
- package/src/init/generator.d.ts +1 -1
- package/src/init/generator.js +8 -6
- package/src/init/generator.js.map +1 -1
- package/src/init/schema.d.js.map +1 -1
- package/src/init/schema.d.ts +1 -0
- package/src/init/schema.json +5 -0
- package/src/mcp-server/server.js +2 -0
- package/src/mcp-server/server.js.map +1 -1
- package/src/mcp-server/tools/best-practices.d.ts +28 -0
- package/src/mcp-server/tools/best-practices.js +43 -0
- package/src/mcp-server/tools/best-practices.js.map +1 -0
- package/src/mcp-server/tools/general-guidance.d.ts +1 -1
- package/src/mcp-server/tools/general-guidance.js +13 -4
- package/src/mcp-server/tools/general-guidance.js.map +1 -1
- package/src/migrations/latest/checkov-scan-cache-inputs/metadata.json +3 -0
- package/src/migrations/latest/checkov-scan-cache-inputs/migration.d.ts +6 -0
- package/src/migrations/latest/checkov-scan-cache-inputs/migration.js +58 -0
- package/src/migrations/latest/checkov-scan-cache-inputs/migration.js.map +1 -0
- package/src/migrations/latest/gateway-url-accessor/__snapshots__/migration.spec.ts.snap +84 -0
- package/src/migrations/latest/gateway-url-accessor/metadata.json +3 -0
- package/src/migrations/latest/gateway-url-accessor/migration.d.ts +6 -0
- package/src/migrations/latest/gateway-url-accessor/migration.js +94 -0
- package/src/migrations/latest/gateway-url-accessor/migration.js.map +1 -0
- package/src/migrations/latest/infra-deploy-express-mode/metadata.json +1 -1
- package/src/migrations/latest/infra-deploy-express-mode/migration.js +26 -28
- package/src/migrations/latest/infra-deploy-express-mode/migration.js.map +1 -1
- package/src/migrations/latest/py-lambda-powertools-context/metadata.json +3 -0
- package/src/migrations/latest/py-lambda-powertools-context/migration.d.ts +6 -0
- package/src/migrations/latest/py-lambda-powertools-context/migration.js +58 -0
- package/src/migrations/latest/py-lambda-powertools-context/migration.js.map +1 -0
- package/src/migrations/latest/script-project-quality-gates/metadata.json +3 -0
- package/src/migrations/latest/script-project-quality-gates/migration.d.ts +6 -0
- package/src/migrations/latest/script-project-quality-gates/migration.js +53 -0
- package/src/migrations/latest/script-project-quality-gates/migration.js.map +1 -0
- package/src/migrations/latest/smithy-extension-trait-aliases/__snapshots__/migration.spec.ts.snap +25 -0
- package/src/migrations/latest/smithy-extension-trait-aliases/metadata.json +3 -0
- package/src/migrations/latest/smithy-extension-trait-aliases/migration.d.ts +28 -0
- package/src/migrations/latest/smithy-extension-trait-aliases/migration.js +75 -0
- package/src/migrations/latest/smithy-extension-trait-aliases/migration.js.map +1 -0
- package/src/migrations/latest/terraform-validate-without-backend/metadata.json +3 -0
- package/src/migrations/latest/terraform-validate-without-backend/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-validate-without-backend/migration.js +84 -0
- package/src/migrations/latest/terraform-validate-without-backend/migration.js.map +1 -0
- package/src/preset/generator.js +4 -25
- package/src/preset/generator.js.map +1 -1
- package/src/py/agent/a2a-connection/generator.d.ts +1 -1
- package/src/py/agent/gateway-connection/generator.d.ts +1 -1
- package/src/py/agent/mcp-connection/generator.d.ts +1 -1
- package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +4 -1
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +8 -10
- package/src/py/dynamodb/generator.js +34 -7
- package/src/py/dynamodb/generator.js.map +1 -1
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/py/lambda-function/files/handler/__lambdaFunctionSnakeCase__.py.template +2 -1
- package/src/py/project/schema.json +3 -1
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +28 -12
- package/src/py/rdb/files/Dockerfile.create-db-user.template +7 -3
- package/src/py/rdb/files/Dockerfile.migration.template +7 -3
- package/src/py/rdb/generator.js +29 -28
- package/src/py/rdb/generator.js.map +1 -1
- package/src/smithy/react-connection/files/model/extensions.smithy.template +3 -3
- package/src/smithy/ts/api/generator.js +7 -2
- package/src/smithy/ts/api/generator.js.map +1 -1
- package/src/terraform/project/generator.js +34 -10
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/generator.js +7 -1
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/react/generator.js +6 -0
- package/src/trpc/react/generator.js.map +1 -1
- package/src/ts/agent/generator.js +3 -3
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +2 -0
- package/src/ts/dynamodb/generator.js +30 -6
- package/src/ts/dynamodb/generator.js.map +1 -1
- package/src/ts/lib/biome.d.ts +15 -1
- package/src/ts/lib/biome.js +79 -63
- package/src/ts/lib/biome.js.map +1 -1
- package/src/ts/lib/generator.js +11 -7
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/ts-project-utils.d.ts +14 -0
- package/src/ts/lib/ts-project-utils.js +24 -0
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- package/src/ts/mcp-server/generator.js +3 -3
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +5 -0
- package/src/ts/rdb/files/Dockerfile.template +5 -0
- package/src/ts/rdb/generator.d.ts +8 -0
- package/src/ts/rdb/generator.js +28 -24
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +39 -0
- package/src/ts/rdb/trpc-connection/generator.js +13 -0
- package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
- package/src/ts/react-website/agui/files/common/src/components/__agentNameKebabCase__-chat.tsx.template +9 -0
- package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +4 -1
- package/src/ts/react-website/agui/generator.js +6 -2
- package/src/ts/react-website/agui/generator.js.map +1 -1
- package/src/ts/react-website/app/generator.js +3 -8
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/utils/agent-connection/agent-connection.d.ts +2 -1
- package/src/utils/agent-connection/agent-connection.js +6 -1
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +11 -7
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +14 -6
- package/src/utils/agent-core-packaging.js +5 -5
- package/src/utils/agent-core-packaging.js.map +1 -1
- package/src/utils/api-constructs/api-constructs.d.ts +5 -0
- package/src/utils/api-constructs/api-constructs.js +8 -0
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +4 -2
- package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +4 -2
- package/src/utils/ast.d.ts +10 -0
- package/src/utils/ast.js +33 -0
- package/src/utils/ast.js.map +1 -1
- package/src/utils/docker.d.ts +11 -0
- package/src/utils/docker.js +16 -3
- package/src/utils/docker.js.map +1 -1
- package/src/utils/dynamodb-config.d.ts +48 -0
- package/src/utils/dynamodb-config.js +44 -0
- package/src/utils/dynamodb-config.js.map +1 -0
- package/src/utils/dynamodb-constructs/files/cdk/app/dynamodb/__nameKebabCase__.ts.template +8 -4
- package/src/utils/git-secrets.d.ts +28 -0
- package/src/utils/git-secrets.js +66 -0
- package/src/utils/git-secrets.js.map +1 -0
- package/src/utils/init.js +7 -6
- package/src/utils/init.js.map +1 -1
- package/src/utils/local-project-dependency.d.ts +28 -0
- package/src/utils/local-project-dependency.js +40 -0
- package/src/utils/local-project-dependency.js.map +1 -0
- package/src/utils/nx.d.ts +14 -0
- package/src/utils/nx.js +30 -0
- package/src/utils/nx.js.map +1 -1
- package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +11 -6
- package/src/utils/script-project-targets.d.ts +26 -0
- package/src/utils/script-project-targets.js +75 -0
- package/src/utils/script-project-targets.js.map +1 -0
- package/src/utils/versions.d.ts +3 -0
- package/src/utils/versions.js +7 -0
- package/src/utils/versions.js.map +1 -1
- package/src/utils/website-constructs/files/cdk/app/static-websites/__websiteNameKebabCase__.ts.template +8 -4
- package/src/py/dynamodb/files/__name__/__init__.py.template +0 -6
- package/src/py/dynamodb/files/__name__/entities/__init__.py.template +0 -4
- package/src/py/dynamodb/files/config.json.template +0 -24
- package/src/ts/dynamodb/files/config.json.template +0 -24
- package/src/ts/dynamodb/files/src/entities/index.ts.template +0 -1
- package/src/ts/dynamodb/files/src/index.ts.template +0 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { applyGritQL, GRIT_INSERT_PLACEHOLDER, insertViaGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
5
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
6
|
+
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
7
|
+
/**
|
|
8
|
+
* The CDK `Gateway` L2 types its `gatewayUrl` as `string | undefined`, so
|
|
9
|
+
* reaching through the vended `AgentCoreGateway` construct to
|
|
10
|
+
* `gateway.gateway.gatewayUrl` does not typecheck where a `string` is required —
|
|
11
|
+
* the DCR proxy's `upstreamUrl`, for example. `AgentCoreGateway` gains a
|
|
12
|
+
* non-optional `gatewayUrl` accessor falling back to the CloudFormation
|
|
13
|
+
* attribute, which `addGateway` and the vended app-level gateway constructs then
|
|
14
|
+
* read.
|
|
15
|
+
*/ const CONSTRUCTS_SRC = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src`;
|
|
16
|
+
const GATEWAY_CONSTRUCT_FILE = `${CONSTRUCTS_SRC}/core/agentcore-gateway/agentcore-gateway.ts`;
|
|
17
|
+
const GATEWAYS_DIR = `${CONSTRUCTS_SRC}/app/gateways`;
|
|
18
|
+
const GATEWAY_URL_ACCESSOR = `/**
|
|
19
|
+
* The gateway's URL endpoint. The Gateway L2 types its own \`gatewayUrl\` as
|
|
20
|
+
* optional and only populates it when created from its own props, so fall
|
|
21
|
+
* back to the CloudFormation attribute.
|
|
22
|
+
*/
|
|
23
|
+
public get gatewayUrl(): string {
|
|
24
|
+
return (
|
|
25
|
+
this.gateway.gatewayUrl ??
|
|
26
|
+
(this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl
|
|
27
|
+
);
|
|
28
|
+
}`;
|
|
29
|
+
const divergedCoreMessage = `${GATEWAY_CONSTRUCT_FILE}: the AgentCoreGateway construct has diverged from the generated shape - left untouched. To use a gateway's URL where a \`string\` is required, add a \`public get gatewayUrl(): string\` accessor returning \`this.gateway.gatewayUrl ?? (this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl\`.`;
|
|
30
|
+
/**
|
|
31
|
+
* Add the `gatewayUrl` accessor to the vended core construct, and route
|
|
32
|
+
* `addGateway` and the shape it requires of its argument through it. Returns
|
|
33
|
+
* whether the core construct ends up carrying the accessor — app-level
|
|
34
|
+
* constructs may only be pointed at it once it exists.
|
|
35
|
+
*/ const migrateCoreConstruct = async (tree, nextSteps)=>{
|
|
36
|
+
if (!tree.exists(GATEWAY_CONSTRUCT_FILE)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const hasAccessor = await matchGritQL(tree, GATEWAY_CONSTRUCT_FILE, '`public get gatewayUrl(): string { $_ }`');
|
|
40
|
+
if (!hasAccessor) {
|
|
41
|
+
// Anchored on the grantPrincipal accessor, present in every vended version.
|
|
42
|
+
const added = await insertViaGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`public get grantPrincipal(): iam.IPrincipal { $body }\` as $accessor => \`$accessor
|
|
43
|
+
|
|
44
|
+
${GRIT_INSERT_PLACEHOLDER}\``, GATEWAY_URL_ACCESSOR);
|
|
45
|
+
if (!added) {
|
|
46
|
+
nextSteps.push(divergedCoreMessage);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const addGatewayUsesAccessor = await matchGritQL(tree, GATEWAY_CONSTRUCT_FILE, '`gatewayUrl: gateway.gatewayUrl`');
|
|
51
|
+
if (!addGatewayUsesAccessor) {
|
|
52
|
+
// The accessor is part of the shape addGateway requires of its argument.
|
|
53
|
+
await applyGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`readonly gatewayName: string\` as $member => \`$member;
|
|
54
|
+
readonly gatewayUrl: string\``);
|
|
55
|
+
// addGateway reads the accessor rather than repeating the fallback inline.
|
|
56
|
+
await applyGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`this.addGatewayTarget({ gatewayTargetName: $name, gatewayUrl: $url, gatewayArn: $arn })\` where {
|
|
57
|
+
$url <: contains \`attrGatewayUrl\`
|
|
58
|
+
} => \`this.addGatewayTarget({
|
|
59
|
+
gatewayTargetName: $name,
|
|
60
|
+
gatewayUrl: gateway.gatewayUrl,
|
|
61
|
+
gatewayArn: $arn,
|
|
62
|
+
})\``);
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Point each vended app-level gateway construct's runtime config entry at the
|
|
68
|
+
* accessor.
|
|
69
|
+
*/ const migrateAppConstructs = async (tree)=>{
|
|
70
|
+
if (!tree.exists(GATEWAYS_DIR)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
for (const dir of tree.children(GATEWAYS_DIR)){
|
|
74
|
+
const constructFile = `${GATEWAYS_DIR}/${dir}/${dir}.ts`;
|
|
75
|
+
if (!tree.exists(constructFile)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
await applyGritQL(tree, constructFile, '`this.gateway.gatewayUrl` => `this.gatewayUrl`');
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export default async function migration(tree) {
|
|
82
|
+
const nextSteps = [];
|
|
83
|
+
// The app constructs read the accessor, so they may only be migrated once the
|
|
84
|
+
// core construct carries it.
|
|
85
|
+
if (await migrateCoreConstruct(tree, nextSteps)) {
|
|
86
|
+
await migrateAppConstructs(tree);
|
|
87
|
+
}
|
|
88
|
+
await formatFilesInSubtree(tree);
|
|
89
|
+
return {
|
|
90
|
+
nextSteps
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/gateway-url-accessor/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport {\n applyGritQL,\n GRIT_INSERT_PLACEHOLDER,\n insertViaGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * The CDK `Gateway` L2 types its `gatewayUrl` as `string | undefined`, so\n * reaching through the vended `AgentCoreGateway` construct to\n * `gateway.gateway.gatewayUrl` does not typecheck where a `string` is required —\n * the DCR proxy's `upstreamUrl`, for example. `AgentCoreGateway` gains a\n * non-optional `gatewayUrl` accessor falling back to the CloudFormation\n * attribute, which `addGateway` and the vended app-level gateway constructs then\n * read.\n */\n\nconst CONSTRUCTS_SRC = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src`;\n\nconst GATEWAY_CONSTRUCT_FILE = `${CONSTRUCTS_SRC}/core/agentcore-gateway/agentcore-gateway.ts`;\n\nconst GATEWAYS_DIR = `${CONSTRUCTS_SRC}/app/gateways`;\n\nconst GATEWAY_URL_ACCESSOR = `/**\n * The gateway's URL endpoint. The Gateway L2 types its own \\`gatewayUrl\\` as\n * optional and only populates it when created from its own props, so fall\n * back to the CloudFormation attribute.\n */\n public get gatewayUrl(): string {\n return (\n this.gateway.gatewayUrl ??\n (this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl\n );\n }`;\n\nconst divergedCoreMessage = `${GATEWAY_CONSTRUCT_FILE}: the AgentCoreGateway construct has diverged from the generated shape - left untouched. To use a gateway's URL where a \\`string\\` is required, add a \\`public get gatewayUrl(): string\\` accessor returning \\`this.gateway.gatewayUrl ?? (this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl\\`.`;\n\n/**\n * Add the `gatewayUrl` accessor to the vended core construct, and route\n * `addGateway` and the shape it requires of its argument through it. Returns\n * whether the core construct ends up carrying the accessor — app-level\n * constructs may only be pointed at it once it exists.\n */\nconst migrateCoreConstruct = async (\n tree: Tree,\n nextSteps: string[],\n): Promise<boolean> => {\n if (!tree.exists(GATEWAY_CONSTRUCT_FILE)) {\n return false;\n }\n\n const hasAccessor = await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`public get gatewayUrl(): string { $_ }`',\n );\n\n if (!hasAccessor) {\n // Anchored on the grantPrincipal accessor, present in every vended version.\n const added = await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`public get grantPrincipal(): iam.IPrincipal { $body }\\` as $accessor => \\`$accessor\n\n ${GRIT_INSERT_PLACEHOLDER}\\``,\n GATEWAY_URL_ACCESSOR,\n );\n if (!added) {\n nextSteps.push(divergedCoreMessage);\n return false;\n }\n }\n\n const addGatewayUsesAccessor = await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`gatewayUrl: gateway.gatewayUrl`',\n );\n\n if (!addGatewayUsesAccessor) {\n // The accessor is part of the shape addGateway requires of its argument.\n await applyGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`readonly gatewayName: string\\` as $member => \\`$member;\n readonly gatewayUrl: string\\``,\n );\n\n // addGateway reads the accessor rather than repeating the fallback inline.\n await applyGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`this.addGatewayTarget({ gatewayTargetName: $name, gatewayUrl: $url, gatewayArn: $arn })\\` where {\n $url <: contains \\`attrGatewayUrl\\`\n} => \\`this.addGatewayTarget({\n gatewayTargetName: $name,\n gatewayUrl: gateway.gatewayUrl,\n gatewayArn: $arn,\n })\\``,\n );\n }\n\n return true;\n};\n\n/**\n * Point each vended app-level gateway construct's runtime config entry at the\n * accessor.\n */\nconst migrateAppConstructs = async (tree: Tree): Promise<void> => {\n if (!tree.exists(GATEWAYS_DIR)) {\n return;\n }\n for (const dir of tree.children(GATEWAYS_DIR)) {\n const constructFile = `${GATEWAYS_DIR}/${dir}/${dir}.ts`;\n if (!tree.exists(constructFile)) {\n continue;\n }\n await applyGritQL(\n tree,\n constructFile,\n '`this.gateway.gatewayUrl` => `this.gatewayUrl`',\n );\n }\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n // The app constructs read the accessor, so they may only be migrated once the\n // core construct carries it.\n if (await migrateCoreConstruct(tree, nextSteps)) {\n await migrateAppConstructs(tree);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","CONSTRUCTS_SRC","GATEWAY_CONSTRUCT_FILE","GATEWAYS_DIR","GATEWAY_URL_ACCESSOR","divergedCoreMessage","migrateCoreConstruct","tree","nextSteps","exists","hasAccessor","added","push","addGatewayUsesAccessor","migrateAppConstructs","dir","children","constructFile","migration"],"mappings":"AAAA;;;CAGC,GAED,SACEA,WAAW,EACXC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,qBAAqB,QAChB,gDAAgD;AAEvD;;;;;;;;CAQC,GAED,MAAMC,iBAAiB,GAAGF,aAAa,CAAC,EAAEC,sBAAsB,IAAI,CAAC;AAErE,MAAME,yBAAyB,GAAGD,eAAe,4CAA4C,CAAC;AAE9F,MAAME,eAAe,GAAGF,eAAe,aAAa,CAAC;AAErD,MAAMG,uBAAuB,CAAC;;;;;;;;;;GAU3B,CAAC;AAEJ,MAAMC,sBAAsB,GAAGH,uBAAuB,oTAAoT,CAAC;AAE3W;;;;;CAKC,GACD,MAAMI,uBAAuB,OAC3BC,MACAC;IAEA,IAAI,CAACD,KAAKE,MAAM,CAACP,yBAAyB;QACxC,OAAO;IACT;IAEA,MAAMQ,cAAc,MAAMb,YACxBU,MACAL,wBACA;IAGF,IAAI,CAACQ,aAAa;QAChB,4EAA4E;QAC5E,MAAMC,QAAQ,MAAMf,gBAClBW,MACAL,wBACA,CAAC;;EAEL,EAAEP,wBAAwB,EAAE,CAAC,EACzBS;QAEF,IAAI,CAACO,OAAO;YACVH,UAAUI,IAAI,CAACP;YACf,OAAO;QACT;IACF;IAEA,MAAMQ,yBAAyB,MAAMhB,YACnCU,MACAL,wBACA;IAGF,IAAI,CAACW,wBAAwB;QAC3B,yEAAyE;QACzE,MAAMnB,YACJa,MACAL,wBACA,CAAC;mCAC4B,CAAC;QAGhC,2EAA2E;QAC3E,MAAMR,YACJa,MACAL,wBACA,CAAC;;;;;;QAMC,CAAC;IAEP;IAEA,OAAO;AACT;AAEA;;;CAGC,GACD,MAAMY,uBAAuB,OAAOP;IAClC,IAAI,CAACA,KAAKE,MAAM,CAACN,eAAe;QAC9B;IACF;IACA,KAAK,MAAMY,OAAOR,KAAKS,QAAQ,CAACb,cAAe;QAC7C,MAAMc,gBAAgB,GAAGd,aAAa,CAAC,EAAEY,IAAI,CAAC,EAAEA,IAAI,GAAG,CAAC;QACxD,IAAI,CAACR,KAAKE,MAAM,CAACQ,gBAAgB;YAC/B;QACF;QACA,MAAMvB,YACJa,MACAU,eACA;IAEJ;AACF;AAEA,eAAe,eAAeC,UAC5BX,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,8EAA8E;IAC9E,6BAA6B;IAC7B,IAAI,MAAMF,qBAAqBC,MAAMC,YAAY;QAC/C,MAAMM,qBAAqBP;IAC7B;IAEA,MAAMT,qBAAqBS;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Deploy using CloudFormation express mode from the deploy
|
|
2
|
+
"description": "Deploy using CloudFormation express mode from the deploy-sandbox target of ts#infra projects, and wait for full stabilization from deploy"
|
|
3
3
|
}
|
|
@@ -5,29 +5,31 @@
|
|
|
5
5
|
import { INFRA_APP_GENERATOR_INFO } from "../../../infra/app/generator.js";
|
|
6
6
|
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
7
7
|
/**
|
|
8
|
-
* Deploy using CloudFormation express mode from the deploy
|
|
9
|
-
*
|
|
8
|
+
* Deploy using CloudFormation express mode from the deploy-sandbox target of
|
|
9
|
+
* ts#infra projects, and wait for full stabilization everywhere else.
|
|
10
10
|
*
|
|
11
|
-
* Express mode completes each resource operation as soon as its configuration
|
|
12
|
-
*
|
|
13
|
-
* iteration cycle for development deploys.
|
|
11
|
+
* Express mode completes each resource operation as soon as its configuration is
|
|
12
|
+
* applied rather than waiting for full stabilization, which is a much faster
|
|
13
|
+
* iteration cycle for development deploys. It returns before resources have
|
|
14
|
+
* settled, so it suits only the stage you iterate on.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*/ const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
* `deploy-sandbox` therefore gets it, since it only ever deploys the sandbox
|
|
17
|
+
* stage. `deploy` names whichever stage you give it, including beta and prod, and
|
|
18
|
+
* `deploy-ci` runs from a pipeline - both wait for full stabilization.
|
|
19
|
+
*/ const EXPRESS_FLAG = '--express';
|
|
20
|
+
const NO_EXPRESS_FLAG = '--no-express';
|
|
21
|
+
/** Whether `deploy-sandbox` should carry the flag, and `deploy` should not. */ const WANTS_EXPRESS = {
|
|
22
|
+
'deploy-sandbox': true,
|
|
23
|
+
deploy: false
|
|
24
|
+
};
|
|
23
25
|
/**
|
|
24
26
|
* Whether the command is one of the deploy commands this migration vends -
|
|
25
27
|
* either a direct `cdk deploy`, or the stage-config `infra-deploy.ts` script
|
|
26
28
|
* that wraps it. Anything else has been hand-written and is reported rather
|
|
27
29
|
* than rewritten.
|
|
28
30
|
*/ const isGeneratedDeployCommand = (command)=>/(^|\s)cdk\s+deploy(\s|$)/.test(command) || command.includes('infra-deploy.ts');
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
const divergedNextStep = (projectName, target, wantsExpress)=>wantsExpress ? `${projectName}: its ${target} target has been customised, so it was left as it is. Add "${EXPRESS_FLAG}" to the target's command to deploy using CloudFormation express mode.` : `${projectName}: its ${target} target has been customised, so it was left as it is. Remove "${EXPRESS_FLAG}" from the target's command so it waits for full resource stabilization - this target can name any stage, including production.`;
|
|
32
|
+
/** Drops the flag wherever it sits, leaving the rest of the command untouched. */ const withoutExpress = (command)=>command.split(/\s+/).filter((arg)=>arg !== EXPRESS_FLAG).join(' ');
|
|
31
33
|
export default async function migration(tree) {
|
|
32
34
|
const nextSteps = [];
|
|
33
35
|
let migrated = false;
|
|
@@ -36,35 +38,31 @@ export default async function migration(tree) {
|
|
|
36
38
|
continue;
|
|
37
39
|
}
|
|
38
40
|
let projectChanged = false;
|
|
39
|
-
for (const targetName of
|
|
41
|
+
for (const [targetName, wantsExpress] of Object.entries(WANTS_EXPRESS)){
|
|
40
42
|
const target = project.targets?.[targetName];
|
|
41
43
|
const command = target?.options?.command;
|
|
42
44
|
if (!target || typeof command !== 'string') {
|
|
43
45
|
continue;
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
const args = command.split(/\s+/);
|
|
48
|
+
const hasExpress = args.includes(EXPRESS_FLAG);
|
|
49
|
+
// Already in the wanted state, so re-running - and a project generated
|
|
50
|
+
// after this change - is a no-op.
|
|
51
|
+
if (hasExpress === wantsExpress) {
|
|
48
52
|
continue;
|
|
49
53
|
}
|
|
50
54
|
// `--no-express` is a deliberate opt-out, so honour it rather than
|
|
51
55
|
// flipping the user back to express mode.
|
|
52
|
-
if (
|
|
56
|
+
if (wantsExpress && args.includes(NO_EXPRESS_FLAG)) {
|
|
53
57
|
continue;
|
|
54
58
|
}
|
|
55
59
|
if (!isGeneratedDeployCommand(command)) {
|
|
56
|
-
nextSteps.push(divergedNextStep(name, targetName));
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
// When stages are configured, `deploy` deploys whichever stage is named,
|
|
60
|
-
// including beta and prod, so it stays on full stabilization. Only its
|
|
61
|
-
// sandbox counterpart opts into express mode.
|
|
62
|
-
if (targetName === 'deploy' && isStageConfigDeploy(command)) {
|
|
60
|
+
nextSteps.push(divergedNextStep(name, targetName, wantsExpress));
|
|
63
61
|
continue;
|
|
64
62
|
}
|
|
65
63
|
// Appended last so it stays clear of the stage pattern, which the
|
|
66
64
|
// stage-config deploy script reads from the first positional argument.
|
|
67
|
-
target.options.command = `${command} ${EXPRESS_FLAG}
|
|
65
|
+
target.options.command = wantsExpress ? `${command} ${EXPRESS_FLAG}` : withoutExpress(command);
|
|
68
66
|
projectChanged = true;
|
|
69
67
|
}
|
|
70
68
|
if (projectChanged) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/infra-deploy-express-mode/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Deploy using CloudFormation express mode from the deploy
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/infra-deploy-express-mode/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Deploy using CloudFormation express mode from the deploy-sandbox target of\n * ts#infra projects, and wait for full stabilization everywhere else.\n *\n * Express mode completes each resource operation as soon as its configuration is\n * applied rather than waiting for full stabilization, which is a much faster\n * iteration cycle for development deploys. It returns before resources have\n * settled, so it suits only the stage you iterate on.\n *\n * `deploy-sandbox` therefore gets it, since it only ever deploys the sandbox\n * stage. `deploy` names whichever stage you give it, including beta and prod, and\n * `deploy-ci` runs from a pipeline - both wait for full stabilization.\n */\n\nconst EXPRESS_FLAG = '--express';\nconst NO_EXPRESS_FLAG = '--no-express';\n\n/** Whether `deploy-sandbox` should carry the flag, and `deploy` should not. */\nconst WANTS_EXPRESS: Record<string, boolean> = {\n 'deploy-sandbox': true,\n deploy: false,\n};\n\n/**\n * Whether the command is one of the deploy commands this migration vends -\n * either a direct `cdk deploy`, or the stage-config `infra-deploy.ts` script\n * that wraps it. Anything else has been hand-written and is reported rather\n * than rewritten.\n */\nconst isGeneratedDeployCommand = (command: string): boolean =>\n /(^|\\s)cdk\\s+deploy(\\s|$)/.test(command) ||\n command.includes('infra-deploy.ts');\n\nconst divergedNextStep = (\n projectName: string,\n target: string,\n wantsExpress: boolean,\n): string =>\n wantsExpress\n ? `${projectName}: its ${target} target has been customised, so it was left as it is. Add \"${EXPRESS_FLAG}\" to the target's command to deploy using CloudFormation express mode.`\n : `${projectName}: its ${target} target has been customised, so it was left as it is. Remove \"${EXPRESS_FLAG}\" from the target's command so it waits for full resource stabilization - this target can name any stage, including production.`;\n\n/** Drops the flag wherever it sits, leaving the rest of the command untouched. */\nconst withoutExpress = (command: string): string =>\n command\n .split(/\\s+/)\n .filter((arg) => arg !== EXPRESS_FLAG)\n .join(' ');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n for (const [name, project] of getProjects(tree)) {\n if (\n (project.metadata as { generator?: string } | undefined)?.generator !==\n INFRA_APP_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n let projectChanged = false;\n\n for (const [targetName, wantsExpress] of Object.entries(WANTS_EXPRESS)) {\n const target: TargetConfiguration | undefined =\n project.targets?.[targetName];\n const command = target?.options?.command;\n if (!target || typeof command !== 'string') {\n continue;\n }\n\n const args = command.split(/\\s+/);\n const hasExpress = args.includes(EXPRESS_FLAG);\n\n // Already in the wanted state, so re-running - and a project generated\n // after this change - is a no-op.\n if (hasExpress === wantsExpress) {\n continue;\n }\n\n // `--no-express` is a deliberate opt-out, so honour it rather than\n // flipping the user back to express mode.\n if (wantsExpress && args.includes(NO_EXPRESS_FLAG)) {\n continue;\n }\n\n if (!isGeneratedDeployCommand(command)) {\n nextSteps.push(divergedNextStep(name, targetName, wantsExpress));\n continue;\n }\n\n // Appended last so it stays clear of the stage pattern, which the\n // stage-config deploy script reads from the first positional argument.\n target.options.command = wantsExpress\n ? `${command} ${EXPRESS_FLAG}`\n : withoutExpress(command);\n projectChanged = true;\n }\n\n if (projectChanged) {\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","EXPRESS_FLAG","NO_EXPRESS_FLAG","WANTS_EXPRESS","deploy","isGeneratedDeployCommand","command","test","includes","divergedNextStep","projectName","target","wantsExpress","withoutExpress","split","filter","arg","join","migration","tree","nextSteps","migrated","name","project","metadata","generator","id","projectChanged","targetName","Object","entries","targets","options","args","hasExpress","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;CAYC,GAED,MAAMC,eAAe;AACrB,MAAMC,kBAAkB;AAExB,6EAA6E,GAC7E,MAAMC,gBAAyC;IAC7C,kBAAkB;IAClBC,QAAQ;AACV;AAEA;;;;;CAKC,GACD,MAAMC,2BAA2B,CAACC,UAChC,2BAA2BC,IAAI,CAACD,YAChCA,QAAQE,QAAQ,CAAC;AAEnB,MAAMC,mBAAmB,CACvBC,aACAC,QACAC,eAEAA,eACI,GAAGF,YAAY,MAAM,EAAEC,OAAO,2DAA2D,EAAEV,aAAa,sEAAsE,CAAC,GAC/K,GAAGS,YAAY,MAAM,EAAEC,OAAO,8DAA8D,EAAEV,aAAa,+HAA+H,CAAC;AAEjP,gFAAgF,GAChF,MAAMY,iBAAiB,CAACP,UACtBA,QACGQ,KAAK,CAAC,OACNC,MAAM,CAAC,CAACC,MAAQA,QAAQf,cACxBgB,IAAI,CAAC;AAEV,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAI1B,YAAYsB,MAAO;QAC/C,IACE,AAACI,QAAQC,QAAQ,EAAyCC,cAC1D1B,yBAAyB2B,EAAE,EAC3B;YACA;QACF;QAEA,IAAIC,iBAAiB;QAErB,KAAK,MAAM,CAACC,YAAYhB,aAAa,IAAIiB,OAAOC,OAAO,CAAC3B,eAAgB;YACtE,MAAMQ,SACJY,QAAQQ,OAAO,EAAE,CAACH,WAAW;YAC/B,MAAMtB,UAAUK,QAAQqB,SAAS1B;YACjC,IAAI,CAACK,UAAU,OAAOL,YAAY,UAAU;gBAC1C;YACF;YAEA,MAAM2B,OAAO3B,QAAQQ,KAAK,CAAC;YAC3B,MAAMoB,aAAaD,KAAKzB,QAAQ,CAACP;YAEjC,uEAAuE;YACvE,kCAAkC;YAClC,IAAIiC,eAAetB,cAAc;gBAC/B;YACF;YAEA,mEAAmE;YACnE,0CAA0C;YAC1C,IAAIA,gBAAgBqB,KAAKzB,QAAQ,CAACN,kBAAkB;gBAClD;YACF;YAEA,IAAI,CAACG,yBAAyBC,UAAU;gBACtCc,UAAUe,IAAI,CAAC1B,iBAAiBa,MAAMM,YAAYhB;gBAClD;YACF;YAEA,kEAAkE;YAClE,uEAAuE;YACvED,OAAOqB,OAAO,CAAC1B,OAAO,GAAGM,eACrB,GAAGN,QAAQ,CAAC,EAAEL,cAAc,GAC5BY,eAAeP;YACnBqB,iBAAiB;QACnB;QAEA,IAAIA,gBAAgB;YAClB7B,2BAA2BqB,MAAMG,MAAMC;YACvCF,WAAW;QACb;IACF;IAEA,IAAIA,UAAU;QACZ,MAAMrB,qBAAqBmB;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { getProjects, joinPathFragments } from "@nx/devkit";
|
|
5
|
+
import { LAMBDA_FUNCTION_GENERATOR_INFO } from "../../../py/lambda-function/generator.js";
|
|
6
|
+
import { applyGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
7
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
8
|
+
/**
|
|
9
|
+
* Wire powertools Lambda context injection and the cold start metric into
|
|
10
|
+
* handlers generated by py#lambda-function.
|
|
11
|
+
*
|
|
12
|
+
* `@logger.inject_lambda_context` is what annotates each log record with the
|
|
13
|
+
* function name, request id, memory size and cold start flag, and
|
|
14
|
+
* `capture_cold_start_metric` is what emits the `ColdStart` metric.
|
|
15
|
+
*
|
|
16
|
+
* Both rewrites are scoped to the decorator list of the `lambda_handler`
|
|
17
|
+
* definition, so a `@metrics.log_metrics` decorating another function in the
|
|
18
|
+
* same module is left alone.
|
|
19
|
+
*/ const INJECT_CONTEXT = '@logger.inject_lambda_context';
|
|
20
|
+
const LOG_METRICS_OLD = '@metrics.log_metrics';
|
|
21
|
+
const LOG_METRICS_NEW = '@metrics.log_metrics(capture_cold_start_metric=True)';
|
|
22
|
+
const HANDLER_DECORATORS = (body)=>`language python
|
|
23
|
+
decorated_definition($decorators, $definition) where {
|
|
24
|
+
$definition <: contains \`lambda_handler\`,
|
|
25
|
+
${body}
|
|
26
|
+
}`;
|
|
27
|
+
/** The shape the generator produces: a bare `log_metrics` below the tracer. */ const GENERATED_SHAPE = HANDLER_DECORATORS(`$decorators <: contains \`@tracer.capture_lambda_handler\`,
|
|
28
|
+
$decorators <: contains \`${LOG_METRICS_OLD}\``);
|
|
29
|
+
const ALREADY_MIGRATED = HANDLER_DECORATORS(`$decorators <: contains \`${INJECT_CONTEXT}\`,
|
|
30
|
+
$decorators <: contains \`${LOG_METRICS_NEW}\``);
|
|
31
|
+
const REWRITE = HANDLER_DECORATORS(`$decorators <: contains \`@tracer.capture_lambda_handler\` => raw\`@tracer.capture_lambda_handler
|
|
32
|
+
${INJECT_CONTEXT}\`,
|
|
33
|
+
$decorators <: contains \`${LOG_METRICS_OLD}\` => \`${LOG_METRICS_NEW}\``);
|
|
34
|
+
const migrateHandler = async (tree, handlerPath, nextSteps)=>{
|
|
35
|
+
if (!tree.exists(handlerPath)) return;
|
|
36
|
+
if (await matchGritQL(tree, handlerPath, ALREADY_MIGRATED)) return;
|
|
37
|
+
if (!await matchGritQL(tree, handlerPath, GENERATED_SHAPE)) {
|
|
38
|
+
nextSteps.push(`${handlerPath}: diverged from the generated py#lambda-function shape - left untouched. To annotate logs with the Lambda context and emit a ColdStart metric, add \`${INJECT_CONTEXT}\` to the handler and change \`${LOG_METRICS_OLD}\` to \`${LOG_METRICS_NEW}\`.`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await applyGritQL(tree, handlerPath, REWRITE);
|
|
42
|
+
};
|
|
43
|
+
export default async function migration(tree) {
|
|
44
|
+
const nextSteps = [];
|
|
45
|
+
for (const project of getProjects(tree).values()){
|
|
46
|
+
const components = (project.metadata?.components ?? []).filter((component)=>component.generator === LAMBDA_FUNCTION_GENERATOR_INFO.id);
|
|
47
|
+
for (const component of components){
|
|
48
|
+
if (!component.path) continue;
|
|
49
|
+
await migrateHandler(tree, joinPathFragments(project.root, component.path), nextSteps);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
await formatFilesInSubtree(tree);
|
|
53
|
+
return {
|
|
54
|
+
nextSteps
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/py-lambda-powertools-context/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { LAMBDA_FUNCTION_GENERATOR_INFO } from '../../../py/lambda-function/generator.js';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport type { ComponentMetadata } from '../../../utils/nx.js';\n\n/**\n * Wire powertools Lambda context injection and the cold start metric into\n * handlers generated by py#lambda-function.\n *\n * `@logger.inject_lambda_context` is what annotates each log record with the\n * function name, request id, memory size and cold start flag, and\n * `capture_cold_start_metric` is what emits the `ColdStart` metric.\n *\n * Both rewrites are scoped to the decorator list of the `lambda_handler`\n * definition, so a `@metrics.log_metrics` decorating another function in the\n * same module is left alone.\n */\nconst INJECT_CONTEXT = '@logger.inject_lambda_context';\nconst LOG_METRICS_OLD = '@metrics.log_metrics';\nconst LOG_METRICS_NEW = '@metrics.log_metrics(capture_cold_start_metric=True)';\n\nconst HANDLER_DECORATORS = (body: string) => `language python\ndecorated_definition($decorators, $definition) where {\n $definition <: contains \\`lambda_handler\\`,\n ${body}\n}`;\n\n/** The shape the generator produces: a bare `log_metrics` below the tracer. */\nconst GENERATED_SHAPE =\n HANDLER_DECORATORS(`$decorators <: contains \\`@tracer.capture_lambda_handler\\`,\n $decorators <: contains \\`${LOG_METRICS_OLD}\\``);\n\nconst ALREADY_MIGRATED =\n HANDLER_DECORATORS(`$decorators <: contains \\`${INJECT_CONTEXT}\\`,\n $decorators <: contains \\`${LOG_METRICS_NEW}\\``);\n\nconst REWRITE =\n HANDLER_DECORATORS(`$decorators <: contains \\`@tracer.capture_lambda_handler\\` => raw\\`@tracer.capture_lambda_handler\n${INJECT_CONTEXT}\\`,\n $decorators <: contains \\`${LOG_METRICS_OLD}\\` => \\`${LOG_METRICS_NEW}\\``);\n\nconst migrateHandler = async (\n tree: Tree,\n handlerPath: string,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(handlerPath)) return;\n\n if (await matchGritQL(tree, handlerPath, ALREADY_MIGRATED)) return;\n\n if (!(await matchGritQL(tree, handlerPath, GENERATED_SHAPE))) {\n nextSteps.push(\n `${handlerPath}: diverged from the generated py#lambda-function shape - left untouched. To annotate logs with the Lambda context and emit a ColdStart metric, add \\`${INJECT_CONTEXT}\\` to the handler and change \\`${LOG_METRICS_OLD}\\` to \\`${LOG_METRICS_NEW}\\`.`,\n );\n return;\n }\n\n await applyGritQL(tree, handlerPath, REWRITE);\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const project of getProjects(tree).values()) {\n const components = (\n (project.metadata as { components?: ComponentMetadata[] })?.components ??\n []\n ).filter(\n (component) => component.generator === LAMBDA_FUNCTION_GENERATOR_INFO.id,\n );\n\n for (const component of components) {\n if (!component.path) continue;\n await migrateHandler(\n tree,\n joinPathFragments(project.root, component.path),\n nextSteps,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","LAMBDA_FUNCTION_GENERATOR_INFO","applyGritQL","matchGritQL","formatFilesInSubtree","INJECT_CONTEXT","LOG_METRICS_OLD","LOG_METRICS_NEW","HANDLER_DECORATORS","body","GENERATED_SHAPE","ALREADY_MIGRATED","REWRITE","migrateHandler","tree","handlerPath","nextSteps","exists","push","migration","project","values","components","metadata","filter","component","generator","id","path","root"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,8BAA8B,QAAQ,2CAA2C;AAC1F,SAASC,WAAW,EAAEC,WAAW,QAAQ,wBAAwB;AACjE,SAASC,oBAAoB,QAAQ,2BAA2B;AAGhE;;;;;;;;;;;CAWC,GACD,MAAMC,iBAAiB;AACvB,MAAMC,kBAAkB;AACxB,MAAMC,kBAAkB;AAExB,MAAMC,qBAAqB,CAACC,OAAiB,CAAC;;;EAG5C,EAAEA,KAAK;CACR,CAAC;AAEF,6EAA6E,GAC7E,MAAMC,kBACJF,mBAAmB,CAAC;4BACM,EAAEF,gBAAgB,EAAE,CAAC;AAEjD,MAAMK,mBACJH,mBAAmB,CAAC,0BAA0B,EAAEH,eAAe;4BACrC,EAAEE,gBAAgB,EAAE,CAAC;AAEjD,MAAMK,UACJJ,mBAAmB,CAAC;AACtB,EAAEH,eAAe;4BACW,EAAEC,gBAAgB,QAAQ,EAAEC,gBAAgB,EAAE,CAAC;AAE3E,MAAMM,iBAAiB,OACrBC,MACAC,aACAC;IAEA,IAAI,CAACF,KAAKG,MAAM,CAACF,cAAc;IAE/B,IAAI,MAAMZ,YAAYW,MAAMC,aAAaJ,mBAAmB;IAE5D,IAAI,CAAE,MAAMR,YAAYW,MAAMC,aAAaL,kBAAmB;QAC5DM,UAAUE,IAAI,CACZ,GAAGH,YAAY,qJAAqJ,EAAEV,eAAe,+BAA+B,EAAEC,gBAAgB,QAAQ,EAAEC,gBAAgB,GAAG,CAAC;QAEtQ;IACF;IAEA,MAAML,YAAYY,MAAMC,aAAaH;AACvC;AAEA,eAAe,eAAeO,UAC5BL,IAAU;IAEV,MAAME,YAAsB,EAAE;IAE9B,KAAK,MAAMI,WAAWrB,YAAYe,MAAMO,MAAM,GAAI;QAChD,MAAMC,aAAa,AACjB,CAAA,AAACF,QAAQG,QAAQ,EAA2CD,cAC5D,EAAE,AAAD,EACDE,MAAM,CACN,CAACC,YAAcA,UAAUC,SAAS,KAAKzB,+BAA+B0B,EAAE;QAG1E,KAAK,MAAMF,aAAaH,WAAY;YAClC,IAAI,CAACG,UAAUG,IAAI,EAAE;YACrB,MAAMf,eACJC,MACAd,kBAAkBoB,QAAQS,IAAI,EAAEJ,UAAUG,IAAI,GAC9CZ;QAEJ;IACF;IAEA,MAAMZ,qBAAqBU;IAE3B,OAAO;QAAEE;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { getProjects, joinPathFragments, updateProjectConfiguration } from "@nx/devkit";
|
|
5
|
+
import { AGENTCORE_GATEWAY_GENERATOR_INFO } from "../../../agentcore-gateway/generator.js";
|
|
6
|
+
import { AGENTCORE_HARNESS_GENERATOR_INFO } from "../../../agentcore-harness/generator.js";
|
|
7
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
8
|
+
import { addScriptProjectTargets } from "../../../utils/script-project-targets.js";
|
|
9
|
+
/**
|
|
10
|
+
* AgentCore Gateway and Harness projects host TypeScript that runs through
|
|
11
|
+
* `tsx` — a Gateway's `local-dev.ts` (which the connection generators edit) and
|
|
12
|
+
* a Harness's `scripts/chat.ts`. Neither project had a `tsconfig.json` or a
|
|
13
|
+
* `build`, `lint`, `format` or `typecheck` target, so that code was invisible to
|
|
14
|
+
* `nx run-many --target build --all` and a type error in it only surfaced at
|
|
15
|
+
* runtime.
|
|
16
|
+
*
|
|
17
|
+
* How to write a migration:
|
|
18
|
+
* - https://nx.dev/docs/kb/migration-generators
|
|
19
|
+
* - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject
|
|
20
|
+
*/ /** The generators whose projects gain the gates. */ const SCRIPT_PROJECT_GENERATORS = [
|
|
21
|
+
AGENTCORE_GATEWAY_GENERATOR_INFO.id,
|
|
22
|
+
AGENTCORE_HARNESS_GENERATOR_INFO.id
|
|
23
|
+
];
|
|
24
|
+
export default async function migration(tree) {
|
|
25
|
+
const nextSteps = [];
|
|
26
|
+
for (const [, project] of getProjects(tree)){
|
|
27
|
+
const generator = project.metadata?.generator;
|
|
28
|
+
if (!generator || !SCRIPT_PROJECT_GENERATORS.includes(generator)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
// Already migrated (or the user added their own gates).
|
|
32
|
+
if (project.targets?.typecheck) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
// A project that has been reworked into a compiled `ts#project` owns its own
|
|
36
|
+
// tsconfig graph, so leave it alone rather than layering a `noEmit` config on
|
|
37
|
+
// top of one that emits.
|
|
38
|
+
if (tree.exists(joinPathFragments(project.root, 'tsconfig.lib.json'))) {
|
|
39
|
+
nextSteps.push(`Project '${project.name}' has a tsconfig.lib.json, so its quality gates were left as they are. Confirm its build covers the TypeScript at ${project.root}.`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
addScriptProjectTargets(tree, {
|
|
43
|
+
project
|
|
44
|
+
});
|
|
45
|
+
updateProjectConfiguration(tree, project.name, project);
|
|
46
|
+
}
|
|
47
|
+
await formatFilesInSubtree(tree);
|
|
48
|
+
return {
|
|
49
|
+
nextSteps
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/script-project-quality-gates/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { AGENTCORE_GATEWAY_GENERATOR_INFO } from '../../../agentcore-gateway/generator.js';\nimport { AGENTCORE_HARNESS_GENERATOR_INFO } from '../../../agentcore-harness/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addScriptProjectTargets } from '../../../utils/script-project-targets.js';\n\n/**\n * AgentCore Gateway and Harness projects host TypeScript that runs through\n * `tsx` — a Gateway's `local-dev.ts` (which the connection generators edit) and\n * a Harness's `scripts/chat.ts`. Neither project had a `tsconfig.json` or a\n * `build`, `lint`, `format` or `typecheck` target, so that code was invisible to\n * `nx run-many --target build --all` and a type error in it only surfaced at\n * runtime.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n */\n\n/** The generators whose projects gain the gates. */\nconst SCRIPT_PROJECT_GENERATORS = [\n AGENTCORE_GATEWAY_GENERATOR_INFO.id,\n AGENTCORE_HARNESS_GENERATOR_INFO.id,\n];\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (!generator || !SCRIPT_PROJECT_GENERATORS.includes(generator)) {\n continue;\n }\n // Already migrated (or the user added their own gates).\n if (project.targets?.typecheck) {\n continue;\n }\n // A project that has been reworked into a compiled `ts#project` owns its own\n // tsconfig graph, so leave it alone rather than layering a `noEmit` config on\n // top of one that emits.\n if (tree.exists(joinPathFragments(project.root, 'tsconfig.lib.json'))) {\n nextSteps.push(\n `Project '${project.name}' has a tsconfig.lib.json, so its quality gates were left as they are. Confirm its build covers the TypeScript at ${project.root}.`,\n );\n continue;\n }\n\n addScriptProjectTargets(tree, { project });\n updateProjectConfiguration(tree, project.name, project);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","AGENTCORE_GATEWAY_GENERATOR_INFO","AGENTCORE_HARNESS_GENERATOR_INFO","formatFilesInSubtree","addScriptProjectTargets","SCRIPT_PROJECT_GENERATORS","id","migration","tree","nextSteps","project","generator","metadata","includes","targets","typecheck","exists","root","push","name"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAGjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,uBAAuB,QAAQ,2CAA2C;AAEnF;;;;;;;;;;;CAWC,GAED,kDAAkD,GAClD,MAAMC,4BAA4B;IAChCJ,iCAAiCK,EAAE;IACnCJ,iCAAiCI,EAAE;CACpC;AAED,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,GAAGC,QAAQ,IAAIZ,YAAYU,MAAO;QAC3C,MAAMG,YAAaD,QAAQE,QAAQ,EAC/BD;QACJ,IAAI,CAACA,aAAa,CAACN,0BAA0BQ,QAAQ,CAACF,YAAY;YAChE;QACF;QACA,wDAAwD;QACxD,IAAID,QAAQI,OAAO,EAAEC,WAAW;YAC9B;QACF;QACA,6EAA6E;QAC7E,8EAA8E;QAC9E,yBAAyB;QACzB,IAAIP,KAAKQ,MAAM,CAACjB,kBAAkBW,QAAQO,IAAI,EAAE,uBAAuB;YACrER,UAAUS,IAAI,CACZ,CAAC,SAAS,EAAER,QAAQS,IAAI,CAAC,kHAAkH,EAAET,QAAQO,IAAI,CAAC,CAAC,CAAC;YAE9J;QACF;QAEAb,wBAAwBI,MAAM;YAAEE;QAAQ;QACxCV,2BAA2BQ,MAAME,QAAQS,IAAI,EAAET;IACjD;IAEA,MAAMP,qBAAqBK;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
package/src/migrations/latest/smithy-extension-trait-aliases/__snapshots__/migration.spec.ts.snap
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`smithy-extension-trait-aliases migration > should alias every vended trait 1`] = `
|
|
4
|
+
"$version: "2.0"
|
|
5
|
+
|
|
6
|
+
namespace com.example
|
|
7
|
+
|
|
8
|
+
use smithy.openapi#specificationExtension
|
|
9
|
+
|
|
10
|
+
@trait
|
|
11
|
+
@specificationExtension(as: "x-query")
|
|
12
|
+
structure query {}
|
|
13
|
+
|
|
14
|
+
@trait
|
|
15
|
+
@specificationExtension(as: "x-mutation")
|
|
16
|
+
structure mutation {}
|
|
17
|
+
|
|
18
|
+
@trait
|
|
19
|
+
@specificationExtension(as: "x-cursor")
|
|
20
|
+
structure cursor {
|
|
21
|
+
inputToken: String
|
|
22
|
+
enabled: Boolean
|
|
23
|
+
}
|
|
24
|
+
"
|
|
25
|
+
`;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
/**
|
|
7
|
+
* Give each trait in a Smithy model's `extensions.smithy` an explicit
|
|
8
|
+
* `@specificationExtension(as: "...")` alias.
|
|
9
|
+
*
|
|
10
|
+
* Without the alias Smithy derives the OpenAPI key from the trait's shape id and
|
|
11
|
+
* emits a namespace-prefixed key (`x-<namespace>-query`), which the client code
|
|
12
|
+
* generator does not read — so the `@query`, `@mutation` and `@cursor` traits
|
|
13
|
+
* have no effect on the generated client. The alias pins each key to the
|
|
14
|
+
* unprefixed name the generator recognises.
|
|
15
|
+
*
|
|
16
|
+
* How to write a migration:
|
|
17
|
+
* - https://nx.dev/docs/kb/migration-generators
|
|
18
|
+
* - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject
|
|
19
|
+
*
|
|
20
|
+
* Guardrails:
|
|
21
|
+
* - Smithy IDL is not a language GritQL parses, so each edit is anchored to the
|
|
22
|
+
* exact `@trait` + `@specificationExtension` + `structure <name>` triple the
|
|
23
|
+
* generator vends.
|
|
24
|
+
* - A declaration that already carries an `as:` argument, or that has diverged
|
|
25
|
+
* from the vended shape, is left alone and reported via `nextSteps`.
|
|
26
|
+
* - Idempotent: an aliased declaration no longer matches the bare pattern.
|
|
27
|
+
*/
|
|
28
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { getProjects, joinPathFragments } from "@nx/devkit";
|
|
5
|
+
import { SMITHY_PROJECT_GENERATOR_INFO } from "../../../smithy/project/generator.js";
|
|
6
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
7
|
+
/** The traits the connection generator vends, each named after its OpenAPI key. */ const TRAITS = [
|
|
8
|
+
'query',
|
|
9
|
+
'mutation',
|
|
10
|
+
'cursor'
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Matches a bare `@specificationExtension` applied to the named structure, with
|
|
14
|
+
* the `@trait` and `@specificationExtension` traits adjacent to the `structure`
|
|
15
|
+
* they annotate. A declaration that already carries an argument does not match.
|
|
16
|
+
*/ const bareDeclaration = (trait)=>new RegExp(`(@trait\\s*\\n\\s*@specificationExtension)(\\s*\\n\\s*structure\\s+${trait}\\s*\\{)`);
|
|
17
|
+
/**
|
|
18
|
+
* Give each trait in a Smithy model's `extensions.smithy` an explicit
|
|
19
|
+
* `@specificationExtension(as: "...")` alias.
|
|
20
|
+
*
|
|
21
|
+
* Without the alias Smithy derives the OpenAPI key from the trait's shape id and
|
|
22
|
+
* emits a namespace-prefixed key (`x-<namespace>-query`), which the client code
|
|
23
|
+
* generator does not read — so the `@query`, `@mutation` and `@cursor` traits
|
|
24
|
+
* have no effect on the generated client. The alias pins each key to the
|
|
25
|
+
* unprefixed name the generator recognises.
|
|
26
|
+
*
|
|
27
|
+
* How to write a migration:
|
|
28
|
+
* - https://nx.dev/docs/kb/migration-generators
|
|
29
|
+
* - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject
|
|
30
|
+
*
|
|
31
|
+
* Guardrails:
|
|
32
|
+
* - Smithy IDL is not a language GritQL parses, so each edit is anchored to the
|
|
33
|
+
* exact `@trait` + `@specificationExtension` + `structure <name>` triple the
|
|
34
|
+
* generator vends.
|
|
35
|
+
* - A declaration that already carries an `as:` argument, or that has diverged
|
|
36
|
+
* from the vended shape, is left alone and reported via `nextSteps`.
|
|
37
|
+
* - Idempotent: an aliased declaration no longer matches the bare pattern.
|
|
38
|
+
*/ export default async function migration(tree) {
|
|
39
|
+
const nextSteps = [];
|
|
40
|
+
for (const [, project] of getProjects(tree)){
|
|
41
|
+
if ((project.metadata ?? {}).generator !== SMITHY_PROJECT_GENERATOR_INFO.id) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const extensionsPath = joinPathFragments(project.sourceRoot ?? joinPathFragments(project.root, 'src'), 'extensions.smithy');
|
|
45
|
+
if (!tree.exists(extensionsPath)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const before = tree.read(extensionsPath, 'utf-8') ?? '';
|
|
49
|
+
let after = before;
|
|
50
|
+
const skipped = [];
|
|
51
|
+
for (const trait of TRAITS){
|
|
52
|
+
if (after.includes(`@specificationExtension(as: "x-${trait}")`)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const bare = bareDeclaration(trait);
|
|
56
|
+
if (!bare.test(after)) {
|
|
57
|
+
skipped.push(trait);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
after = after.replace(bare, `$1(as: "x-${trait}")$2`);
|
|
61
|
+
}
|
|
62
|
+
if (after !== before) {
|
|
63
|
+
tree.write(extensionsPath, after);
|
|
64
|
+
}
|
|
65
|
+
if (skipped.length > 0) {
|
|
66
|
+
nextSteps.push(`${extensionsPath}: add ${skipped.map((trait)=>`\`(as: "x-${trait}")\``).join(', ')} to the \`@specificationExtension\` trait on ${skipped.map((trait)=>`\`${trait}\``).join(', ')}, so Smithy emits the ${skipped.map((trait)=>`\`x-${trait}\``).join(', ')} OpenAPI ${skipped.length === 1 ? 'key' : 'keys'} the client generator reads.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await formatFilesInSubtree(tree);
|
|
70
|
+
return {
|
|
71
|
+
nextSteps
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/smithy-extension-trait-aliases/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { SMITHY_PROJECT_GENERATOR_INFO } from '../../../smithy/project/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/** The traits the connection generator vends, each named after its OpenAPI key. */\nconst TRAITS = ['query', 'mutation', 'cursor'] as const;\n\n/**\n * Matches a bare `@specificationExtension` applied to the named structure, with\n * the `@trait` and `@specificationExtension` traits adjacent to the `structure`\n * they annotate. A declaration that already carries an argument does not match.\n */\nconst bareDeclaration = (trait: string) =>\n new RegExp(\n `(@trait\\\\s*\\\\n\\\\s*@specificationExtension)(\\\\s*\\\\n\\\\s*structure\\\\s+${trait}\\\\s*\\\\{)`,\n );\n\n/**\n * Give each trait in a Smithy model's `extensions.smithy` an explicit\n * `@specificationExtension(as: \"...\")` alias.\n *\n * Without the alias Smithy derives the OpenAPI key from the trait's shape id and\n * emits a namespace-prefixed key (`x-<namespace>-query`), which the client code\n * generator does not read — so the `@query`, `@mutation` and `@cursor` traits\n * have no effect on the generated client. The alias pins each key to the\n * unprefixed name the generator recognises.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Smithy IDL is not a language GritQL parses, so each edit is anchored to the\n * exact `@trait` + `@specificationExtension` + `structure <name>` triple the\n * generator vends.\n * - A declaration that already carries an `as:` argument, or that has diverged\n * from the vended shape, is left alone and reported via `nextSteps`.\n * - Idempotent: an aliased declaration no longer matches the bare pattern.\n */\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [, project] of getProjects(tree)) {\n if (\n ((project.metadata as any) ?? {}).generator !==\n SMITHY_PROJECT_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n const extensionsPath = joinPathFragments(\n project.sourceRoot ?? joinPathFragments(project.root, 'src'),\n 'extensions.smithy',\n );\n if (!tree.exists(extensionsPath)) {\n continue;\n }\n\n const before = tree.read(extensionsPath, 'utf-8') ?? '';\n let after = before;\n const skipped: string[] = [];\n\n for (const trait of TRAITS) {\n if (after.includes(`@specificationExtension(as: \"x-${trait}\")`)) {\n // Already aliased.\n continue;\n }\n const bare = bareDeclaration(trait);\n if (!bare.test(after)) {\n skipped.push(trait);\n continue;\n }\n after = after.replace(bare, `$1(as: \"x-${trait}\")$2`);\n }\n\n if (after !== before) {\n tree.write(extensionsPath, after);\n }\n\n if (skipped.length > 0) {\n nextSteps.push(\n `${extensionsPath}: add ${skipped\n .map((trait) => `\\`(as: \"x-${trait}\")\\``)\n .join(\n ', ',\n )} to the \\`@specificationExtension\\` trait on ${skipped.map((trait) => `\\`${trait}\\``).join(', ')}, so Smithy emits the ${skipped.map((trait) => `\\`x-${trait}\\``).join(', ')} OpenAPI ${skipped.length === 1 ? 'key' : 'keys'} the client generator reads.`,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","SMITHY_PROJECT_GENERATOR_INFO","formatFilesInSubtree","TRAITS","bareDeclaration","trait","RegExp","migration","tree","nextSteps","project","metadata","generator","id","extensionsPath","sourceRoot","root","exists","before","read","after","skipped","includes","bare","test","push","replace","write","length","map","join"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,6BAA6B,QAAQ,uCAAuC;AACrF,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE,iFAAiF,GACjF,MAAMC,SAAS;IAAC;IAAS;IAAY;CAAS;AAE9C;;;;CAIC,GACD,MAAMC,kBAAkB,CAACC,QACvB,IAAIC,OACF,CAAC,mEAAmE,EAAED,MAAM,QAAQ,CAAC;AAGzF;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,eAAe,eAAeE,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,GAAGC,QAAQ,IAAIX,YAAYS,MAAO;QAC3C,IACE,AAAC,CAAA,AAACE,QAAQC,QAAQ,IAAY,CAAC,CAAA,EAAGC,SAAS,KAC3CX,8BAA8BY,EAAE,EAChC;YACA;QACF;QAEA,MAAMC,iBAAiBd,kBACrBU,QAAQK,UAAU,IAAIf,kBAAkBU,QAAQM,IAAI,EAAE,QACtD;QAEF,IAAI,CAACR,KAAKS,MAAM,CAACH,iBAAiB;YAChC;QACF;QAEA,MAAMI,SAASV,KAAKW,IAAI,CAACL,gBAAgB,YAAY;QACrD,IAAIM,QAAQF;QACZ,MAAMG,UAAoB,EAAE;QAE5B,KAAK,MAAMhB,SAASF,OAAQ;YAC1B,IAAIiB,MAAME,QAAQ,CAAC,CAAC,+BAA+B,EAAEjB,MAAM,EAAE,CAAC,GAAG;gBAE/D;YACF;YACA,MAAMkB,OAAOnB,gBAAgBC;YAC7B,IAAI,CAACkB,KAAKC,IAAI,CAACJ,QAAQ;gBACrBC,QAAQI,IAAI,CAACpB;gBACb;YACF;YACAe,QAAQA,MAAMM,OAAO,CAACH,MAAM,CAAC,UAAU,EAAElB,MAAM,IAAI,CAAC;QACtD;QAEA,IAAIe,UAAUF,QAAQ;YACpBV,KAAKmB,KAAK,CAACb,gBAAgBM;QAC7B;QAEA,IAAIC,QAAQO,MAAM,GAAG,GAAG;YACtBnB,UAAUgB,IAAI,CACZ,GAAGX,eAAe,MAAM,EAAEO,QACvBQ,GAAG,CAAC,CAACxB,QAAU,CAAC,UAAU,EAAEA,MAAM,IAAI,CAAC,EACvCyB,IAAI,CACH,MACA,6CAA6C,EAAET,QAAQQ,GAAG,CAAC,CAACxB,QAAU,CAAC,EAAE,EAAEA,MAAM,EAAE,CAAC,EAAEyB,IAAI,CAAC,MAAM,sBAAsB,EAAET,QAAQQ,GAAG,CAAC,CAACxB,QAAU,CAAC,IAAI,EAAEA,MAAM,EAAE,CAAC,EAAEyB,IAAI,CAAC,MAAM,SAAS,EAAET,QAAQO,MAAM,KAAK,IAAI,QAAQ,OAAO,4BAA4B,CAAC;QAEnQ;IACF;IAEA,MAAM1B,qBAAqBM;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|