@nikovirtala/projen-lambda-function-construct-generator 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts ADDED
@@ -0,0 +1,99 @@
1
+ import { BuildOptions } from "@mrgrain/cdk-esbuild";
2
+ import { Component } from "projen";
3
+ import { NodeProject } from "projen/lib/javascript";
4
+ /**
5
+ * Options for the LambdaFunctionConstructGenerator
6
+ */
7
+ export interface LambdaFunctionConstructGeneratorOptions {
8
+ /**
9
+ * Source directory where Lambda Function handlers are located
10
+ *
11
+ * @default "src/handlers"
12
+ */
13
+ readonly sourceDir?: string;
14
+ /**
15
+ * Output directory where Lambda Function constructs will be generated
16
+ *
17
+ * @default "src/constructs/lambda"
18
+ */
19
+ readonly outputDir?: string;
20
+ /**
21
+ * File pattern to identify Lambda Function handlers
22
+ *
23
+ * @default "*.lambda.ts"
24
+ */
25
+ readonly filePattern?: string;
26
+ /**
27
+ * esbuild options to customize the bundling process
28
+ *
29
+ * @default {}
30
+ */
31
+ readonly esbuildOptions?: BuildOptions;
32
+ /**
33
+ * Whether to automatically add the required dependencies
34
+ *
35
+ * @default true
36
+ */
37
+ readonly addDependencies?: boolean;
38
+ /**
39
+ * Import statement for the base construct
40
+ *
41
+ * @example "import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';"
42
+ *
43
+ * @default "import { aws_lambda } from 'aws-cdk-lib';"
44
+ */
45
+ readonly baseConstructImport?: string;
46
+ /**
47
+ * Name of the construct class to extend
48
+ *
49
+ * @example "NodejsFunction"
50
+ *
51
+ * @default "aws_lambda.Function"
52
+ */
53
+ readonly baseConstructClass?: string;
54
+ /**
55
+ * Package name to add as dependency for the base construct
56
+ *
57
+ * @example "aws-cdk-lib"
58
+ *
59
+ * @default "aws-cdk-lib"
60
+ */
61
+ readonly baseConstructPackage?: string;
62
+ }
63
+ /**
64
+ * A projen component that generates AWS CDK Lambda Function constructs and bundles their code assets using esbuild.
65
+ *
66
+ * The bundling happens during projen execution, not during CDK synth, enabling a "build once, deploy many" pattern.
67
+ */
68
+ export declare class LambdaFunctionConstructGenerator extends Component {
69
+ readonly sourceDir: string;
70
+ readonly outputDir: string;
71
+ readonly filePattern: string;
72
+ readonly esbuildOptions: BuildOptions;
73
+ readonly baseConstructImport?: string;
74
+ readonly baseConstructClass?: string;
75
+ readonly baseConstructPackage?: string;
76
+ private readonly nodeProject;
77
+ private readonly bundlerScriptPath;
78
+ constructor(project: NodeProject, options?: LambdaFunctionConstructGeneratorOptions);
79
+ /**
80
+ * Add required dependencies for the component
81
+ */
82
+ private addDependencies;
83
+ /**
84
+ * Create a unique ID based on sourceDir and filePattern
85
+ */
86
+ private createUniqueId;
87
+ /**
88
+ * Create the bundle task that will be executed during projen build
89
+ */
90
+ private createBundleTask;
91
+ /**
92
+ * Create the bundler script that will be executed by the bundle task
93
+ */
94
+ private createBundlerScript;
95
+ /**
96
+ * Add the bundle task to the build workflow
97
+ */
98
+ private addBundleTaskToWorkflow;
99
+ }
package/lib/index.js ADDED
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.LambdaFunctionConstructGenerator = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const path = require("path");
7
+ const projen_1 = require("projen");
8
+ /**
9
+ * A projen component that generates AWS CDK Lambda Function constructs and bundles their code assets using esbuild.
10
+ *
11
+ * The bundling happens during projen execution, not during CDK synth, enabling a "build once, deploy many" pattern.
12
+ */
13
+ class LambdaFunctionConstructGenerator extends projen_1.Component {
14
+ constructor(project, options) {
15
+ super(project);
16
+ this.nodeProject = project;
17
+ this.sourceDir = options?.sourceDir ?? "src/handlers";
18
+ this.outputDir = options?.outputDir ?? "src/constructs/lambda";
19
+ this.filePattern = options?.filePattern ?? "*.lambda.ts";
20
+ this.esbuildOptions = options?.esbuildOptions ?? {};
21
+ this.baseConstructImport = options?.baseConstructImport;
22
+ this.baseConstructClass = options?.baseConstructClass;
23
+ this.baseConstructPackage = options?.baseConstructPackage;
24
+ // Create unique script name based on sourceDir and filePattern
25
+ const uniqueId = this.createUniqueId(this.sourceDir, this.filePattern);
26
+ this.bundlerScriptPath = path.join(".projen", `generate-and-bundle-${uniqueId}.ts`);
27
+ // Add required dependencies
28
+ if (options?.addDependencies ?? true) {
29
+ this.addDependencies(options?.baseConstructPackage);
30
+ }
31
+ // Create the bundle task
32
+ this.createBundleTask();
33
+ // Add the bundle task to the build workflow
34
+ this.addBundleTaskToWorkflow();
35
+ }
36
+ /**
37
+ * Add required dependencies for the component
38
+ */
39
+ addDependencies(additionalPackage) {
40
+ this.nodeProject.addDeps("aws-cdk-lib", "constructs");
41
+ if (additionalPackage && additionalPackage !== "aws-cdk-lib" && additionalPackage !== "constructs") {
42
+ this.nodeProject.addDeps(additionalPackage);
43
+ }
44
+ }
45
+ /**
46
+ * Create a unique ID based on sourceDir and filePattern
47
+ */
48
+ createUniqueId(sourceDir, filePattern) {
49
+ // Remove special characters and convert to kebab case
50
+ const dirPart = sourceDir.replace(/\//g, "-").replace(/[^\w-]/g, "");
51
+ const patternPart = filePattern
52
+ .replace(/\*/g, "")
53
+ .replace(/\./g, "-")
54
+ .replace(/[^\w-]/g, "");
55
+ return `${dirPart}-${patternPart}`.replace(/--+/g, "-").replace(/^-|-$/g, "");
56
+ }
57
+ /**
58
+ * Create the bundle task that will be executed during projen build
59
+ */
60
+ createBundleTask() {
61
+ const uniqueId = this.createUniqueId(this.sourceDir, this.filePattern);
62
+ const taskName = `generate-and-bundle-${uniqueId}`;
63
+ let baseConstructArgs = "";
64
+ if (this.baseConstructImport) {
65
+ baseConstructArgs += ` --base-construct-import '${this.baseConstructImport}'`;
66
+ }
67
+ if (this.baseConstructClass) {
68
+ baseConstructArgs += ` --base-construct-class '${this.baseConstructClass}'`;
69
+ }
70
+ const bundleTask = this.nodeProject.addTask(taskName, {
71
+ description: `Generate Lambda Function Constructs from ${this.sourceDir}/${this.filePattern} and bundle their handlers`,
72
+ exec: `tsx --tsconfig tsconfig.dev.json ${this.bundlerScriptPath} --source-dir ${this.sourceDir} --output-dir ${this.outputDir} --file-pattern "${this.filePattern}" --esbuild-options '${JSON.stringify(this.esbuildOptions)}'${baseConstructArgs}`,
73
+ });
74
+ // Create the bundler script
75
+ this.createBundlerScript();
76
+ return bundleTask;
77
+ }
78
+ /**
79
+ * Create the bundler script that will be executed by the bundle task
80
+ */
81
+ createBundlerScript() {
82
+ const bundlerScript = `// ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
83
+
84
+ import * as path from 'path';
85
+ import * as fs from 'fs';
86
+ import * as esbuild from 'esbuild';
87
+ import * as glob from 'glob';
88
+ import { pascalCase } from 'change-case';
89
+ import yargs from 'yargs/yargs';
90
+ import { hideBin } from 'yargs/helpers';
91
+
92
+ async function main() {
93
+ const argv = await yargs(hideBin(process.argv))
94
+ .option('source-dir', { type: 'string', default: 'src/handlers', description: 'Source directory where Lambda Function handlers are located' })
95
+ .option('output-dir', { type: 'string', default: 'src/constructs/lambda', description: 'Output directory where Lambda Function constructs will be generated' })
96
+ .option('file-pattern', { type: 'string', default: '*.lambda.ts', description: 'File pattern to identify Lambda Function handlers' })
97
+ .option('esbuild-options', { type: 'string', default: '{}', description: 'esbuild options as JSON string' })
98
+ .option('base-construct-import', { type: 'string', description: 'Import statement for the base construct' })
99
+ .option('base-construct-class', { type: 'string', description: 'Name of the construct class to extend' })
100
+ .help()
101
+ .parse();
102
+
103
+ const sourceDir = argv['source-dir'];
104
+ const outputDir = argv['output-dir'];
105
+ const filePattern = argv['file-pattern'];
106
+ const esbuildOptions = JSON.parse(argv['esbuild-options'] as string);
107
+ const baseConstructImport = argv['base-construct-import'] as string | undefined;
108
+ const baseConstructClass = argv['base-construct-class'] as string | undefined;
109
+
110
+ // Ensure output directory exists
111
+ fs.mkdirSync(path.join(process.cwd(), outputDir), { recursive: true });
112
+
113
+ // Ensure assets directory exists
114
+ const assetsDir = path.join(process.cwd(), 'assets', 'handlers');
115
+ fs.mkdirSync(assetsDir, { recursive: true });
116
+
117
+ // Find all Lambda Function handler files
118
+ const handlerFiles = glob.sync(path.join(process.cwd(), sourceDir, filePattern));
119
+
120
+ console.log(\`Found \${handlerFiles.length} Lambda Function handler files\`);
121
+
122
+ // Process each handler file
123
+ for (const handlerFile of handlerFiles) {
124
+ const relativePath = path.relative(path.join(process.cwd(), sourceDir), handlerFile);
125
+ const fileName = path.basename(relativePath, path.extname(relativePath));
126
+ const functionName = fileName.replace('.lambda', '');
127
+
128
+ console.log(\`Processing Lambda Function handler: \${functionName}\`);
129
+
130
+ // Create function-specific directory
131
+ const functionDir = path.join(assetsDir, functionName);
132
+ fs.mkdirSync(functionDir, { recursive: true });
133
+
134
+ // Bundle the handler code to index.js in the function directory
135
+ const outfile = path.join(functionDir, 'index.js');
136
+
137
+ try {
138
+ await esbuild.build({
139
+ entryPoints: [handlerFile],
140
+ bundle: true,
141
+ minify: true,
142
+ platform: 'node',
143
+ target: 'node18',
144
+ outfile,
145
+ ...esbuildOptions,
146
+ });
147
+
148
+ console.log(\`Successfully bundled \${functionName} to \${outfile}\`);
149
+
150
+ // Generate the CDK construct
151
+ const constructFilePath = path.join(process.cwd(), outputDir, \`\${functionName}.ts\`);
152
+ const constructCode = generateConstructCode(functionName, relativePath, baseConstructImport, baseConstructClass);
153
+
154
+ fs.writeFileSync(constructFilePath, constructCode);
155
+ console.log(\`Generated construct at \${constructFilePath}\`);
156
+ } catch (error) {
157
+ console.error(\`Error processing \${functionName}:\`, error);
158
+ }
159
+ }
160
+ }
161
+
162
+ function generateConstructCode(functionName: string, handlerPath: string, baseConstructImport?: string, baseConstructClass?: string) {
163
+ const constructName = \`\${pascalCase(functionName)}Function\`;
164
+
165
+ // Default values if no baseConstruct is provided
166
+ const importStatement = baseConstructImport ?? "";
167
+ const baseClassName = baseConstructClass ?? "aws_lambda.Function";
168
+
169
+ // Determine if we need to use aws_lambda.Runtime or not based on the base class
170
+ const useAwsLambdaRuntime = !baseConstructClass || baseClassName.includes("Function");
171
+
172
+ return \`// ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
173
+
174
+ import * as path from 'path';
175
+ import { fileURLToPath } from 'url';
176
+ \${importStatement}
177
+ import { aws_lambda } from 'aws-cdk-lib';
178
+ import { Construct } from 'constructs';
179
+
180
+ // ES Module compatibility
181
+ const __filename = fileURLToPath(import.meta.url);
182
+ const __dirname = path.dirname(__filename);
183
+
184
+ /**
185
+ * Properties for \${constructName}
186
+ */
187
+ export interface \${constructName}Props extends Omit<\${baseClassName === "aws_lambda.Function" ? "aws_lambda.FunctionProps" : \`\${baseClassName}Props\`}, 'code'\${useAwsLambdaRuntime ? " | 'runtime'" : ""} | 'handler'> {
188
+ \${useAwsLambdaRuntime ? \`/**
189
+ * Override the default runtime
190
+ * @default nodejs22.x
191
+ */
192
+ readonly runtime?: aws_lambda.Runtime;\` : ""}
193
+ }
194
+
195
+ /**
196
+ * \${constructName} - Lambda Function Construct for \${handlerPath}
197
+ */
198
+ export class \${constructName} extends \${baseClassName} {
199
+ constructor(scope: Construct, id: string, props: \${constructName}Props = {}) {
200
+ super(scope, id, {
201
+ ...props,
202
+ \${useAwsLambdaRuntime ? "runtime: props.runtime ?? aws_lambda.Runtime.NODEJS_22_X," : ""}
203
+ handler: 'index.handler',
204
+ code: aws_lambda.Code.fromAsset(path.join(__dirname, '../../../assets/handlers/\${functionName}')),
205
+ });
206
+ }
207
+ }
208
+ \`;
209
+ }
210
+
211
+ main().catch(error => {
212
+ console.error('Error:', error);
213
+ process.exit(1);
214
+ });
215
+ `;
216
+ // Create source code file and add code lines to it
217
+ const src = new projen_1.SourceCode(this.project, this.bundlerScriptPath);
218
+ const lines = bundlerScript.split("\n");
219
+ for (const line of lines) {
220
+ src.line(line);
221
+ }
222
+ // Add the dependencies needed for the bundler script
223
+ this.nodeProject.addDevDeps("esbuild", "glob", "yargs", "@types/glob", "@types/yargs", "tsx", "change-case");
224
+ }
225
+ /**
226
+ * Add the bundle task to the build workflow
227
+ */
228
+ addBundleTaskToWorkflow() {
229
+ // Get the compile task
230
+ const compileTask = this.nodeProject.tasks.tryFind("compile");
231
+ if (compileTask) {
232
+ // Add the bundle task as a dependency of the compile task
233
+ const uniqueId = this.createUniqueId(this.sourceDir, this.filePattern);
234
+ const taskName = `generate-and-bundle-${uniqueId}`;
235
+ const bundleTask = this.nodeProject.tasks.tryFind(taskName);
236
+ if (bundleTask) {
237
+ compileTask.prependSpawn(bundleTask);
238
+ }
239
+ }
240
+ }
241
+ }
242
+ exports.LambdaFunctionConstructGenerator = LambdaFunctionConstructGenerator;
243
+ _a = JSII_RTTI_SYMBOL_1;
244
+ LambdaFunctionConstructGenerator[_a] = { fqn: "@nikovirtala/projen-lambda-function-construct-generator.LambdaFunctionConstructGenerator", version: "0.0.0" };
245
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw2QkFBNkI7QUFFN0IsbUNBQStDO0FBc0UvQzs7OztHQUlHO0FBQ0gsTUFBYSxnQ0FBaUMsU0FBUSxrQkFBUztJQVczRCxZQUFZLE9BQW9CLEVBQUUsT0FBaUQ7UUFDL0UsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUM7UUFDM0IsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLEVBQUUsU0FBUyxJQUFJLGNBQWMsQ0FBQztRQUN0RCxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sRUFBRSxTQUFTLElBQUksdUJBQXVCLENBQUM7UUFDL0QsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLEVBQUUsV0FBVyxJQUFJLGFBQWEsQ0FBQztRQUN6RCxJQUFJLENBQUMsY0FBYyxHQUFHLE9BQU8sRUFBRSxjQUFjLElBQUksRUFBRSxDQUFDO1FBQ3BELElBQUksQ0FBQyxtQkFBbUIsR0FBRyxPQUFPLEVBQUUsbUJBQW1CLENBQUM7UUFDeEQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLE9BQU8sRUFBRSxrQkFBa0IsQ0FBQztRQUN0RCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsT0FBTyxFQUFFLG9CQUFvQixDQUFDO1FBRTFELCtEQUErRDtRQUMvRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSx1QkFBdUIsUUFBUSxLQUFLLENBQUMsQ0FBQztRQUVwRiw0QkFBNEI7UUFDNUIsSUFBSSxPQUFPLEVBQUUsZUFBZSxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FB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R0FBRyxJQUFJLG1CQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUNqRSxNQUFNLEtBQUssR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDdkIsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQixDQUFDO1FBRUQscURBQXFEO1FBQ3JELElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBQ2pILENBQUM7SUFFRDs7T0FFRztJQUNLLHVCQUF1QjtRQUMzQix1QkFBdUI7UUFDdkIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRTlELElBQUksV0FBVyxFQUFFLENBQUM7WUFDZCwwREFBMEQ7WUFDMUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN2RSxNQUFNLFFBQVEsR0FBRyx1QkFBdUIsUUFBUSxFQUFFLENBQUM7WUFDbkQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzVELElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQ2IsV0FBVyxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN6QyxDQUFDO1FBQ0wsQ0FBQztJQUNMLENBQUM7O0FBOVBMLDRFQStQQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IEJ1aWxkT3B0aW9ucyB9IGZyb20gXCJAbXJncmFpbi9jZGstZXNidWlsZFwiO1xuaW1wb3J0IHsgQ29tcG9uZW50LCBTb3VyY2VDb2RlIH0gZnJvbSBcInByb2plblwiO1xuaW1wb3J0IHsgTm9kZVByb2plY3QgfSBmcm9tIFwicHJvamVuL2xpYi9qYXZhc2NyaXB0XCI7XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgdGhlIExhbWJkYUZ1bmN0aW9uQ29uc3RydWN0R2VuZXJhdG9yXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhRnVuY3Rpb25Db25zdHJ1Y3RHZW5lcmF0b3JPcHRpb25zIHtcbiAgICAvKipcbiAgICAgKiBTb3VyY2UgZGlyZWN0b3J5IHdoZXJlIExhbWJkYSBGdW5jdGlvbiBoYW5kbGVycyBhcmUgbG9jYXRlZFxuICAgICAqXG4gICAgICogQGRlZmF1bHQgXCJzcmMvaGFuZGxlcnNcIlxuICAgICAqL1xuICAgIHJlYWRvbmx5IHNvdXJjZURpcj86IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIE91dHB1dCBkaXJlY3Rvcnkgd2hlcmUgTGFtYmRhIEZ1bmN0aW9uIGNvbnN0cnVjdHMgd2lsbCBiZSBnZW5lcmF0ZWRcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IFwic3JjL2NvbnN0cnVjdHMvbGFtYmRhXCJcbiAgICAgKi9cbiAgICByZWFkb25seSBvdXRwdXREaXI/OiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBGaWxlIHBhdHRlcm4gdG8gaWRlbnRpZnkgTGFtYmRhIEZ1bmN0aW9uIGhhbmRsZXJzXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCBcIioubGFtYmRhLnRzXCJcbiAgICAgKi9cbiAgICByZWFkb25seSBmaWxlUGF0dGVybj86IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIGVzYnVpbGQgb3B0aW9ucyB0byBjdXN0b21pemUgdGhlIGJ1bmRsaW5nIHByb2Nlc3NcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IHt9XG4gICAgICovXG4gICAgcmVhZG9ubHkgZXNidWlsZE9wdGlvbnM/OiBCdWlsZE9wdGlvbnM7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRvIGF1dG9tYXRpY2FsbHkgYWRkIHRoZSByZXF1aXJlZCBkZXBlbmRlbmNpZXNcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICByZWFkb25seSBhZGREZXBlbmRlbmNpZXM/OiBib29sZWFuO1xuXG4gICAgLyoqXG4gICAgICogSW1wb3J0IHN0YXRlbWVudCBmb3IgdGhlIGJhc2UgY29uc3RydWN0XG4gICAgICpcbiAgICAgKiBAZXhhbXBsZSBcImltcG9ydCB7IE5vZGVqc0Z1bmN0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYS1ub2RlanMnO1wiXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCBcImltcG9ydCB7IGF3c19sYW1iZGEgfSBmcm9tICdhd3MtY2RrLWxpYic7XCJcbiAgICAgKi9cbiAgICByZWFkb25seSBiYXNlQ29uc3RydWN0SW1wb3J0Pzogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogTmFtZSBvZiB0aGUgY29uc3RydWN0IGNsYXNzIHRvIGV4dGVuZFxuICAgICAqXG4gICAgICogQGV4YW1wbGUgXCJOb2RlanNGdW5jdGlvblwiXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCBcImF3c19sYW1iZGEuRnVuY3Rpb25cIlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGJhc2VDb25zdHJ1Y3RDbGFzcz86IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIFBhY2thZ2UgbmFtZSB0byBhZGQgYXMgZGVwZW5kZW5jeSBmb3IgdGhlIGJhc2UgY29uc3RydWN0XG4gICAgICpcbiAgICAgKiBAZXhhbXBsZSBcImF3cy1jZGstbGliXCJcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IFwiYXdzLWNkay1saWJcIlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGJhc2VDb25zdHJ1Y3RQYWNrYWdlPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEEgcHJvamVuIGNvbXBvbmVudCB0aGF0IGdlbmVyYXRlcyBBV1MgQ0RLIExhbWJkYSBGdW5jdGlvbiBjb25zdHJ1Y3RzIGFuZCBidW5kbGVzIHRoZWlyIGNvZGUgYXNzZXRzIHVzaW5nIGVzYnVpbGQuXG4gKlxuICogVGhlIGJ1bmRsaW5nIGhhcHBlbnMgZHVyaW5nIHByb2plbiBleGVjdXRpb24sIG5vdCBkdXJpbmcgQ0RLIHN5bnRoLCBlbmFibGluZyBhIFwiYnVpbGQgb25jZSwgZGVwbG95IG1hbnlcIiBwYXR0ZXJuLlxuICovXG5leHBvcnQgY2xhc3MgTGFtYmRhRnVuY3Rpb25Db25zdHJ1Y3RHZW5lcmF0b3IgZXh0ZW5kcyBDb21wb25lbnQge1xuICAgIHB1YmxpYyByZWFkb25seSBzb3VyY2VEaXI6IHN0cmluZztcbiAgICBwdWJsaWMgcmVhZG9ubHkgb3V0cHV0RGlyOiBzdHJpbmc7XG4gICAgcHVibGljIHJlYWRvbmx5IGZpbGVQYXR0ZXJuOiBzdHJpbmc7XG4gICAgcHVibGljIHJlYWRvbmx5IGVzYnVpbGRPcHRpb25zOiBCdWlsZE9wdGlvbnM7XG4gICAgcHVibGljIHJlYWRvbmx5IGJhc2VDb25zdHJ1Y3RJbXBvcnQ/OiBzdHJpbmc7XG4gICAgcHVibGljIHJlYWRvbmx5IGJhc2VDb25zdHJ1Y3RDbGFzcz86IHN0cmluZztcbiAgICBwdWJsaWMgcmVhZG9ubHkgYmFzZUNvbnN0cnVjdFBhY2thZ2U/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBub2RlUHJvamVjdDogTm9kZVByb2plY3Q7XG4gICAgcHJpdmF0ZSByZWFkb25seSBidW5kbGVyU2NyaXB0UGF0aDogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IocHJvamVjdDogTm9kZVByb2plY3QsIG9wdGlvbnM/OiBMYW1iZGFGdW5jdGlvbkNvbnN0cnVjdEdlbmVyYXRvck9wdGlvbnMpIHtcbiAgICAgICAgc3VwZXIocHJvamVjdCk7XG4gICAgICAgIHRoaXMubm9kZVByb2plY3QgPSBwcm9qZWN0O1xuICAgICAgICB0aGlzLnNvdXJjZURpciA9IG9wdGlvbnM/LnNvdXJjZURpciA/PyBcInNyYy9oYW5kbGVyc1wiO1xuICAgICAgICB0aGlzLm91dHB1dERpciA9IG9wdGlvbnM/Lm91dHB1dERpciA/PyBcInNyYy9jb25zdHJ1Y3RzL2xhbWJkYVwiO1xuICAgICAgICB0aGlzLmZpbGVQYXR0ZXJuID0gb3B0aW9ucz8uZmlsZVBhdHRlcm4gPz8gXCIqLmxhbWJkYS50c1wiO1xuICAgICAgICB0aGlzLmVzYnVpbGRPcHRpb25zID0gb3B0aW9ucz8uZXNidWlsZE9wdGlvbnMgPz8ge307XG4gICAgICAgIHRoaXMuYmFzZUNvbnN0cnVjdEltcG9ydCA9IG9wdGlvbnM/LmJhc2VDb25zdHJ1Y3RJbXBvcnQ7XG4gICAgICAgIHRoaXMuYmFzZUNvbnN0cnVjdENsYXNzID0gb3B0aW9ucz8uYmFzZUNvbnN0cnVjdENsYXNzO1xuICAgICAgICB0aGlzLmJhc2VDb25zdHJ1Y3RQYWNrYWdlID0gb3B0aW9ucz8uYmFzZUNvbnN0cnVjdFBhY2thZ2U7XG5cbiAgICAgICAgLy8gQ3JlYXRlIHVuaXF1ZSBzY3JpcHQgbmFtZSBiYXNlZCBvbiBzb3VyY2VEaXIgYW5kIGZpbGVQYXR0ZXJuXG4gICAgICAgIGNvbnN0IHVuaXF1ZUlkID0gdGhpcy5jcmVhdGVVbmlxdWVJZCh0aGlzLnNvdXJjZURpciwgdGhpcy5maWxlUGF0dGVybik7XG4gICAgICAgIHRoaXMuYnVuZGxlclNjcmlwdFBhdGggPSBwYXRoLmpvaW4oXCIucHJvamVuXCIsIGBnZW5lcmF0ZS1hbmQtYnVuZGxlLSR7dW5pcXVlSWR9LnRzYCk7XG5cbiAgICAgICAgLy8gQWRkIHJlcXVpcmVkIGRlcGVuZGVuY2llc1xuICAgICAgICBpZiAob3B0aW9ucz8uYWRkRGVwZW5kZW5jaWVzID8/IHRydWUpIHtcbiAgICAgICAgICAgIHRoaXMuYWRkRGVwZW5kZW5jaWVzKG9wdGlvbnM/LmJhc2VDb25zdHJ1Y3RQYWNrYWdlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgYnVuZGxlIHRhc2tcbiAgICAgICAgdGhpcy5jcmVhdGVCdW5kbGVUYXNrKCk7XG5cbiAgICAgICAgLy8gQWRkIHRoZSBidW5kbGUgdGFzayB0byB0aGUgYnVpbGQgd29ya2Zsb3dcbiAgICAgICAgdGhpcy5hZGRCdW5kbGVUYXNrVG9Xb3JrZmxvdygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCByZXF1aXJlZCBkZXBlbmRlbmNpZXMgZm9yIHRoZSBjb21wb25lbnRcbiAgICAgKi9cbiAgICBwcml2YXRlIGFkZERlcGVuZGVuY2llcyhhZGRpdGlvbmFsUGFja2FnZT86IHN0cmluZykge1xuICAgICAgICB0aGlzLm5vZGVQcm9qZWN0LmFkZERlcHMoXCJhd3MtY2RrLWxpYlwiLCBcImNvbnN0cnVjdHNcIik7XG5cbiAgICAgICAgaWYgKGFkZGl0aW9uYWxQYWNrYWdlICYmIGFkZGl0aW9uYWxQYWNrYWdlICE9PSBcImF3cy1jZGstbGliXCIgJiYgYWRkaXRpb25hbFBhY2thZ2UgIT09IFwiY29uc3RydWN0c1wiKSB7XG4gICAgICAgICAgICB0aGlzLm5vZGVQcm9qZWN0LmFkZERlcHMoYWRkaXRpb25hbFBhY2thZ2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgdW5pcXVlIElEIGJhc2VkIG9uIHNvdXJjZURpciBhbmQgZmlsZVBhdHRlcm5cbiAgICAgKi9cbiAgICBwcml2YXRlIGNyZWF0ZVVuaXF1ZUlkKHNvdXJjZURpcjogc3RyaW5nLCBmaWxlUGF0dGVybjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgLy8gUmVtb3ZlIHNwZWNpYWwgY2hhcmFjdGVycyBhbmQgY29udmVydCB0byBrZWJhYiBjYXNlXG4gICAgICAgIGNvbnN0IGRpclBhcnQgPSBzb3VyY2VEaXIucmVwbGFjZSgvXFwvL2csIFwiLVwiKS5yZXBsYWNlKC9bXlxcdy1dL2csIFwiXCIpO1xuICAgICAgICBjb25zdCBwYXR0ZXJuUGFydCA9IGZpbGVQYXR0ZXJuXG4gICAgICAgICAgICAucmVwbGFjZSgvXFwqL2csIFwiXCIpXG4gICAgICAgICAgICAucmVwbGFjZSgvXFwuL2csIFwiLVwiKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1teXFx3LV0vZywgXCJcIik7XG4gICAgICAgIHJldHVybiBgJHtkaXJQYXJ0fS0ke3BhdHRlcm5QYXJ0fWAucmVwbGFjZSgvLS0rL2csIFwiLVwiKS5yZXBsYWNlKC9eLXwtJC9nLCBcIlwiKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgdGhlIGJ1bmRsZSB0YXNrIHRoYXQgd2lsbCBiZSBleGVjdXRlZCBkdXJpbmcgcHJvamVuIGJ1aWxkXG4gICAgICovXG4gICAgcHJpdmF0ZSBjcmVhdGVCdW5kbGVUYXNrKCkge1xuICAgICAgICBjb25zdCB1bmlxdWVJZCA9IHRoaXMuY3JlYXRlVW5pcXVlSWQodGhpcy5zb3VyY2VEaXIsIHRoaXMuZmlsZVBhdHRlcm4pO1xuICAgICAgICBjb25zdCB0YXNrTmFtZSA9IGBnZW5lcmF0ZS1hbmQtYnVuZGxlLSR7dW5pcXVlSWR9YDtcblxuICAgICAgICBsZXQgYmFzZUNvbnN0cnVjdEFyZ3MgPSBcIlwiO1xuICAgICAgICBpZiAodGhpcy5iYXNlQ29uc3RydWN0SW1wb3J0KSB7XG4gICAgICAgICAgICBiYXNlQ29uc3RydWN0QXJncyArPSBgIC0tYmFzZS1jb25zdHJ1Y3QtaW1wb3J0ICcke3RoaXMuYmFzZUNvbnN0cnVjdEltcG9ydH0nYDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5iYXNlQ29uc3RydWN0Q2xhc3MpIHtcbiAgICAgICAgICAgIGJhc2VDb25zdHJ1Y3RBcmdzICs9IGAgLS1iYXNlLWNvbnN0cnVjdC1jbGFzcyAnJHt0aGlzLmJhc2VDb25zdHJ1Y3RDbGFzc30nYDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1bmRsZVRhc2sgPSB0aGlzLm5vZGVQcm9qZWN0LmFkZFRhc2sodGFza05hbWUsIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgR2VuZXJhdGUgTGFtYmRhIEZ1bmN0aW9uIENvbnN0cnVjdHMgZnJvbSAke3RoaXMuc291cmNlRGlyfS8ke3RoaXMuZmlsZVBhdHRlcm59IGFuZCBidW5kbGUgdGhlaXIgaGFuZGxlcnNgLFxuICAgICAgICAgICAgZXhlYzogYHRzeCAtLXRzY29uZmlnIHRzY29uZmlnLmRldi5qc29uICR7dGhpcy5idW5kbGVyU2NyaXB0UGF0aH0gLS1zb3VyY2UtZGlyICR7dGhpcy5zb3VyY2VEaXJ9IC0tb3V0cHV0LWRpciAke3RoaXMub3V0cHV0RGlyfSAtLWZpbGUtcGF0dGVybiBcIiR7dGhpcy5maWxlUGF0dGVybn1cIiAtLWVzYnVpbGQtb3B0aW9ucyAnJHtKU09OLnN0cmluZ2lmeSh0aGlzLmVzYnVpbGRPcHRpb25zKX0nJHtiYXNlQ29uc3RydWN0QXJnc31gLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBDcmVhdGUgdGhlIGJ1bmRsZXIgc2NyaXB0XG4gICAgICAgIHRoaXMuY3JlYXRlQnVuZGxlclNjcmlwdCgpO1xuXG4gICAgICAgIHJldHVybiBidW5kbGVUYXNrO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSB0aGUgYnVuZGxlciBzY3JpcHQgdGhhdCB3aWxsIGJlIGV4ZWN1dGVkIGJ5IHRoZSBidW5kbGUgdGFza1xuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlQnVuZGxlclNjcmlwdCgpIHtcbiAgICAgICAgY29uc3QgYnVuZGxlclNjcmlwdCA9IGAvLyB+fiBHZW5lcmF0ZWQgYnkgcHJvamVuLiBUbyBtb2RpZnksIGVkaXQgLnByb2plbnJjLnRzIGFuZCBydW4gXCJucHggcHJvamVuXCIuXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBlc2J1aWxkIGZyb20gJ2VzYnVpbGQnO1xuaW1wb3J0ICogYXMgZ2xvYiBmcm9tICdnbG9iJztcbmltcG9ydCB7IHBhc2NhbENhc2UgfSBmcm9tICdjaGFuZ2UtY2FzZSc7XG5pbXBvcnQgeWFyZ3MgZnJvbSAneWFyZ3MveWFyZ3MnO1xuaW1wb3J0IHsgaGlkZUJpbiB9IGZyb20gJ3lhcmdzL2hlbHBlcnMnO1xuXG5hc3luYyBmdW5jdGlvbiBtYWluKCkge1xuICBjb25zdCBhcmd2ID0gYXdhaXQgeWFyZ3MoaGlkZUJpbihwcm9jZXNzLmFyZ3YpKVxuICAgIC5vcHRpb24oJ3NvdXJjZS1kaXInLCB7IHR5cGU6ICdzdHJpbmcnLCBkZWZhdWx0OiAnc3JjL2hhbmRsZXJzJywgZGVzY3JpcHRpb246ICdTb3VyY2UgZGlyZWN0b3J5IHdoZXJlIExhbWJkYSBGdW5jdGlvbiBoYW5kbGVycyBhcmUgbG9jYXRlZCcgfSlcbiAgICAub3B0aW9uKCdvdXRwdXQtZGlyJywgeyB0eXBlOiAnc3RyaW5nJywgZGVmYXVsdDogJ3NyYy9jb25zdHJ1Y3RzL2xhbWJkYScsIGRlc2NyaXB0aW9uOiAnT3V0cHV0IGRpcmVjdG9yeSB3aGVyZSBMYW1iZGEgRnVuY3Rpb24gY29uc3RydWN0cyB3aWxsIGJlIGdlbmVyYXRlZCcgfSlcbiAgICAub3B0aW9uKCdmaWxlLXBhdHRlcm4nLCB7IHR5cGU6ICdzdHJpbmcnLCBkZWZhdWx0OiAnKi5sYW1iZGEudHMnLCBkZXNjcmlwdGlvbjogJ0ZpbGUgcGF0dGVybiB0byBpZGVudGlmeSBMYW1iZGEgRnVuY3Rpb24gaGFuZGxlcnMnIH0pXG4gICAgLm9wdGlvbignZXNidWlsZC1vcHRpb25zJywgeyB0eXBlOiAnc3RyaW5nJywgZGVmYXVsdDogJ3t9JywgZGVzY3JpcHRpb246ICdlc2J1aWxkIG9wdGlvbnMgYXMgSlNPTiBzdHJpbmcnIH0pXG4gICAgLm9wdGlvbignYmFzZS1jb25zdHJ1Y3QtaW1wb3J0JywgeyB0eXBlOiAnc3RyaW5nJywgZGVzY3JpcHRpb246ICdJbXBvcnQgc3RhdGVtZW50IGZvciB0aGUgYmFzZSBjb25zdHJ1Y3QnIH0pXG4gICAgLm9wdGlvbignYmFzZS1jb25zdHJ1Y3QtY2xhc3MnLCB7IHR5cGU6ICdzdHJpbmcnLCBkZXNjcmlwdGlvbjogJ05hbWUgb2YgdGhlIGNvbnN0cnVjdCBjbGFzcyB0byBleHRlbmQnIH0pXG4gICAgLmhlbHAoKVxuICAgIC5wYXJzZSgpO1xuXG4gIGNvbnN0IHNvdXJjZURpciA9IGFyZ3ZbJ3NvdXJjZS1kaXInXTtcbiAgY29uc3Qgb3V0cHV0RGlyID0gYXJndlsnb3V0cHV0LWRpciddO1xuICBjb25zdCBmaWxlUGF0dGVybiA9IGFyZ3ZbJ2ZpbGUtcGF0dGVybiddO1xuICBjb25zdCBlc2J1aWxkT3B0aW9ucyA9IEpTT04ucGFyc2UoYXJndlsnZXNidWlsZC1vcHRpb25zJ10gYXMgc3RyaW5nKTtcbiAgY29uc3QgYmFzZUNvbnN0cnVjdEltcG9ydCA9IGFyZ3ZbJ2Jhc2UtY29uc3RydWN0LWltcG9ydCddIGFzIHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgY29uc3QgYmFzZUNvbnN0cnVjdENsYXNzID0gYXJndlsnYmFzZS1jb25zdHJ1Y3QtY2xhc3MnXSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLy8gRW5zdXJlIG91dHB1dCBkaXJlY3RvcnkgZXhpc3RzXG4gIGZzLm1rZGlyU3luYyhwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgb3V0cHV0RGlyKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgLy8gRW5zdXJlIGFzc2V0cyBkaXJlY3RvcnkgZXhpc3RzXG4gIGNvbnN0IGFzc2V0c0RpciA9IHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAnYXNzZXRzJywgJ2hhbmRsZXJzJyk7XG4gIGZzLm1rZGlyU3luYyhhc3NldHNEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG4gIC8vIEZpbmQgYWxsIExhbWJkYSBGdW5jdGlvbiBoYW5kbGVyIGZpbGVzXG4gIGNvbnN0IGhhbmRsZXJGaWxlcyA9IGdsb2Iuc3luYyhwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgc291cmNlRGlyLCBmaWxlUGF0dGVybikpO1xuXG4gIGNvbnNvbGUubG9nKFxcYEZvdW5kIFxcJHtoYW5kbGVyRmlsZXMubGVuZ3RofSBMYW1iZGEgRnVuY3Rpb24gaGFuZGxlciBmaWxlc1xcYCk7XG5cbiAgLy8gUHJvY2VzcyBlYWNoIGhhbmRsZXIgZmlsZVxuICBmb3IgKGNvbnN0IGhhbmRsZXJGaWxlIG9mIGhhbmRsZXJGaWxlcykge1xuICAgIGNvbnN0IHJlbGF0aXZlUGF0aCA9IHBhdGgucmVsYXRpdmUocGF0aC5qb2luKHByb2Nlc3MuY3dkKCksIHNvdXJjZURpciksIGhhbmRsZXJGaWxlKTtcbiAgICBjb25zdCBmaWxlTmFtZSA9IHBhdGguYmFzZW5hbWUocmVsYXRpdmVQYXRoLCBwYXRoLmV4dG5hbWUocmVsYXRpdmVQYXRoKSk7XG4gICAgY29uc3QgZnVuY3Rpb25OYW1lID0gZmlsZU5hbWUucmVwbGFjZSgnLmxhbWJkYScsICcnKTtcblxuICAgIGNvbnNvbGUubG9nKFxcYFByb2Nlc3NpbmcgTGFtYmRhIEZ1bmN0aW9uIGhhbmRsZXI6IFxcJHtmdW5jdGlvbk5hbWV9XFxgKTtcblxuICAgIC8vIENyZWF0ZSBmdW5jdGlvbi1zcGVjaWZpYyBkaXJlY3RvcnlcbiAgICBjb25zdCBmdW5jdGlvbkRpciA9IHBhdGguam9pbihhc3NldHNEaXIsIGZ1bmN0aW9uTmFtZSk7XG4gICAgZnMubWtkaXJTeW5jKGZ1bmN0aW9uRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAgIC8vIEJ1bmRsZSB0aGUgaGFuZGxlciBjb2RlIHRvIGluZGV4LmpzIGluIHRoZSBmdW5jdGlvbiBkaXJlY3RvcnlcbiAgICBjb25zdCBvdXRmaWxlID0gcGF0aC5qb2luKGZ1bmN0aW9uRGlyLCAnaW5kZXguanMnKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBlc2J1aWxkLmJ1aWxkKHtcbiAgICAgICAgZW50cnlQb2ludHM6IFtoYW5kbGVyRmlsZV0sXG4gICAgICAgIGJ1bmRsZTogdHJ1ZSxcbiAgICAgICAgbWluaWZ5OiB0cnVlLFxuICAgICAgICBwbGF0Zm9ybTogJ25vZGUnLFxuICAgICAgICB0YXJnZXQ6ICdub2RlMTgnLFxuICAgICAgICBvdXRmaWxlLFxuICAgICAgICAuLi5lc2J1aWxkT3B0aW9ucyxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zb2xlLmxvZyhcXGBTdWNjZXNzZnVsbHkgYnVuZGxlZCBcXCR7ZnVuY3Rpb25OYW1lfSB0byBcXCR7b3V0ZmlsZX1cXGApO1xuXG4gICAgICAvLyBHZW5lcmF0ZSB0aGUgQ0RLIGNvbnN0cnVjdFxuICAgICAgY29uc3QgY29uc3RydWN0RmlsZVBhdGggPSBwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgb3V0cHV0RGlyLCBcXGBcXCR7ZnVuY3Rpb25OYW1lfS50c1xcYCk7XG4gICAgICBjb25zdCBjb25zdHJ1Y3RDb2RlID0gZ2VuZXJhdGVDb25zdHJ1Y3RDb2RlKGZ1bmN0aW9uTmFtZSwgcmVsYXRpdmVQYXRoLCBiYXNlQ29uc3RydWN0SW1wb3J0LCBiYXNlQ29uc3RydWN0Q2xhc3MpO1xuXG4gICAgICBmcy53cml0ZUZpbGVTeW5jKGNvbnN0cnVjdEZpbGVQYXRoLCBjb25zdHJ1Y3RDb2RlKTtcbiAgICAgIGNvbnNvbGUubG9nKFxcYEdlbmVyYXRlZCBjb25zdHJ1Y3QgYXQgXFwke2NvbnN0cnVjdEZpbGVQYXRofVxcYCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXFxgRXJyb3IgcHJvY2Vzc2luZyBcXCR7ZnVuY3Rpb25OYW1lfTpcXGAsIGVycm9yKTtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVDb25zdHJ1Y3RDb2RlKGZ1bmN0aW9uTmFtZTogc3RyaW5nLCBoYW5kbGVyUGF0aDogc3RyaW5nLCBiYXNlQ29uc3RydWN0SW1wb3J0Pzogc3RyaW5nLCBiYXNlQ29uc3RydWN0Q2xhc3M/OiBzdHJpbmcpIHtcbiAgY29uc3QgY29uc3RydWN0TmFtZSA9IFxcYFxcJHtwYXNjYWxDYXNlKGZ1bmN0aW9uTmFtZSl9RnVuY3Rpb25cXGA7XG5cbiAgLy8gRGVmYXVsdCB2YWx1ZXMgaWYgbm8gYmFzZUNvbnN0cnVjdCBpcyBwcm92aWRlZFxuICBjb25zdCBpbXBvcnRTdGF0ZW1lbnQgPSBiYXNlQ29uc3RydWN0SW1wb3J0ID8/IFwiXCI7XG4gIGNvbnN0IGJhc2VDbGFzc05hbWUgPSBiYXNlQ29uc3RydWN0Q2xhc3MgPz8gXCJhd3NfbGFtYmRhLkZ1bmN0aW9uXCI7XG5cbiAgLy8gRGV0ZXJtaW5lIGlmIHdlIG5lZWQgdG8gdXNlIGF3c19sYW1iZGEuUnVudGltZSBvciBub3QgYmFzZWQgb24gdGhlIGJhc2UgY2xhc3NcbiAgY29uc3QgdXNlQXdzTGFtYmRhUnVudGltZSA9ICFiYXNlQ29uc3RydWN0Q2xhc3MgfHwgYmFzZUNsYXNzTmFtZS5pbmNsdWRlcyhcIkZ1bmN0aW9uXCIpO1xuXG4gIHJldHVybiBcXGAvLyB+fiBHZW5lcmF0ZWQgYnkgcHJvamVuLiBUbyBtb2RpZnksIGVkaXQgLnByb2plbnJjLnRzIGFuZCBydW4gXCJucHggcHJvamVuXCIuXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcblxcJHtpbXBvcnRTdGF0ZW1lbnR9XG5pbXBvcnQgeyBhd3NfbGFtYmRhIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5cbi8vIEVTIE1vZHVsZSBjb21wYXRpYmlsaXR5XG5jb25zdCBfX2ZpbGVuYW1lID0gZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpO1xuY29uc3QgX19kaXJuYW1lID0gcGF0aC5kaXJuYW1lKF9fZmlsZW5hbWUpO1xuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIFxcJHtjb25zdHJ1Y3ROYW1lfVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFxcJHtjb25zdHJ1Y3ROYW1lfVByb3BzIGV4dGVuZHMgT21pdDxcXCR7YmFzZUNsYXNzTmFtZSA9PT0gXCJhd3NfbGFtYmRhLkZ1bmN0aW9uXCIgPyBcImF3c19sYW1iZGEuRnVuY3Rpb25Qcm9wc1wiIDogXFxgXFwke2Jhc2VDbGFzc05hbWV9UHJvcHNcXGB9LCAnY29kZSdcXCR7dXNlQXdzTGFtYmRhUnVudGltZSA/IFwiIHwgJ3J1bnRpbWUnXCIgOiBcIlwifSB8ICdoYW5kbGVyJz4ge1xuICBcXCR7dXNlQXdzTGFtYmRhUnVudGltZSA/IFxcYC8qKlxuICAgKiBPdmVycmlkZSB0aGUgZGVmYXVsdCBydW50aW1lXG4gICAqIEBkZWZhdWx0IG5vZGVqczIyLnhcbiAgICovXG4gIHJlYWRvbmx5IHJ1bnRpbWU/OiBhd3NfbGFtYmRhLlJ1bnRpbWU7XFxgIDogXCJcIn1cbn1cblxuLyoqXG4gKiBcXCR7Y29uc3RydWN0TmFtZX0gLSBMYW1iZGEgRnVuY3Rpb24gQ29uc3RydWN0IGZvciBcXCR7aGFuZGxlclBhdGh9XG4gKi9cbmV4cG9ydCBjbGFzcyBcXCR7Y29uc3RydWN0TmFtZX0gZXh0ZW5kcyBcXCR7YmFzZUNsYXNzTmFtZX0ge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogXFwke2NvbnN0cnVjdE5hbWV9UHJvcHMgPSB7fSkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwge1xuICAgICAgLi4ucHJvcHMsXG4gICAgICBcXCR7dXNlQXdzTGFtYmRhUnVudGltZSA/IFwicnVudGltZTogcHJvcHMucnVudGltZSA/PyBhd3NfbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzIyX1gsXCIgOiBcIlwifVxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgY29kZTogYXdzX2xhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vLi4vYXNzZXRzL2hhbmRsZXJzL1xcJHtmdW5jdGlvbk5hbWV9JykpLFxuICAgIH0pO1xuICB9XG59XG5cXGA7XG59XG5cbm1haW4oKS5jYXRjaChlcnJvciA9PiB7XG4gIGNvbnNvbGUuZXJyb3IoJ0Vycm9yOicsIGVycm9yKTtcbiAgcHJvY2Vzcy5leGl0KDEpO1xufSk7XG5gO1xuXG4gICAgICAgIC8vIENyZWF0ZSBzb3VyY2UgY29kZSBmaWxlIGFuZCBhZGQgY29kZSBsaW5lcyB0byBpdFxuICAgICAgICBjb25zdCBzcmMgPSBuZXcgU291cmNlQ29kZSh0aGlzLnByb2plY3QsIHRoaXMuYnVuZGxlclNjcmlwdFBhdGgpO1xuICAgICAgICBjb25zdCBsaW5lcyA9IGJ1bmRsZXJTY3JpcHQuc3BsaXQoXCJcXG5cIik7XG4gICAgICAgIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgICAgICAgc3JjLmxpbmUobGluZSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgdGhlIGRlcGVuZGVuY2llcyBuZWVkZWQgZm9yIHRoZSBidW5kbGVyIHNjcmlwdFxuICAgICAgICB0aGlzLm5vZGVQcm9qZWN0LmFkZERldkRlcHMoXCJlc2J1aWxkXCIsIFwiZ2xvYlwiLCBcInlhcmdzXCIsIFwiQHR5cGVzL2dsb2JcIiwgXCJAdHlwZXMveWFyZ3NcIiwgXCJ0c3hcIiwgXCJjaGFuZ2UtY2FzZVwiKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgdGhlIGJ1bmRsZSB0YXNrIHRvIHRoZSBidWlsZCB3b3JrZmxvd1xuICAgICAqL1xuICAgIHByaXZhdGUgYWRkQnVuZGxlVGFza1RvV29ya2Zsb3coKSB7XG4gICAgICAgIC8vIEdldCB0aGUgY29tcGlsZSB0YXNrXG4gICAgICAgIGNvbnN0IGNvbXBpbGVUYXNrID0gdGhpcy5ub2RlUHJvamVjdC50YXNrcy50cnlGaW5kKFwiY29tcGlsZVwiKTtcblxuICAgICAgICBpZiAoY29tcGlsZVRhc2spIHtcbiAgICAgICAgICAgIC8vIEFkZCB0aGUgYnVuZGxlIHRhc2sgYXMgYSBkZXBlbmRlbmN5IG9mIHRoZSBjb21waWxlIHRhc2tcbiAgICAgICAgICAgIGNvbnN0IHVuaXF1ZUlkID0gdGhpcy5jcmVhdGVVbmlxdWVJZCh0aGlzLnNvdXJjZURpciwgdGhpcy5maWxlUGF0dGVybik7XG4gICAgICAgICAgICBjb25zdCB0YXNrTmFtZSA9IGBnZW5lcmF0ZS1hbmQtYnVuZGxlLSR7dW5pcXVlSWR9YDtcbiAgICAgICAgICAgIGNvbnN0IGJ1bmRsZVRhc2sgPSB0aGlzLm5vZGVQcm9qZWN0LnRhc2tzLnRyeUZpbmQodGFza05hbWUpO1xuICAgICAgICAgICAgaWYgKGJ1bmRsZVRhc2spIHtcbiAgICAgICAgICAgICAgICBjb21waWxlVGFzay5wcmVwZW5kU3Bhd24oYnVuZGxlVGFzayk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG4iXX0=
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@nikovirtala/projen-lambda-function-construct-generator",
3
+ "description": "Projen component to generate AWS CDK Lambda Function Constructs and bundle their Code Assets",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/nikovirtala/projen-lambda-function-construct-generator.git"
7
+ },
8
+ "author": {
9
+ "name": "Niko Virtala",
10
+ "email": "niko.virtala@hey.com",
11
+ "organization": false
12
+ },
13
+ "devDependencies": {
14
+ "@mrgrain/cdk-esbuild": "^5.7.3",
15
+ "@nikovirtala/projen-vitest": "^2.1.1",
16
+ "@types/glob": "^8.1.0",
17
+ "@types/node": "ts5.9",
18
+ "@types/yargs": "^17.0.34",
19
+ "@typescript-eslint/eslint-plugin": "^8",
20
+ "@typescript-eslint/parser": "^8",
21
+ "@vitest/coverage-v8": "^4",
22
+ "change-case": "^5.4.4",
23
+ "commit-and-tag-version": "^12",
24
+ "constructs": "^10.4.3",
25
+ "esbuild": "^0.27.0",
26
+ "eslint": "^9",
27
+ "eslint-config-prettier": "^10.1.8",
28
+ "eslint-import-resolver-typescript": "^4.4.4",
29
+ "eslint-plugin-import": "^2.32.0",
30
+ "eslint-plugin-prettier": "^5.5.4",
31
+ "glob": "^10.4.5",
32
+ "jsii": "~5.9.3",
33
+ "jsii-diff": "^1.118.0",
34
+ "jsii-docgen": "^10.5.0",
35
+ "jsii-pacmak": "^1.118.0",
36
+ "jsii-rosetta": "~5.9.3",
37
+ "prettier": "^3.6.2",
38
+ "projen": "^0.98.10",
39
+ "ts-node": "^10.9.2",
40
+ "tsx": "^4.20.6",
41
+ "typescript": "5.9.3",
42
+ "vitest": "^4",
43
+ "yargs": "^17.7.2"
44
+ },
45
+ "peerDependencies": {
46
+ "@mrgrain/cdk-esbuild": "^5.7.3",
47
+ "aws-cdk-lib": "^2.222.0",
48
+ "constructs": "^10.4.3",
49
+ "projen": "^0.98.10"
50
+ },
51
+ "dependencies": {
52
+ "@mrgrain/cdk-esbuild": "^5.7.3",
53
+ "aws-cdk-lib": "^2.222.0",
54
+ "constructs": "^10.4.3",
55
+ "projen": "^0.98.10"
56
+ },
57
+ "main": "lib/index.js",
58
+ "license": "MIT",
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "version": "0.0.0",
63
+ "types": "lib/index.d.ts",
64
+ "stability": "stable",
65
+ "jsii": {
66
+ "outdir": "dist",
67
+ "targets": {},
68
+ "tsc": {
69
+ "outDir": "lib",
70
+ "rootDir": "src"
71
+ }
72
+ },
73
+ "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\".",
74
+ "scripts": {
75
+ "build": "npx projen build",
76
+ "bump": "npx projen bump",
77
+ "clobber": "npx projen clobber",
78
+ "compat": "npx projen compat",
79
+ "compile": "npx projen compile",
80
+ "default": "npx projen default",
81
+ "docgen": "npx projen docgen",
82
+ "eject": "npx projen eject",
83
+ "eslint": "npx projen eslint",
84
+ "package": "npx projen package",
85
+ "package-all": "npx projen package-all",
86
+ "package:js": "npx projen package:js",
87
+ "post-compile": "npx projen post-compile",
88
+ "post-upgrade": "npx projen post-upgrade",
89
+ "pre-compile": "npx projen pre-compile",
90
+ "release": "npx projen release",
91
+ "test": "npx projen test",
92
+ "test:update": "npx projen test:update",
93
+ "test:watch": "npx projen test:watch",
94
+ "unbump": "npx projen unbump",
95
+ "upgrade": "npx projen upgrade",
96
+ "watch": "npx projen watch",
97
+ "projen": "npx projen"
98
+ }
99
+ }