diff --git a/lerna.json b/lerna.json index 51e83fcdb1c13..a9fb8c56b7866 100644 --- a/lerna.json +++ b/lerna.json @@ -20,6 +20,7 @@ "tools/@aws-cdk/prlint", "tools/@aws-cdk/spec2cdk", "tools/@aws-cdk/yarn-cling", + "tools/@aws-cdk/lazify", "scripts/@aws-cdk/script-tests" ], "rejectCycles": true, diff --git a/package.json b/package.json index e0a6bd687bc5f..7bd5bae4ab0d0 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "tools/@aws-cdk/prlint", "tools/@aws-cdk/spec2cdk", "tools/@aws-cdk/yarn-cling", + "tools/@aws-cdk/lazify", "scripts/@aws-cdk/script-tests" ], "nohoist": [ diff --git a/packages/@aws-cdk-testing/cli-integ/tests/init-javascript/init-javascript.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/init-javascript/init-javascript.integtest.ts index 8fc4be4bf64fb..2a4002932e95f 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/init-javascript/init-javascript.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/init-javascript/init-javascript.integtest.ts @@ -1,3 +1,5 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; import { integTest, withTemporaryDirectory, ShellHelper, withPackages } from '../../lib'; ['app', 'sample-app'].forEach(template => { @@ -13,3 +15,43 @@ import { integTest, withTemporaryDirectory, ShellHelper, withPackages } from '.. await shell.shell(['cdk', 'synth']); }))); }); + +integTest('Test importing CDK from ESM', withTemporaryDirectory(withPackages(async (context) => { + // Use 'cdk init -l=javascript' to get set up, but use a different file + const shell = ShellHelper.fromContext(context); + await context.packages.makeCliAvailable(); + + await shell.shell(['cdk', 'init', '-l', 'javascript', 'app']); + + // Rewrite some files + await fs.writeFile(path.join(context.integTestDir, 'new-entrypoint.mjs'), ` +// Test two styles of imports +import { Stack, aws_sns as sns, aws_sns_subscriptions as subs, aws_sqs as sqs } from 'aws-cdk-lib'; +import * as cdk from 'aws-cdk-lib'; + +class TestjsStack extends Stack { + constructor(scope, id, props) { + super(scope, id, props); + + const queue = new sqs.Queue(this, 'TestjsQueue', { + visibilityTimeout: cdk.Duration.seconds(300) + }); + + const topic = new sns.Topic(this, 'TestjsTopic'); + + topic.addSubscription(new subs.SqsSubscription(queue)); + } +} + +const app = new cdk.App(); +new TestjsStack(app, 'TestjsStack'); +`, { encoding: 'utf-8' }); + + // Rewrite 'cdk.json' to use new entrypoint + const cdkJson = await fs.readJson(path.join(context.integTestDir, 'cdk.json')); + cdkJson.app = 'node new-entrypoing.mjs'; + await fs.writeJson(path.join(context.integTestDir, 'cdk.json'), cdkJson); + + await shell.shell(['cdk', 'synth']); + +}))); diff --git a/packages/@aws-cdk/aws-scheduler-alpha/README.md b/packages/@aws-cdk/aws-scheduler-alpha/README.md index 5f5ef0d41a997..da1e1c182d4e2 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/README.md +++ b/packages/@aws-cdk/aws-scheduler-alpha/README.md @@ -60,11 +60,6 @@ You can choose from three schedule types when configuring your schedule: rate-ba Both rate-based and cron-based schedules are recurring schedules. You can configure each recurring schedule type using a schedule expression. For cron-based schedule you can specify a time zone in which EventBridge Scheduler evaluates the expression. - -> ScheduleExpression should be used together with class Schedule, which is not yet implemented. - -[comment]: <> (TODO: Switch to `ts` once Schedule is implemented) - ```ts declare const target: targets.LambdaInvoke; @@ -129,6 +124,21 @@ new Schedule(this, 'Schedule', { }); ``` +### Disabling Schedules + +By default, a schedule will be enabled. You can disable a schedule by setting the `enabled` property to false: + +```ts +declare const target: targets.LambdaInvoke; + +new Schedule(this, 'Schedule', { + schedule: ScheduleExpression.rate(Duration.minutes(10)), + target: target, + enabled: false, +}); +``` + + ## Scheduler Targets The `@aws-cdk/aws-schedule-targets-alpha` module includes classes that implement the `IScheduleTarget` interface for diff --git a/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule.ts b/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule.ts index e349ebb31e2ac..32611f99ad64e 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule.ts +++ b/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule.ts @@ -57,9 +57,15 @@ export interface ScheduleProps { /** * The schedule's group. * - * @deafult - By default a schedule will be associated with the `default` group. + * @default - By default a schedule will be associated with the `default` group. */ readonly group?: IGroup; + + /** + * Indicates whether the schedule is enabled. + * @default true + */ + readonly enabled?: boolean; } /** @@ -95,6 +101,7 @@ export class Schedule extends Resource implements ISchedule { scheduleExpression: props.schedule.expressionString, scheduleExpressionTimezone: props.schedule.timeZone?.timezoneName, groupName: this.group?.groupName, + state: (props.enabled ?? true) ? 'ENABLED' : 'DISABLED', target: { arn: targetConfig.arn, roleArn: targetConfig.role.roleArn, diff --git a/packages/@aws-cdk/aws-scheduler-alpha/package.json b/packages/@aws-cdk/aws-scheduler-alpha/package.json index 8a720a217fbb0..560b37dc31b3b 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/package.json +++ b/packages/@aws-cdk/aws-scheduler-alpha/package.json @@ -86,7 +86,8 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^29.5.5", "aws-cdk-lib": "0.0.0", - "constructs": "^10.0.0" + "constructs": "^10.0.0", + "@aws-cdk/integ-tests-alpha": "0.0.0" }, "dependencies": {}, "peerDependencies": { diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.assets.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.assets.json new file mode 100644 index 0000000000000..78b01562c3813 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.assets.json @@ -0,0 +1,19 @@ +{ + "version": "34.0.0", + "files": { + "bbcd00ec8f22ebae1e8018bdae1226dbbdf643fd8c5453daf208abedd325db6c": { + "source": { + "path": "aws-cdk-scheduler-schedule.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "bbcd00ec8f22ebae1e8018bdae1226dbbdf643fd8c5453daf208abedd325db6c.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.template.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.template.json new file mode 100644 index 0000000000000..2042d17cbd10b --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.template.json @@ -0,0 +1,153 @@ +{ + "Resources": { + "FunctionServiceRole675BB04A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "Function76856677": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionServiceRole675BB04A", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "FunctionServiceRole675BB04A" + ] + }, + "Role1ABCC5F0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "scheduler.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "DefaultSchedule597B0B2C": { + "Type": "AWS::Scheduler::Schedule", + "Properties": { + "FlexibleTimeWindow": { + "Mode": "OFF" + }, + "ScheduleExpression": "rate(12 hours)", + "State": "ENABLED", + "Target": { + "Arn": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + }, + "DisabledScheduleA1DF7F0F": { + "Type": "AWS::Scheduler::Schedule", + "Properties": { + "FlexibleTimeWindow": { + "Mode": "OFF" + }, + "ScheduleExpression": "rate(12 hours)", + "State": "DISABLED", + "Target": { + "Arn": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/cdk.out b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/cdk.out new file mode 100644 index 0000000000000..2313ab5436501 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"34.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integ.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integ.json new file mode 100644 index 0000000000000..c1aec1a40f53f --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "34.0.0", + "testCases": { + "integtest-schedule/DefaultTest": { + "stacks": [ + "aws-cdk-scheduler-schedule" + ], + "assertionStack": "integtest-schedule/DefaultTest/DeployAssert", + "assertionStackName": "integtestscheduleDefaultTestDeployAssert24CB3896" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.assets.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.assets.json new file mode 100644 index 0000000000000..8f8a003c1b5ba --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.assets.json @@ -0,0 +1,19 @@ +{ + "version": "34.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integtestscheduleDefaultTestDeployAssert24CB3896.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.template.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/manifest.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/manifest.json new file mode 100644 index 0000000000000..2dc25c77fa582 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/manifest.json @@ -0,0 +1,137 @@ +{ + "version": "34.0.0", + "artifacts": { + "aws-cdk-scheduler-schedule.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-scheduler-schedule.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-scheduler-schedule": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-scheduler-schedule.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/bbcd00ec8f22ebae1e8018bdae1226dbbdf643fd8c5453daf208abedd325db6c.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-scheduler-schedule.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-scheduler-schedule.assets" + ], + "metadata": { + "/aws-cdk-scheduler-schedule/Function/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionServiceRole675BB04A" + } + ], + "/aws-cdk-scheduler-schedule/Function/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Function76856677" + } + ], + "/aws-cdk-scheduler-schedule/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Role1ABCC5F0" + } + ], + "/aws-cdk-scheduler-schedule/DefaultSchedule/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultSchedule597B0B2C" + } + ], + "/aws-cdk-scheduler-schedule/DisabledSchedule/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DisabledScheduleA1DF7F0F" + } + ], + "/aws-cdk-scheduler-schedule/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-scheduler-schedule/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-scheduler-schedule" + }, + "integtestscheduleDefaultTestDeployAssert24CB3896.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtestscheduleDefaultTestDeployAssert24CB3896.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtestscheduleDefaultTestDeployAssert24CB3896": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtestscheduleDefaultTestDeployAssert24CB3896.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtestscheduleDefaultTestDeployAssert24CB3896.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integtestscheduleDefaultTestDeployAssert24CB3896.assets" + ], + "metadata": { + "/integtest-schedule/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integtest-schedule/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integtest-schedule/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/tree.json b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/tree.json new file mode 100644 index 0000000000000..ede00d1d0df84 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/tree.json @@ -0,0 +1,319 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-scheduler-schedule": { + "id": "aws-cdk-scheduler-schedule", + "path": "aws-cdk-scheduler-schedule", + "children": { + "Function": { + "id": "Function", + "path": "aws-cdk-scheduler-schedule/Function", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-scheduler-schedule/Function/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-scheduler-schedule/Function/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-scheduler-schedule/Function/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-scheduler-schedule/Function/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "handler": "index.handler", + "role": { + "Fn::GetAtt": [ + "FunctionServiceRole675BB04A", + "Arn" + ] + }, + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "aws-cdk-scheduler-schedule/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "aws-cdk-scheduler-schedule/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-scheduler-schedule/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "scheduler.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "DefaultSchedule": { + "id": "DefaultSchedule", + "path": "aws-cdk-scheduler-schedule/DefaultSchedule", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-scheduler-schedule/DefaultSchedule/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Scheduler::Schedule", + "aws:cdk:cloudformation:props": { + "flexibleTimeWindow": { + "mode": "OFF" + }, + "scheduleExpression": "rate(12 hours)", + "state": "ENABLED", + "target": { + "arn": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_scheduler.CfnSchedule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-scheduler-alpha.Schedule", + "version": "0.0.0" + } + }, + "DisabledSchedule": { + "id": "DisabledSchedule", + "path": "aws-cdk-scheduler-schedule/DisabledSchedule", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-scheduler-schedule/DisabledSchedule/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Scheduler::Schedule", + "aws:cdk:cloudformation:props": { + "flexibleTimeWindow": { + "mode": "OFF" + }, + "scheduleExpression": "rate(12 hours)", + "state": "DISABLED", + "target": { + "arn": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_scheduler.CfnSchedule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-scheduler-alpha.Schedule", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-scheduler-schedule/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-scheduler-schedule/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "integtest-schedule": { + "id": "integtest-schedule", + "path": "integtest-schedule", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integtest-schedule/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integtest-schedule/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integtest-schedule/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integtest-schedule/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integtest-schedule/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.ts new file mode 100644 index 0000000000000..a1907102a0ebf --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.ts @@ -0,0 +1,47 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as cdk from 'aws-cdk-lib'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as scheduler from '../lib'; + +class SomeLambdaTarget implements scheduler.IScheduleTarget { + public constructor(private readonly fn: lambda.IFunction, private readonly role: iam.IRole) { + } + + public bind(): scheduler.ScheduleTargetConfig { + return { + arn: this.fn.functionArn, + role: this.role, + }; + } +} + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-scheduler-schedule'); + +const expression = scheduler.ScheduleExpression.rate(cdk.Duration.hours(12)); +const func = new lambda.Function(stack, 'Function', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, +}); +const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'), +}); + +const target = new SomeLambdaTarget(func, role); + +new scheduler.Schedule(stack, 'DefaultSchedule', { + schedule: expression, + target: target, +}); + +new scheduler.Schedule(stack, 'DisabledSchedule', { + schedule: expression, + target: target, + enabled: false, +}); + +new IntegTest(app, 'integtest-schedule', { + testCases: [stack], +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts new file mode 100644 index 0000000000000..a4db92018322d --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts @@ -0,0 +1,65 @@ +import { App, Stack } from 'aws-cdk-lib'; + +import { Template } from 'aws-cdk-lib/assertions'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { IScheduleTarget, Schedule, ScheduleTargetConfig } from '../lib'; +import { ScheduleExpression } from '../lib/schedule-expression'; + +class SomeLambdaTarget implements IScheduleTarget { + public constructor(private readonly fn: lambda.IFunction, private readonly role: iam.IRole) { + } + + public bind(): ScheduleTargetConfig { + return { + arn: this.fn.functionArn, + role: this.role, + }; + } +} + +describe('Schedule', () => { + let stack: Stack; + let func: lambda.IFunction; + let role: iam.IRole; + const expr = ScheduleExpression.at(new Date(Date.UTC(1969, 10, 20, 0, 0, 0))); + + beforeEach(() => { + const app = new App(); + stack = new Stack(app, 'Stack', { env: { region: 'us-east-1', account: '123456789012' } }); + func = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_LATEST, + tracing: lambda.Tracing.PASS_THROUGH, + }); + role = iam.Role.fromRoleArn(stack, 'ImportedRole', 'arn:aws:iam::123456789012:role/someRole'); + }); + + test('schedule is enabled by default', () => { + // WHEN + new Schedule(stack, 'TestSchedule', { + schedule: expr, + target: new SomeLambdaTarget(func, role), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Scheduler::Schedule', { + State: 'ENABLED', + }); + }); + + test('schedule can be disabled', () => { + // WHEN + new Schedule(stack, 'TestSchedule', { + schedule: expr, + target: new SomeLambdaTarget(func, role), + enabled: false, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Scheduler::Schedule', { + State: 'DISABLED', + }); + }); +}); \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-ec2/lib/restrict-default-security-group-handler/.is_custom_resource b/packages/aws-cdk-lib/aws-ec2/lib/restrict-default-security-group-handler/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-iam/lib/oidc-provider/.is_custom_resource b/packages/aws-cdk-lib/aws-iam/lib/oidc-provider/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-lambda/test/code.test.ts b/packages/aws-cdk-lib/aws-lambda/test/code.test.ts index a7e3e328a1c91..4cb41a1078555 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/code.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/code.test.ts @@ -440,7 +440,7 @@ describe('code', () => { // then Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Metadata: { - [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.7bbf7edf9881819a1b91e5b02acae3e3973f96fa93325c676a1285351ddacc62', + [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: Match.stringLikeRegexp('asset\\.[0-9a-f]+'), [cxapi.ASSET_RESOURCE_METADATA_IS_BUNDLED_KEY]: false, [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code', }, diff --git a/packages/aws-cdk-lib/aws-lambda/test/docker-build-lambda/.is_custom_resource b/packages/aws-cdk-lib/aws-lambda/test/docker-build-lambda/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-logs/lib/log-retention-provider/.is_custom_resource b/packages/aws-cdk-lib/aws-logs/lib/log-retention-provider/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/.is_custom_resource b/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-route53/lib/delete-existing-record-set-handler/.is_custom_resource b/packages/aws-cdk-lib/aws-route53/lib/delete-existing-record-set-handler/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-ses/lib/drop-spam-handler/.is_custom_resource b/packages/aws-cdk-lib/aws-ses/lib/drop-spam-handler/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/eval-nodejs-handler/.is_custom_resource b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/eval-nodejs-handler/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/core/lib/asset-staging.ts b/packages/aws-cdk-lib/core/lib/asset-staging.ts index b4f889517fb73..438c9e9749051 100644 --- a/packages/aws-cdk-lib/core/lib/asset-staging.ts +++ b/packages/aws-cdk-lib/core/lib/asset-staging.ts @@ -167,6 +167,7 @@ export class AssetStaging extends Construct { this.sourcePath = path.resolve(props.sourcePath); this.fingerprintOptions = { ...props, + exclude: ['.is_custom_resource', ...props.exclude ?? []], extraHash: props.extraHash || salt ? `${props.extraHash ?? ''}${salt ?? ''}` : undefined, }; diff --git a/packages/aws-cdk-lib/core/lib/custom-resource-provider/.is_custom_resource b/packages/aws-cdk-lib/core/lib/custom-resource-provider/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/core/lib/private/cfn-utils-provider/.is_custom_resource b/packages/aws-cdk-lib/core/lib/private/cfn-utils-provider/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/lazy-index.ts b/packages/aws-cdk-lib/lazy-index.ts deleted file mode 100644 index 28b4358e31449..0000000000000 --- a/packages/aws-cdk-lib/lazy-index.ts +++ /dev/null @@ -1,263 +0,0 @@ -/* eslint-disable @typescript-eslint/no-require-imports */ -export * from './core'; -Object.defineProperty(exports, 'alexa_ask', { get: function () { return require('./alexa-ask'); } }); -Object.defineProperty(exports, 'assertions', { get: function () { return require('./assertions'); } }); -Object.defineProperty(exports, 'assets', { get: function () { return require('./assets'); } }); -Object.defineProperty(exports, 'aws_accessanalyzer', { get: function () { return require('./aws-accessanalyzer'); } }); -Object.defineProperty(exports, 'aws_acmpca', { get: function () { return require('./aws-acmpca'); } }); -Object.defineProperty(exports, 'aws_amazonmq', { get: function () { return require('./aws-amazonmq'); } }); -Object.defineProperty(exports, 'aws_amplify', { get: function () { return require('./aws-amplify'); } }); -Object.defineProperty(exports, 'aws_amplifyuibuilder', { get: function () { return require('./aws-amplifyuibuilder'); } }); -Object.defineProperty(exports, 'aws_apigateway', { get: function () { return require('./aws-apigateway'); } }); -Object.defineProperty(exports, 'aws_apigatewayv2', { get: function () { return require('./aws-apigatewayv2'); } }); -Object.defineProperty(exports, 'aws_appconfig', { get: function () { return require('./aws-appconfig'); } }); -Object.defineProperty(exports, 'aws_appflow', { get: function () { return require('./aws-appflow'); } }); -Object.defineProperty(exports, 'aws_appintegrations', { get: function () { return require('./aws-appintegrations'); } }); -Object.defineProperty(exports, 'aws_applicationautoscaling', { get: function () { return require('./aws-applicationautoscaling'); } }); -Object.defineProperty(exports, 'aws_applicationinsights', { get: function () { return require('./aws-applicationinsights'); } }); -Object.defineProperty(exports, 'aws_appmesh', { get: function () { return require('./aws-appmesh'); } }); -Object.defineProperty(exports, 'aws_apprunner', { get: function () { return require('./aws-apprunner'); } }); -Object.defineProperty(exports, 'aws_appstream', { get: function () { return require('./aws-appstream'); } }); -Object.defineProperty(exports, 'aws_appsync', { get: function () { return require('./aws-appsync'); } }); -Object.defineProperty(exports, 'aws_aps', { get: function () { return require('./aws-aps'); } }); -Object.defineProperty(exports, 'aws_athena', { get: function () { return require('./aws-athena'); } }); -Object.defineProperty(exports, 'aws_auditmanager', { get: function () { return require('./aws-auditmanager'); } }); -Object.defineProperty(exports, 'aws_autoscaling_common', { get: function () { return require('./aws-autoscaling-common'); } }); -Object.defineProperty(exports, 'aws_autoscaling_hooktargets', { get: function () { return require('./aws-autoscaling-hooktargets'); } }); -Object.defineProperty(exports, 'aws_autoscaling', { get: function () { return require('./aws-autoscaling'); } }); -Object.defineProperty(exports, 'aws_autoscalingplans', { get: function () { return require('./aws-autoscalingplans'); } }); -Object.defineProperty(exports, 'aws_backup', { get: function () { return require('./aws-backup'); } }); -Object.defineProperty(exports, 'aws_backupgateway', { get: function () { return require('./aws-backupgateway'); } }); -Object.defineProperty(exports, 'aws_batch', { get: function () { return require('./aws-batch'); } }); -Object.defineProperty(exports, 'aws_billingconductor', { get: function () { return require('./aws-billingconductor'); } }); -Object.defineProperty(exports, 'aws_budgets', { get: function () { return require('./aws-budgets'); } }); -Object.defineProperty(exports, 'aws_cassandra', { get: function () { return require('./aws-cassandra'); } }); -Object.defineProperty(exports, 'aws_ce', { get: function () { return require('./aws-ce'); } }); -Object.defineProperty(exports, 'aws_certificatemanager', { get: function () { return require('./aws-certificatemanager'); } }); -Object.defineProperty(exports, 'aws_chatbot', { get: function () { return require('./aws-chatbot'); } }); -Object.defineProperty(exports, 'aws_cleanrooms', { get: function () { return require('./aws-cleanrooms'); } }); -Object.defineProperty(exports, 'aws_cloud9', { get: function () { return require('./aws-cloud9'); } }); -Object.defineProperty(exports, 'aws_cloudformation', { get: function () { return require('./aws-cloudformation'); } }); -Object.defineProperty(exports, 'aws_cloudfront_origins', { get: function () { return require('./aws-cloudfront-origins'); } }); -Object.defineProperty(exports, 'aws_cloudfront', { get: function () { return require('./aws-cloudfront'); } }); -Object.defineProperty(exports, 'aws_cloudtrail', { get: function () { return require('./aws-cloudtrail'); } }); -Object.defineProperty(exports, 'aws_cloudwatch_actions', { get: function () { return require('./aws-cloudwatch-actions'); } }); -Object.defineProperty(exports, 'aws_cloudwatch', { get: function () { return require('./aws-cloudwatch'); } }); -Object.defineProperty(exports, 'aws_codeartifact', { get: function () { return require('./aws-codeartifact'); } }); -Object.defineProperty(exports, 'aws_codebuild', { get: function () { return require('./aws-codebuild'); } }); -Object.defineProperty(exports, 'aws_codecommit', { get: function () { return require('./aws-codecommit'); } }); -Object.defineProperty(exports, 'aws_codedeploy', { get: function () { return require('./aws-codedeploy'); } }); -Object.defineProperty(exports, 'aws_codeguruprofiler', { get: function () { return require('./aws-codeguruprofiler'); } }); -Object.defineProperty(exports, 'aws_codegurureviewer', { get: function () { return require('./aws-codegurureviewer'); } }); -Object.defineProperty(exports, 'aws_codepipeline_actions', { get: function () { return require('./aws-codepipeline-actions'); } }); -Object.defineProperty(exports, 'aws_codepipeline', { get: function () { return require('./aws-codepipeline'); } }); -Object.defineProperty(exports, 'aws_codestar', { get: function () { return require('./aws-codestar'); } }); -Object.defineProperty(exports, 'aws_codestarconnections', { get: function () { return require('./aws-codestarconnections'); } }); -Object.defineProperty(exports, 'aws_codestarnotifications', { get: function () { return require('./aws-codestarnotifications'); } }); -Object.defineProperty(exports, 'aws_cognito', { get: function () { return require('./aws-cognito'); } }); -Object.defineProperty(exports, 'aws_comprehend', { get: function () { return require('./aws-comprehend'); } }); -Object.defineProperty(exports, 'aws_config', { get: function () { return require('./aws-config'); } }); -Object.defineProperty(exports, 'aws_connect', { get: function () { return require('./aws-connect'); } }); -Object.defineProperty(exports, 'aws_connectcampaigns', { get: function () { return require('./aws-connectcampaigns'); } }); -Object.defineProperty(exports, 'aws_controltower', { get: function () { return require('./aws-controltower'); } }); -Object.defineProperty(exports, 'aws_cur', { get: function () { return require('./aws-cur'); } }); -Object.defineProperty(exports, 'aws_customerprofiles', { get: function () { return require('./aws-customerprofiles'); } }); -Object.defineProperty(exports, 'aws_databrew', { get: function () { return require('./aws-databrew'); } }); -Object.defineProperty(exports, 'aws_datapipeline', { get: function () { return require('./aws-datapipeline'); } }); -Object.defineProperty(exports, 'aws_datasync', { get: function () { return require('./aws-datasync'); } }); -Object.defineProperty(exports, 'aws_dax', { get: function () { return require('./aws-dax'); } }); -Object.defineProperty(exports, 'aws_detective', { get: function () { return require('./aws-detective'); } }); -Object.defineProperty(exports, 'aws_devicefarm', { get: function () { return require('./aws-devicefarm'); } }); -Object.defineProperty(exports, 'aws_devopsguru', { get: function () { return require('./aws-devopsguru'); } }); -Object.defineProperty(exports, 'aws_directoryservice', { get: function () { return require('./aws-directoryservice'); } }); -Object.defineProperty(exports, 'aws_dlm', { get: function () { return require('./aws-dlm'); } }); -Object.defineProperty(exports, 'aws_dms', { get: function () { return require('./aws-dms'); } }); -Object.defineProperty(exports, 'aws_docdb', { get: function () { return require('./aws-docdb'); } }); -Object.defineProperty(exports, 'aws_docdbelastic', { get: function () { return require('./aws-docdbelastic'); } }); -Object.defineProperty(exports, 'aws_dynamodb', { get: function () { return require('./aws-dynamodb'); } }); -Object.defineProperty(exports, 'aws_ec2', { get: function () { return require('./aws-ec2'); } }); -Object.defineProperty(exports, 'aws_ecr_assets', { get: function () { return require('./aws-ecr-assets'); } }); -Object.defineProperty(exports, 'aws_ecr', { get: function () { return require('./aws-ecr'); } }); -Object.defineProperty(exports, 'aws_ecs_patterns', { get: function () { return require('./aws-ecs-patterns'); } }); -Object.defineProperty(exports, 'aws_ecs', { get: function () { return require('./aws-ecs'); } }); -Object.defineProperty(exports, 'aws_efs', { get: function () { return require('./aws-efs'); } }); -Object.defineProperty(exports, 'aws_eks', { get: function () { return require('./aws-eks'); } }); -Object.defineProperty(exports, 'aws_elasticache', { get: function () { return require('./aws-elasticache'); } }); -Object.defineProperty(exports, 'aws_elasticbeanstalk', { get: function () { return require('./aws-elasticbeanstalk'); } }); -Object.defineProperty(exports, 'aws_elasticloadbalancing', { get: function () { return require('./aws-elasticloadbalancing'); } }); -Object.defineProperty(exports, 'aws_elasticloadbalancingv2_actions', { get: function () { return require('./aws-elasticloadbalancingv2-actions'); } }); -Object.defineProperty(exports, 'aws_elasticloadbalancingv2_targets', { get: function () { return require('./aws-elasticloadbalancingv2-targets'); } }); -Object.defineProperty(exports, 'aws_elasticloadbalancingv2', { get: function () { return require('./aws-elasticloadbalancingv2'); } }); -Object.defineProperty(exports, 'aws_elasticsearch', { get: function () { return require('./aws-elasticsearch'); } }); -Object.defineProperty(exports, 'aws_emr', { get: function () { return require('./aws-emr'); } }); -Object.defineProperty(exports, 'aws_emrcontainers', { get: function () { return require('./aws-emrcontainers'); } }); -Object.defineProperty(exports, 'aws_emrserverless', { get: function () { return require('./aws-emrserverless'); } }); -Object.defineProperty(exports, 'aws_entityresolution', { get: function () { return require('./aws-entityresolution'); } }); -Object.defineProperty(exports, 'aws_events_targets', { get: function () { return require('./aws-events-targets'); } }); -Object.defineProperty(exports, 'aws_events', { get: function () { return require('./aws-events'); } }); -Object.defineProperty(exports, 'aws_eventschemas', { get: function () { return require('./aws-eventschemas'); } }); -Object.defineProperty(exports, 'aws_evidently', { get: function () { return require('./aws-evidently'); } }); -Object.defineProperty(exports, 'aws_finspace', { get: function () { return require('./aws-finspace'); } }); -Object.defineProperty(exports, 'aws_fis', { get: function () { return require('./aws-fis'); } }); -Object.defineProperty(exports, 'aws_fms', { get: function () { return require('./aws-fms'); } }); -Object.defineProperty(exports, 'aws_forecast', { get: function () { return require('./aws-forecast'); } }); -Object.defineProperty(exports, 'aws_frauddetector', { get: function () { return require('./aws-frauddetector'); } }); -Object.defineProperty(exports, 'aws_fsx', { get: function () { return require('./aws-fsx'); } }); -Object.defineProperty(exports, 'aws_gamelift', { get: function () { return require('./aws-gamelift'); } }); -Object.defineProperty(exports, 'aws_globalaccelerator_endpoints', { get: function () { return require('./aws-globalaccelerator-endpoints'); } }); -Object.defineProperty(exports, 'aws_globalaccelerator', { get: function () { return require('./aws-globalaccelerator'); } }); -Object.defineProperty(exports, 'aws_glue', { get: function () { return require('./aws-glue'); } }); -Object.defineProperty(exports, 'aws_grafana', { get: function () { return require('./aws-grafana'); } }); -Object.defineProperty(exports, 'aws_greengrass', { get: function () { return require('./aws-greengrass'); } }); -Object.defineProperty(exports, 'aws_greengrassv2', { get: function () { return require('./aws-greengrassv2'); } }); -Object.defineProperty(exports, 'aws_groundstation', { get: function () { return require('./aws-groundstation'); } }); -Object.defineProperty(exports, 'aws_guardduty', { get: function () { return require('./aws-guardduty'); } }); -Object.defineProperty(exports, 'aws_healthlake', { get: function () { return require('./aws-healthlake'); } }); -Object.defineProperty(exports, 'aws_iam', { get: function () { return require('./aws-iam'); } }); -Object.defineProperty(exports, 'aws_identitystore', { get: function () { return require('./aws-identitystore'); } }); -Object.defineProperty(exports, 'aws_imagebuilder', { get: function () { return require('./aws-imagebuilder'); } }); -Object.defineProperty(exports, 'aws_inspector', { get: function () { return require('./aws-inspector'); } }); -Object.defineProperty(exports, 'aws_inspectorv2', { get: function () { return require('./aws-inspectorv2'); } }); -Object.defineProperty(exports, 'aws_internetmonitor', { get: function () { return require('./aws-internetmonitor'); } }); -Object.defineProperty(exports, 'aws_iot', { get: function () { return require('./aws-iot'); } }); -Object.defineProperty(exports, 'aws_iot1click', { get: function () { return require('./aws-iot1click'); } }); -Object.defineProperty(exports, 'aws_iotanalytics', { get: function () { return require('./aws-iotanalytics'); } }); -Object.defineProperty(exports, 'aws_iotcoredeviceadvisor', { get: function () { return require('./aws-iotcoredeviceadvisor'); } }); -Object.defineProperty(exports, 'aws_iotevents', { get: function () { return require('./aws-iotevents'); } }); -Object.defineProperty(exports, 'aws_iotfleethub', { get: function () { return require('./aws-iotfleethub'); } }); -Object.defineProperty(exports, 'aws_iotfleetwise', { get: function () { return require('./aws-iotfleetwise'); } }); -Object.defineProperty(exports, 'aws_iotsitewise', { get: function () { return require('./aws-iotsitewise'); } }); -Object.defineProperty(exports, 'aws_iotthingsgraph', { get: function () { return require('./aws-iotthingsgraph'); } }); -Object.defineProperty(exports, 'aws_iottwinmaker', { get: function () { return require('./aws-iottwinmaker'); } }); -Object.defineProperty(exports, 'aws_iotwireless', { get: function () { return require('./aws-iotwireless'); } }); -Object.defineProperty(exports, 'aws_ivs', { get: function () { return require('./aws-ivs'); } }); -Object.defineProperty(exports, 'aws_ivschat', { get: function () { return require('./aws-ivschat'); } }); -Object.defineProperty(exports, 'aws_kafkaconnect', { get: function () { return require('./aws-kafkaconnect'); } }); -Object.defineProperty(exports, 'aws_kendra', { get: function () { return require('./aws-kendra'); } }); -Object.defineProperty(exports, 'aws_kendraranking', { get: function () { return require('./aws-kendraranking'); } }); -Object.defineProperty(exports, 'aws_kinesis', { get: function () { return require('./aws-kinesis'); } }); -Object.defineProperty(exports, 'aws_kinesisanalytics', { get: function () { return require('./aws-kinesisanalytics'); } }); -Object.defineProperty(exports, 'aws_kinesisanalyticsv2', { get: function () { return require('./aws-kinesisanalyticsv2'); } }); -Object.defineProperty(exports, 'aws_kinesisfirehose', { get: function () { return require('./aws-kinesisfirehose'); } }); -Object.defineProperty(exports, 'aws_kinesisvideo', { get: function () { return require('./aws-kinesisvideo'); } }); -Object.defineProperty(exports, 'aws_kms', { get: function () { return require('./aws-kms'); } }); -Object.defineProperty(exports, 'aws_lakeformation', { get: function () { return require('./aws-lakeformation'); } }); -Object.defineProperty(exports, 'aws_lambda_destinations', { get: function () { return require('./aws-lambda-destinations'); } }); -Object.defineProperty(exports, 'aws_lambda_event_sources', { get: function () { return require('./aws-lambda-event-sources'); } }); -Object.defineProperty(exports, 'aws_lambda_nodejs', { get: function () { return require('./aws-lambda-nodejs'); } }); -Object.defineProperty(exports, 'aws_lambda', { get: function () { return require('./aws-lambda'); } }); -Object.defineProperty(exports, 'aws_lex', { get: function () { return require('./aws-lex'); } }); -Object.defineProperty(exports, 'aws_licensemanager', { get: function () { return require('./aws-licensemanager'); } }); -Object.defineProperty(exports, 'aws_lightsail', { get: function () { return require('./aws-lightsail'); } }); -Object.defineProperty(exports, 'aws_location', { get: function () { return require('./aws-location'); } }); -Object.defineProperty(exports, 'aws_logs_destinations', { get: function () { return require('./aws-logs-destinations'); } }); -Object.defineProperty(exports, 'aws_logs', { get: function () { return require('./aws-logs'); } }); -Object.defineProperty(exports, 'aws_lookoutequipment', { get: function () { return require('./aws-lookoutequipment'); } }); -Object.defineProperty(exports, 'aws_lookoutmetrics', { get: function () { return require('./aws-lookoutmetrics'); } }); -Object.defineProperty(exports, 'aws_lookoutvision', { get: function () { return require('./aws-lookoutvision'); } }); -Object.defineProperty(exports, 'aws_m2', { get: function () { return require('./aws-m2'); } }); -Object.defineProperty(exports, 'aws_macie', { get: function () { return require('./aws-macie'); } }); -Object.defineProperty(exports, 'aws_managedblockchain', { get: function () { return require('./aws-managedblockchain'); } }); -Object.defineProperty(exports, 'aws_mediaconnect', { get: function () { return require('./aws-mediaconnect'); } }); -Object.defineProperty(exports, 'aws_mediaconvert', { get: function () { return require('./aws-mediaconvert'); } }); -Object.defineProperty(exports, 'aws_medialive', { get: function () { return require('./aws-medialive'); } }); -Object.defineProperty(exports, 'aws_mediapackage', { get: function () { return require('./aws-mediapackage'); } }); -Object.defineProperty(exports, 'aws_mediapackagev2', { get: function () { return require('./aws-mediapackagev2'); } }); -Object.defineProperty(exports, 'aws_mediastore', { get: function () { return require('./aws-mediastore'); } }); -Object.defineProperty(exports, 'aws_mediatailor', { get: function () { return require('./aws-mediatailor'); } }); -Object.defineProperty(exports, 'aws_memorydb', { get: function () { return require('./aws-memorydb'); } }); -Object.defineProperty(exports, 'aws_msk', { get: function () { return require('./aws-msk'); } }); -Object.defineProperty(exports, 'aws_mwaa', { get: function () { return require('./aws-mwaa'); } }); -Object.defineProperty(exports, 'aws_neptune', { get: function () { return require('./aws-neptune'); } }); -Object.defineProperty(exports, 'aws_networkfirewall', { get: function () { return require('./aws-networkfirewall'); } }); -Object.defineProperty(exports, 'aws_networkmanager', { get: function () { return require('./aws-networkmanager'); } }); -Object.defineProperty(exports, 'aws_nimblestudio', { get: function () { return require('./aws-nimblestudio'); } }); -Object.defineProperty(exports, 'aws_oam', { get: function () { return require('./aws-oam'); } }); -Object.defineProperty(exports, 'aws_omics', { get: function () { return require('./aws-omics'); } }); -Object.defineProperty(exports, 'aws_opensearchserverless', { get: function () { return require('./aws-opensearchserverless'); } }); -Object.defineProperty(exports, 'aws_opensearchservice', { get: function () { return require('./aws-opensearchservice'); } }); -Object.defineProperty(exports, 'aws_opsworks', { get: function () { return require('./aws-opsworks'); } }); -Object.defineProperty(exports, 'aws_opsworkscm', { get: function () { return require('./aws-opsworkscm'); } }); -Object.defineProperty(exports, 'aws_organizations', { get: function () { return require('./aws-organizations'); } }); -Object.defineProperty(exports, 'aws_osis', { get: function () { return require('./aws-osis'); } }); -Object.defineProperty(exports, 'aws_panorama', { get: function () { return require('./aws-panorama'); } }); -Object.defineProperty(exports, 'aws_pcaconnectorad', { get: function () { return require('./aws-pcaconnectorad'); } }); -Object.defineProperty(exports, 'aws_personalize', { get: function () { return require('./aws-personalize'); } }); -Object.defineProperty(exports, 'aws_pinpoint', { get: function () { return require('./aws-pinpoint'); } }); -Object.defineProperty(exports, 'aws_pinpointemail', { get: function () { return require('./aws-pinpointemail'); } }); -Object.defineProperty(exports, 'aws_pipes', { get: function () { return require('./aws-pipes'); } }); -Object.defineProperty(exports, 'aws_proton', { get: function () { return require('./aws-proton'); } }); -Object.defineProperty(exports, 'aws_qldb', { get: function () { return require('./aws-qldb'); } }); -Object.defineProperty(exports, 'aws_quicksight', { get: function () { return require('./aws-quicksight'); } }); -Object.defineProperty(exports, 'aws_ram', { get: function () { return require('./aws-ram'); } }); -Object.defineProperty(exports, 'aws_rds', { get: function () { return require('./aws-rds'); } }); -Object.defineProperty(exports, 'aws_redshift', { get: function () { return require('./aws-redshift'); } }); -Object.defineProperty(exports, 'aws_redshiftserverless', { get: function () { return require('./aws-redshiftserverless'); } }); -Object.defineProperty(exports, 'aws_refactorspaces', { get: function () { return require('./aws-refactorspaces'); } }); -Object.defineProperty(exports, 'aws_rekognition', { get: function () { return require('./aws-rekognition'); } }); -Object.defineProperty(exports, 'aws_resiliencehub', { get: function () { return require('./aws-resiliencehub'); } }); -Object.defineProperty(exports, 'aws_resourceexplorer2', { get: function () { return require('./aws-resourceexplorer2'); } }); -Object.defineProperty(exports, 'aws_resourcegroups', { get: function () { return require('./aws-resourcegroups'); } }); -Object.defineProperty(exports, 'aws_robomaker', { get: function () { return require('./aws-robomaker'); } }); -Object.defineProperty(exports, 'aws_rolesanywhere', { get: function () { return require('./aws-rolesanywhere'); } }); -Object.defineProperty(exports, 'aws_route53_patterns', { get: function () { return require('./aws-route53-patterns'); } }); -Object.defineProperty(exports, 'aws_route53_targets', { get: function () { return require('./aws-route53-targets'); } }); -Object.defineProperty(exports, 'aws_route53', { get: function () { return require('./aws-route53'); } }); -Object.defineProperty(exports, 'aws_route53recoverycontrol', { get: function () { return require('./aws-route53recoverycontrol'); } }); -Object.defineProperty(exports, 'aws_route53recoveryreadiness', { get: function () { return require('./aws-route53recoveryreadiness'); } }); -Object.defineProperty(exports, 'aws_route53resolver', { get: function () { return require('./aws-route53resolver'); } }); -Object.defineProperty(exports, 'aws_rum', { get: function () { return require('./aws-rum'); } }); -Object.defineProperty(exports, 'aws_s3_assets', { get: function () { return require('./aws-s3-assets'); } }); -Object.defineProperty(exports, 'aws_s3_deployment', { get: function () { return require('./aws-s3-deployment'); } }); -Object.defineProperty(exports, 'aws_s3_notifications', { get: function () { return require('./aws-s3-notifications'); } }); -Object.defineProperty(exports, 'aws_s3', { get: function () { return require('./aws-s3'); } }); -Object.defineProperty(exports, 'aws_s3objectlambda', { get: function () { return require('./aws-s3objectlambda'); } }); -Object.defineProperty(exports, 'aws_s3outposts', { get: function () { return require('./aws-s3outposts'); } }); -Object.defineProperty(exports, 'aws_sagemaker', { get: function () { return require('./aws-sagemaker'); } }); -Object.defineProperty(exports, 'aws_sam', { get: function () { return require('./aws-sam'); } }); -Object.defineProperty(exports, 'aws_scheduler', { get: function () { return require('./aws-scheduler'); } }); -Object.defineProperty(exports, 'aws_sdb', { get: function () { return require('./aws-sdb'); } }); -Object.defineProperty(exports, 'aws_secretsmanager', { get: function () { return require('./aws-secretsmanager'); } }); -Object.defineProperty(exports, 'aws_securityhub', { get: function () { return require('./aws-securityhub'); } }); -Object.defineProperty(exports, 'aws_servicecatalog', { get: function () { return require('./aws-servicecatalog'); } }); -Object.defineProperty(exports, 'aws_servicecatalogappregistry', { get: function () { return require('./aws-servicecatalogappregistry'); } }); -Object.defineProperty(exports, 'aws_servicediscovery', { get: function () { return require('./aws-servicediscovery'); } }); -Object.defineProperty(exports, 'aws_ses_actions', { get: function () { return require('./aws-ses-actions'); } }); -Object.defineProperty(exports, 'aws_ses', { get: function () { return require('./aws-ses'); } }); -Object.defineProperty(exports, 'aws_shield', { get: function () { return require('./aws-shield'); } }); -Object.defineProperty(exports, 'aws_signer', { get: function () { return require('./aws-signer'); } }); -Object.defineProperty(exports, 'aws_simspaceweaver', { get: function () { return require('./aws-simspaceweaver'); } }); -Object.defineProperty(exports, 'aws_sns_subscriptions', { get: function () { return require('./aws-sns-subscriptions'); } }); -Object.defineProperty(exports, 'aws_sns', { get: function () { return require('./aws-sns'); } }); -Object.defineProperty(exports, 'aws_sqs', { get: function () { return require('./aws-sqs'); } }); -Object.defineProperty(exports, 'aws_ssm', { get: function () { return require('./aws-ssm'); } }); -Object.defineProperty(exports, 'aws_ssmcontacts', { get: function () { return require('./aws-ssmcontacts'); } }); -Object.defineProperty(exports, 'aws_ssmincidents', { get: function () { return require('./aws-ssmincidents'); } }); -Object.defineProperty(exports, 'aws_sso', { get: function () { return require('./aws-sso'); } }); -Object.defineProperty(exports, 'aws_stepfunctions_tasks', { get: function () { return require('./aws-stepfunctions-tasks'); } }); -Object.defineProperty(exports, 'aws_stepfunctions', { get: function () { return require('./aws-stepfunctions'); } }); -Object.defineProperty(exports, 'aws_supportapp', { get: function () { return require('./aws-supportapp'); } }); -Object.defineProperty(exports, 'aws_synthetics', { get: function () { return require('./aws-synthetics'); } }); -Object.defineProperty(exports, 'aws_systemsmanagersap', { get: function () { return require('./aws-systemsmanagersap'); } }); -Object.defineProperty(exports, 'aws_timestream', { get: function () { return require('./aws-timestream'); } }); -Object.defineProperty(exports, 'aws_transfer', { get: function () { return require('./aws-transfer'); } }); -Object.defineProperty(exports, 'aws_verifiedpermissions', { get: function () { return require('./aws-verifiedpermissions'); } }); -Object.defineProperty(exports, 'aws_voiceid', { get: function () { return require('./aws-voiceid'); } }); -Object.defineProperty(exports, 'aws_vpclattice', { get: function () { return require('./aws-vpclattice'); } }); -Object.defineProperty(exports, 'aws_waf', { get: function () { return require('./aws-waf'); } }); -Object.defineProperty(exports, 'aws_wafregional', { get: function () { return require('./aws-wafregional'); } }); -Object.defineProperty(exports, 'aws_wafv2', { get: function () { return require('./aws-wafv2'); } }); -Object.defineProperty(exports, 'aws_wisdom', { get: function () { return require('./aws-wisdom'); } }); -Object.defineProperty(exports, 'aws_workspaces', { get: function () { return require('./aws-workspaces'); } }); -Object.defineProperty(exports, 'aws_workspacesweb', { get: function () { return require('./aws-workspacesweb'); } }); -Object.defineProperty(exports, 'aws_xray', { get: function () { return require('./aws-xray'); } }); -Object.defineProperty(exports, 'cloud_assembly_schema', { get: function () { return require('./cloud-assembly-schema'); } }); -Object.defineProperty(exports, 'cloudformation_include', { get: function () { return require('./cloudformation-include'); } }); -Object.defineProperty(exports, 'custom_resources', { get: function () { return require('./custom-resources'); } }); -Object.defineProperty(exports, 'cx_api', { get: function () { return require('./cx-api'); } }); -Object.defineProperty(exports, 'lambda_layer_awscli', { get: function () { return require('./lambda-layer-awscli'); } }); -Object.defineProperty(exports, 'lambda_layer_kubectl', { get: function () { return require('./lambda-layer-kubectl'); } }); -Object.defineProperty(exports, 'lambda_layer_node_proxy_agent', { get: function () { return require('./lambda-layer-node-proxy-agent'); } }); -Object.defineProperty(exports, 'pipelines', { get: function () { return require('./pipelines'); } }); -Object.defineProperty(exports, 'region_info', { get: function () { return require('./region-info'); } }); -Object.defineProperty(exports, 'triggers', { get: function () { return require('./triggers'); } }); diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 7e75c366952f2..bbcac3151d921 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -41,7 +41,8 @@ "post": [ "ts-node ./scripts/verify-imports-resolve-same.ts", "ts-node ./scripts/verify-imports-shielded.ts", - "ts-node ./cx-api/build-tools/flag-report.ts" + "ts-node ./cx-api/build-tools/flag-report.ts", + "env QUIET=1 lazify ." ] }, "cdk-package": { @@ -166,6 +167,7 @@ "@types/jest": "^29.5.5", "@types/lodash": "^4.14.198", "@types/punycode": "^2.1.0", + "@aws-cdk/lazify": "0.0.0", "aws-sdk": "^2.1461.0", "aws-sdk-client-mock": "^3.0.0", "aws-sdk-client-mock-jest": "^3.0.0", @@ -209,11 +211,7 @@ "libRoot": "/root/remodel/packages/aws-cdk-lib" }, "exports": { - ".": { - "types": "./index.d.ts", - "import": "./index.js", - "require": "./lazy-index.js" - }, + ".": "./index.js", "./.jsii": "./.jsii", "./.warnings.jsii.js": "./.warnings.jsii.js", "./alexa-ask": "./alexa-ask/index.js", diff --git a/packages/aws-cdk-lib/pipelines/lib/private/approve-lambda/.is_custom_resource b/packages/aws-cdk-lib/pipelines/lib/private/approve-lambda/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk-lib/scripts/gen.ts b/packages/aws-cdk-lib/scripts/gen.ts index 7c56f5189160c..2bb7a78e0988b 100644 --- a/packages/aws-cdk-lib/scripts/gen.ts +++ b/packages/aws-cdk-lib/scripts/gen.ts @@ -6,7 +6,6 @@ import submodulesGen from './submodules'; const awsCdkLibDir = path.join(__dirname, '..'); const pkgJsonPath = path.join(awsCdkLibDir, 'package.json'); const topLevelIndexFilePath = path.join(awsCdkLibDir, 'index.ts'); -const lazyExportsFilePath = path.join(awsCdkLibDir, 'lazy-index.ts'); const scopeMapPath = path.join(__dirname, 'scope-map.json'); main().catch(e => { @@ -49,11 +48,6 @@ async function updateExportsAndEntryPoints(modules: ModuleMap) { const indexFile = await fs.readFile(topLevelIndexFilePath); indexStatements.push(...indexFile.toString('utf-8').split('\n').filter(Boolean)); } - const lazyExports = new Array(); - if (fs.existsSync(lazyExportsFilePath)) { - const lazExportsFile = await fs.readFile(lazyExportsFilePath); - lazyExports.push(...lazExportsFile.toString('utf-8').split('\n').filter(Boolean)); - } for (const [moduleName, { definition }] of Object.entries(modules)) { const moduleConfig = { @@ -69,14 +63,6 @@ async function updateExportsAndEntryPoints(modules: ModuleMap) { if (!indexStatements.find(e => e.includes(moduleConfig.name))) { indexStatements.push(`export * as ${moduleConfig.submodule} from './${moduleConfig.name}';`); } - - if (!lazyExports.find(e => e.includes(moduleConfig.name))) { - if (moduleConfig.name === 'core') { - lazyExports.unshift(`export * from './${moduleConfig.name}';`); - } else { - lazyExports.push(`Object.defineProperty(exports, '${moduleConfig.submodule}', { get: function () { return require('${exportName}'); } });`); - } - } } // sort exports @@ -84,5 +70,4 @@ async function updateExportsAndEntryPoints(modules: ModuleMap) { await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 }); await fs.writeFile(topLevelIndexFilePath, indexStatements.sort((l1, l2) => l1.localeCompare(l2)).join('\n') + '\n'); - await fs.writeFile(lazyExportsFilePath, lazyExports.sort((l1, l2) => l1.localeCompare(l2)).join('\n') + '\n'); } diff --git a/packages/aws-cdk-lib/triggers/lib/lambda/.is_custom_resource b/packages/aws-cdk-lib/triggers/lib/lambda/.is_custom_resource new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tools/@aws-cdk/lazify/.gitignore b/tools/@aws-cdk/lazify/.gitignore new file mode 100644 index 0000000000000..bef31def37928 --- /dev/null +++ b/tools/@aws-cdk/lazify/.gitignore @@ -0,0 +1,15 @@ +*.js +*.js.map +*.d.ts +dist + +.LAST_BUILD +*.snk +!jest.config.js + +.nyc_output +coverage +nyc.config.js +!.eslintrc.js +!test/test-fixture/jsii/node_modules/ +junit.xml diff --git a/tools/@aws-cdk/lazify/LICENSE b/tools/@aws-cdk/lazify/LICENSE new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/tools/@aws-cdk/lazify/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/@aws-cdk/lazify/README.md b/tools/@aws-cdk/lazify/README.md new file mode 100644 index 0000000000000..b67e5bdca8d48 --- /dev/null +++ b/tools/@aws-cdk/lazify/README.md @@ -0,0 +1,85 @@ +# lazify + +> **NOTE:** This tool should only be used on packages in this repository, +> and is not intended for external usage. + +This tool rewrites TypeScript-compiled JavaScript files in the current directory +to make all subpackage imports lazy. Subpackages will only be imported when +they are actually used/needed, instead of all packages being all read on +startup. + +This can be used to reduce the load time of large JavaScript libraries, large +parts of which may go unused in any particular client application. + +> [!IMPORTANT] +> This transformation is not safe in general. If modules contain code that must +> be executed upon startup for its side effects, then that code may not run or +> may not run in the right order. +> +> In general, code that depends on those kinds of side effects should be avoided +> regardless. + +## How to use + +```shell +# Run on all JavaScript in the current directory +lazify . +``` + +## Transformations + +We apply the following transformations: + +### Make require() lazy + +We turn this: + +```js +const my_module_1 = require('./my-module'); + +function hello() { + return my_module_1.hello(); +} +``` + +Into this: + +```js +function my_module_1() { + return require('./my-module'); +} + +function hello() { + return my_module_1().hello(); +} +``` + +This makes it so `my-module.js` is only loaded if and when the `hello()` function is actually +called. If that function is never called, we didn't need to needlessly load `my-module.js`. + +### Make getters for 'export *' + +The following TypeScript idiom: + +```ts +export * from './my-module'; +``` + +Is hard to make lazy, because it requires knowing the symbols that are available in `my-module`. + +What this package does is load `my-module.js` at *transform time*, inspect its +list of *exported symbols*, and make a list of lazy getters for each of those symbols. + +So, after statically determining the list of symbols to be `foo`, `bar` and +`baz`, the above gets turned into: + +```js +Object.defineProperty(exports, "foo", { get: () => require("./my-module").foo }); +Object.defineProperty(exports, "bar", { get: () => require("./my-module").bar }); +Object.defineProperty(exports, "baz", { get: () => require("./my-module").baz }); +``` + +> [!IMPORTANT] +> This transformation is also not safe for modules that add to their exported symbol +> set at runtime. None of the TypeScript-written code in our repository should be +> doing that. diff --git a/tools/@aws-cdk/lazify/bin/lazify b/tools/@aws-cdk/lazify/bin/lazify new file mode 100755 index 0000000000000..33415aef9b8c3 --- /dev/null +++ b/tools/@aws-cdk/lazify/bin/lazify @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./lazify.js'); \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/bin/lazify.ts b/tools/@aws-cdk/lazify/bin/lazify.ts new file mode 100644 index 0000000000000..21b39730eedb5 --- /dev/null +++ b/tools/@aws-cdk/lazify/bin/lazify.ts @@ -0,0 +1,43 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { transformFile } from '../lib'; + +async function main() { + const args = process.argv.slice(2); + const verbose = !process.env.QUIET; + + for (const arg of args) { + await recurseJs( + arg, + async (f) => { + // Only if there's an accompanying .ts file + const tsFile = f.replace(/\.js$/, '.ts'); + if (await fs.pathExists(tsFile)) { + await transformFile(f, verbose); + } + }, + // Skip directories marked as 'custom resource's, so we don't affect asset hashes + async (d) => path.basename(d) !== 'node_modules' && await fs.pathExists(path.join(d, '.is_custom_resource'))); + } +} + +async function recurseJs(root: string, fileBlock: (x: string) => Promise, dirBlock: (x: string) => Promise) { + return recurse(root); + + async function recurse(f: string) { + const s = await fs.stat(f); + if (s.isFile() && f.endsWith('.js')) { + await fileBlock(f); + } + if (s.isDirectory() && await dirBlock(f)) { + for (const child of await fs.readdir(f)) { + await recurse(path.join(f, child)); + } + } + } +} + +main().catch((e) => { + console.error(e); + process.exitCode = 1; +}); \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/jest.config.js b/tools/@aws-cdk/lazify/jest.config.js new file mode 100644 index 0000000000000..9a7e1a9cb0b61 --- /dev/null +++ b/tools/@aws-cdk/lazify/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/lib/index.ts b/tools/@aws-cdk/lazify/lib/index.ts new file mode 100644 index 0000000000000..79c1ae3432ed3 --- /dev/null +++ b/tools/@aws-cdk/lazify/lib/index.ts @@ -0,0 +1,236 @@ +/** + * Transform a set of .js files, making all module imports lazy + * + * That is: + * + * - Find all top-level require() assignments, and replace them with a function that performs + * the require(). That way, the require() is only done if any of the objects from its scope + * are actually used. + * - Find all (transpiled) `export * from 'xyz';` statements (by searching for an invocation + * of `__exportStar()`): load the actual module, enumerate the entries, and create a getter + * for each entry. + */ +import { promises as fs } from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; + +type LogFn = (...x: string[]) => void; + +export async function transformFile(filename: string, verbose: boolean) { + progress(filename, '... '); + const contents = await fs.readFile(filename, { encoding: 'utf-8' }); + const transformed = transformFileContents(filename, contents, progress); + await fs.writeFile(filename, transformed, { encoding: 'utf-8' }); + progress(' Done!\n'); + + function progress(...x: string[]) { + if (verbose) { + process.stderr.write(x.join(' ')); + } + } +} + +export function transformFileContents(filename: string, contents: string, progress?: LogFn) { + const sourceFile = ts.createSourceFile( + filename, + contents, + ts.ScriptTarget.Latest, + true // setParentNodes, need this for tree analysis + ); + + // Find all top-level requires and turn them into a function + const topLevelAssignments = sourceFile.statements + .filter(ts.isVariableStatement) + .filter((stmt) => stmt.declarationList.declarations.length === 1) + .map((stmt) => [stmt, stmt.declarationList.declarations[0]] as const); + + progress?.(`${topLevelAssignments.length} declarations`, '... '); + + const topLevelRequires = topLevelAssignments + .flatMap(([stmt, a]) => a.initializer && ts.isCallExpression(a.initializer) + && ts.isIdentifier(a.initializer.expression) && a.initializer.expression.text === 'require' + && ts.isStringLiteral(a.initializer.arguments[0]) + && ts.isIdentifier(a.name) + ? [[stmt, a.name, a.initializer.arguments[0].text] as const] : []); + + progress?.(`${topLevelRequires.length} requires`, '... '); + + let file = sourceFile; + + for (const [stmt, binding, moduleName] of topLevelRequires) { + const result = ts.transform(file, [(ctx: ts.TransformationContext): ts.Transformer => { + const factory = ctx.factory; + const visit: ts.Visitor = node => { + // If this is the statement, replace it with a function definition + + // We replace it with a function that will replace itself after the first invocation. + // This is memoizing on steroids. Instead of: + // + // function mod() { return require('mod'); } + // + // We do: + // + // let mod = () => { const tmp = require('mod'); mod = () => tmp; return tmp; } + // + // This is about 100x faster at call time (~20ns per call instead of ~2us). + + if (node === stmt) { + return createVariable(factory, binding, + factory.createArrowFunction(undefined, undefined, [], undefined, undefined, + factory.createBlock([ + // tmp = require(...) + createVariable(factory, 'tmp', factory.createCallExpression(factory.createIdentifier('require'), [], [factory.createStringLiteral(moduleName)])), + + // = () => tmp + createAssignment(factory, binding.text, + factory.createArrowFunction(undefined, undefined, [], undefined, undefined, factory.createIdentifier('tmp'))), + + // return tmp + factory.createReturnStatement(factory.createIdentifier('tmp')), + ]), + ), + ); + } + + // If this is a shorthand property assignment and we we are the identifier in it, split it into two + if (ts.isShorthandPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === binding.text) { + return factory.createPropertyAssignment(node.name.text, factory.createCallExpression(factory.createIdentifier(binding.text), [], [])); + } + + // If this was an identifier referencing the original required module, turn it into a function call + if (ts.isIdentifier(node) && node.text === binding.text) { + + // Ignore this identifier if it is not in RHS position + const ignore = node.parent && ( + (ts.isPropertyAssignment(node.parent) && node.parent.name === node) // { ident: value } + || (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) // obj.ident = 3; + || ts.isMethodDeclaration(node.parent) // public ident() { ... } + || ts.isMethodSignature(node.parent) // interface X { ident(); } + || ts.isPropertyDeclaration(node.parent) // class X { ident: string } + || ts.isPropertySignature(node.parent) // interface X { ident: string } + || ts.isGetAccessor(node.parent) // class X { get ident() { ... } } + || ts.isGetAccessorDeclaration(node.parent) // interface X { get ident: string } + || ts.isSetAccessor(node.parent) // class X { set ident() { ... } } + || ts.isSetAccessorDeclaration(node.parent) // interface X { set ident: string } + ); + // Another concern is shadowing: we're not checking for that right now because + // I don't know how to and in our code base it won't pose a problem, as we have + // linter rules that forbid identifier shadowing (this is an + // assumption that makes this tool non-portable for now). + + // More places are also not RHS but if we leave those, it'll blow up syntactically and that's good + + if (!ignore) { + return factory.createCallExpression(factory.createIdentifier(binding.text), [], []); + } + } + + return ts.visitEachChild(node, child => visit(child), ctx); + }; + + return (sf: ts.SourceFile) => ts.visitNode(sf, visit, ts.isSourceFile) ?? sf; + }]); + + file = result.transformed[0]; + progress?.('X'); + } + + // Replace __exportStar + + file = ts.transform(file, [(ctx: ts.TransformationContext): ts.Transformer => { + const factory = ctx.factory; + const visit: ts.Visitor = node => { + if (node.parent && ts.isSourceFile(node.parent) + && ts.isExpressionStatement(node) + && ts.isCallExpression(node.expression) + && ts.isIdentifier(node.expression.expression) + && node.expression.expression.text === '__exportStar' + && node.expression.arguments.length === 2 + && ts.isCallExpression(node.expression.arguments[0]) + && ts.isIdentifier(node.expression.arguments[0].expression) + && node.expression.arguments[0].expression.text === 'require' + && ts.isStringLiteral(node.expression.arguments[0].arguments[0])) { + // __exportStar(require('something'), exports); + + const requiredModule = node.expression.arguments[0].arguments[0].text; + + const file = require.resolve(requiredModule, { paths: [path.dirname(filename)] }); + // FIXME: Should probably do this in a subprocess + const module = require(file); + const entries = Object.keys(module); + + return entries.map((entry) => + createModuleGetter(factory, entry, requiredModule, (mod) => + factory.createPropertyAccessExpression(mod, entry)) + ); + } + + if (node.parent && ts.isSourceFile(node.parent) + && ts.isExpressionStatement(node) + && ts.isBinaryExpression(node.expression) + && node.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken + && ts.isPropertyAccessExpression(node.expression.left) + && ts.isIdentifier(node.expression.left.expression) + && node.expression.left.expression.text === 'exports' + && ts.isCallExpression(node.expression.right) + && ts.isIdentifier(node.expression.right.expression) + && node.expression.right.expression.text === 'require' + && ts.isStringLiteral(node.expression.right.arguments[0])) { + // exports.module = require('./module'); + + const exportName = node.expression.left.name.text; + const moduleName = node.expression.right.arguments[0].text; + return createModuleGetter(factory, exportName, moduleName, (x) => x); + } + + return ts.visitEachChild(node, child => visit(child), ctx); + }; + + return (sf: ts.SourceFile) => ts.visitNode(sf, visit, ts.isSourceFile) ?? sf; + }]).transformed[0]; + + + + // To print the AST, we'll use TypeScript's printer + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + + return printer.printFile(file); +} + +function createVariable(factory: ts.NodeFactory, name: string | ts.BindingName, expression: ts.Expression) { + return factory.createVariableStatement([], + factory.createVariableDeclarationList([ + factory.createVariableDeclaration(name, undefined, undefined, expression), + ])); +} + +function createAssignment(factory: ts.NodeFactory, name: string, expression: ts.Expression) { + return factory.createExpressionStatement( + factory.createBinaryExpression( + factory.createIdentifier(name), + ts.SyntaxKind.EqualsToken, + expression)); +} + +function createModuleGetter( + factory: ts.NodeFactory, + exportName: string, + moduleName: string, + moduleFormatter: (x: ts.Expression) => ts.Expression, +) { + return factory.createExpressionStatement(factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), + undefined, + [ + factory.createIdentifier('exports'), + factory.createStringLiteral(exportName), + factory.createObjectLiteralExpression([ + factory.createPropertyAssignment('configurable', factory.createTrue()), + factory.createPropertyAssignment('get', + factory.createArrowFunction(undefined, undefined, [], undefined, undefined, + moduleFormatter( + factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(moduleName)])))), + ]), + ] + )); +} \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/package.json b/tools/@aws-cdk/lazify/package.json new file mode 100644 index 0000000000000..597f81bba24bc --- /dev/null +++ b/tools/@aws-cdk/lazify/package.json @@ -0,0 +1,32 @@ +{ + "name": "@aws-cdk/lazify", + "version": "0.0.0", + "private": true, + "bin": { + "lazify": "bin/lazify" + }, + "scripts": { + "build": "tsc --build", + "build+test": "npm run build && npm run test", + "lint": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern src test", + "package": "mkdir -p dist/js && mv $(npm pack) dist/js/", + "test": "jest --passWithNoTests --updateSnapshot", + "test:watch": "jest --watch", + "watch": "tsc --build -w tsconfig.dev.json" + }, + "devDependencies": { + "@types/jest": "^29.5.4", + "@types/node": "^16", + "@aws-cdk/cdk-build-tools": "0.0.0", + "jest": "^29", + "ts-jest": "^29", + "typescript": "^4.5.5" + }, + "dependencies": { + "esbuild": "^0.19.2", + "fs-extra": "^10.1.0", + "yargs": "^17.7.2" + }, + "main": "lib/index.js", + "license": "Apache-2.0" +} diff --git a/tools/@aws-cdk/lazify/test/export-star.test.ts b/tools/@aws-cdk/lazify/test/export-star.test.ts new file mode 100644 index 0000000000000..ceb1930fe658f --- /dev/null +++ b/tools/@aws-cdk/lazify/test/export-star.test.ts @@ -0,0 +1,32 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { transformFileContents } from '../lib'; + +// Write a .js file in this directory that will be imported by tests below +beforeEach(async () => { + await fs.writeFile(path.join(__dirname, 'some-module.js'), [ + 'module.exports.foo = function() { return "foo"; }', + 'module.exports.bar = 5;', + ].join('\n'), { encoding: 'utf-8' }); +}); + +test('replace __exportStar with getters', () => { + const fakeFile = path.join(__dirname, 'index.ts'); + expect(transformFileContents(fakeFile, [ + '__exportStar(require("./some-module"), exports);' + ].join('\n'))).toMatchInlineSnapshot(` +"Object.defineProperty(exports, "foo", { configurable: true, get: () => require("./some-module").foo }); +Object.defineProperty(exports, "bar", { configurable: true, get: () => require("./some-module").bar }); +" +`); +}); + +test('replace re-export with getter', () => { + const fakeFile = path.join(__dirname, 'index.ts'); + expect(transformFileContents(fakeFile, [ + 'exports.some_module = require("./some-module");', + ].join('\n'))).toMatchInlineSnapshot(` +"Object.defineProperty(exports, "some_module", { configurable: true, get: () => require("./some-module") }); +" +`); +}); \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/test/transform-require.test.ts b/tools/@aws-cdk/lazify/test/transform-require.test.ts new file mode 100644 index 0000000000000..954b29f1dcf04 --- /dev/null +++ b/tools/@aws-cdk/lazify/test/transform-require.test.ts @@ -0,0 +1,64 @@ +import { transformFileContents } from "../lib"; + +test('plain require', () => { + expect(tx( + 'const x = require("x");', + 'module.exports.banana = function() {', + ' return x.hello();', + '}' +)).toMatchInlineSnapshot(` +"var x = () => { var tmp = require("x"); x = () => tmp; return tmp; }; +module.exports.banana = function () { + return x().hello(); +}; +" +`); +}); + +test('split object literal shorthand', () => { + expect(tx( + 'const x = require("x");', + 'module.exports.banana = function() {', + ' return { x };', + '}' +)).toMatchInlineSnapshot(` +"var x = () => { var tmp = require("x"); x = () => tmp; return tmp; }; +module.exports.banana = function () { + return { x: x() }; +}; +" +`); +}); + +test.each([ + ['object key', 'const x = { ident: 5 };'], + ['object access', 'const x = obj.ident;'], + ['method declaration', 'class X { public ident() { } }'], + ['method signature', 'interface X { ident(); }'], + ['property declaration', 'class X { public readonly ident: string; }'], + ['property signature', 'interface X { readonly ident: string; }'], + ['get accessor', 'class X { get ident() { return "asdf"; } }'], + ['set accessor', 'class X { set ident(value: string) { } }'], +])('do not transform identifier in %p position', (_, decl) => { + const input = [ + 'const ident = require("./module");', + decl, + ]; + const transformed = tx(...input).split('\n'); + + const normalizedTransformed = [ + transformed[0], + transformed.slice(1).join('\n').replace(/\s+/g, ' ').trim(), + ]; + const normalizedDecl = decl.replace(/\s+/g, ' ').trim(); + + expect(normalizedTransformed).toEqual([ + 'var ident = () => { var tmp = require("./module"); ident = () => tmp; return tmp; };', + normalizedDecl, + ]); +}); + + +function tx(...xs: string[]) { + return transformFileContents('index.ts', xs.join('\n')); +} \ No newline at end of file diff --git a/tools/@aws-cdk/lazify/tsconfig.json b/tools/@aws-cdk/lazify/tsconfig.json new file mode 100644 index 0000000000000..b6fb832634653 --- /dev/null +++ b/tools/@aws-cdk/lazify/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "declaration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "es2019", + "dom" + ], + "module": "CommonJS", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2019" + }, + "include": [ + "bin/**/*.ts", + "lib/**/*.ts" + ], + "exclude": [] +} diff --git a/yarn.lock b/yarn.lock index b24b3de0cb464..90d0d5ceae99a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4108,7 +4108,7 @@ expect "^28.0.0" pretty-format "^28.0.0" -"@types/jest@^29.5.5": +"@types/jest@^29.5.4", "@types/jest@^29.5.5": version "29.5.5" resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz#727204e06228fe24373df9bae76b90f3e8236a2a" integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== @@ -6766,7 +6766,7 @@ es6-weak-map@^2.0.3: es6-iterator "^2.0.3" es6-symbol "^3.1.1" -esbuild@^0.19.3: +esbuild@^0.19.2, esbuild@^0.19.3: version "0.19.3" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz#d9268cd23358eef9d76146f184e0c55ff8da7bb6" integrity sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==