From ce7b5754f7a007470d91ed856df4a311c397f5cb Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 11:43:12 +0200 Subject: [PATCH 01/16] feat(aws-cdk-lib): reduce load time of JavaScript library This change halves the load time of `require('aws-cdk-lib')`, from ~600ms to ~300ms on my machine. It also shaves ~8min off running all integ tests (again, on my machine). It does this by making all loading of JavaScript modules lazy, so they are only loaded just before any symbols from them are actually accessed (instead of loading all modules at startup). --- packages/aws-cdk-lib/package.json | 4 +- packages/aws-cdk-lib/scripts/lazy-import.ts | 186 ++++++++++++++++ tools/@aws-cdk/lazify/.gitignore | 15 ++ tools/@aws-cdk/lazify/LICENSE | 202 ++++++++++++++++++ tools/@aws-cdk/lazify/README.md | 85 ++++++++ tools/@aws-cdk/lazify/bin/lazify | 2 + tools/@aws-cdk/lazify/bin/lazify.ts | 38 ++++ tools/@aws-cdk/lazify/jest.config.js | 2 + tools/@aws-cdk/lazify/lib/index.d.ts | 4 + tools/@aws-cdk/lazify/lib/index.js | 162 ++++++++++++++ tools/@aws-cdk/lazify/lib/index.ts | 190 ++++++++++++++++ tools/@aws-cdk/lazify/package.json | 32 +++ .../@aws-cdk/lazify/test/export-star.test.ts | 22 ++ .../lazify/test/transform-require.test.ts | 64 ++++++ tools/@aws-cdk/lazify/tsconfig.json | 33 +++ 15 files changed, 1040 insertions(+), 1 deletion(-) create mode 100644 packages/aws-cdk-lib/scripts/lazy-import.ts create mode 100644 tools/@aws-cdk/lazify/.gitignore create mode 100644 tools/@aws-cdk/lazify/LICENSE create mode 100644 tools/@aws-cdk/lazify/README.md create mode 100755 tools/@aws-cdk/lazify/bin/lazify create mode 100644 tools/@aws-cdk/lazify/bin/lazify.ts create mode 100644 tools/@aws-cdk/lazify/jest.config.js create mode 100644 tools/@aws-cdk/lazify/lib/index.d.ts create mode 100644 tools/@aws-cdk/lazify/lib/index.js create mode 100644 tools/@aws-cdk/lazify/lib/index.ts create mode 100644 tools/@aws-cdk/lazify/package.json create mode 100644 tools/@aws-cdk/lazify/test/export-star.test.ts create mode 100644 tools/@aws-cdk/lazify/test/transform-require.test.ts create mode 100644 tools/@aws-cdk/lazify/tsconfig.json diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 0de9bb88162ff..c43a2c1b4a439 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", + "lazify ." ] }, "cdk-package": { @@ -166,6 +167,7 @@ "@types/jest": "^29.5.4", "@types/lodash": "^4.14.198", "@types/punycode": "^2.1.0", + "@aws-cdk/lazify": "0.0.0", "aws-sdk": "^2.1451.0", "aws-sdk-client-mock": "^3.0.0", "aws-sdk-client-mock-jest": "^3.0.0", diff --git a/packages/aws-cdk-lib/scripts/lazy-import.ts b/packages/aws-cdk-lib/scripts/lazy-import.ts new file mode 100644 index 0000000000000..6bb4adebd6f0a --- /dev/null +++ b/packages/aws-cdk-lib/scripts/lazy-import.ts @@ -0,0 +1,186 @@ +import { promises as fs } from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; + +function progress(...x: string[]) { + process.stderr.write(x.join(' ')); +} + +async function main(args: string[]) { + for (const arg of args) { + await transform(arg); + } +} + +async function transform(filename: string) { + if (!(await fs.stat(filename)).isFile()) { + return; + } + + progress(filename, '... '); + const sourceFile = ts.createSourceFile( + filename, + await fs.readFile(filename, { encoding: 'utf-8' }), + 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 + 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 } + ); + // We should also ignore this identifier if it is shadowed + // 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) => + factory.createExpressionStatement(factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), + undefined, + [ + factory.createIdentifier('exports'), + factory.createStringLiteral(entry), + factory.createObjectLiteralExpression([ + factory.createPropertyAssignment('configurable', factory.createTrue()), + factory.createPropertyAssignment('get', + factory.createArrowFunction(undefined, undefined, [], undefined, undefined, + factory.createPropertyAccessExpression( + factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), + entry))) + ]), + ] + ))); + } + + 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 }); + + await fs.writeFile(filename, printer.printFile(file), { encoding: 'utf-8' }); + progress(' Done!\n'); +} + +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)); +} + + +main(process.argv.slice(2)).catch((e) => { + console.error(e); + process.exitCode = 1; +}); \ No newline at end of file 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..13929817a739f --- /dev/null +++ b/tools/@aws-cdk/lazify/bin/lazify.ts @@ -0,0 +1,38 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { transformFile } from '../lib'; + +async function main() { + const args = process.argv.slice(2); + + 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); + } + }); + } +} + +async function recurseJs(root: string, block: (x: string) => Promise) { + return recurse(root); + + async function recurse(f: string) { + const s = await fs.stat(f); + if (s.isFile() && f.endsWith('.js')) { + await block(f); + } + if (s.isDirectory() && path.basename(f) !== 'node_modules') { + 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.d.ts b/tools/@aws-cdk/lazify/lib/index.d.ts new file mode 100644 index 0000000000000..56a55a6f8d38a --- /dev/null +++ b/tools/@aws-cdk/lazify/lib/index.d.ts @@ -0,0 +1,4 @@ +type LogFn = (...x: string[]) => void; +export declare function transformFile(filename: string): Promise; +export declare function transformFileContents(filename: string, contents: string, progress?: LogFn): string; +export {}; diff --git a/tools/@aws-cdk/lazify/lib/index.js b/tools/@aws-cdk/lazify/lib/index.js new file mode 100644 index 0000000000000..47a0d393f68b4 --- /dev/null +++ b/tools/@aws-cdk/lazify/lib/index.js @@ -0,0 +1,162 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.transformFileContents = exports.transformFile = void 0; +/** + * 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. + */ +const fs_1 = require("fs"); +const path = __importStar(require("path")); +const ts = __importStar(require("typescript")); +async function transformFile(filename) { + progress(filename, '... '); + const contents = await fs_1.promises.readFile(filename, { encoding: 'utf-8' }); + const transformed = transformFileContents(filename, contents, progress); + await fs_1.promises.writeFile(filename, transformed, { encoding: 'utf-8' }); + progress(' Done!\n'); + function progress(...x) { + process.stderr.write(x.join(' ')); + } +} +exports.transformFile = transformFile; +function transformFileContents(filename, contents, progress) { + 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]]); + progress === null || progress === void 0 ? void 0 : 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]] : []); + progress === null || progress === void 0 ? void 0 : progress(`${topLevelRequires.length} requires`, '... '); + let file = sourceFile; + for (const [stmt, binding, moduleName] of topLevelRequires) { + const result = ts.transform(file, [(ctx) => { + const factory = ctx.factory; + const visit = node => { + // If this is the statement, replace it with a function definition + 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 } + ); + // We should also ignore this identifier if it is shadowed + // 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) => { var _a; return (_a = ts.visitNode(sf, visit, ts.isSourceFile)) !== null && _a !== void 0 ? _a : sf; }; + }]); + file = result.transformed[0]; + progress === null || progress === void 0 ? void 0 : progress('X'); + } + // Replace __exportStar + file = ts.transform(file, [(ctx) => { + const factory = ctx.factory; + const visit = 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) => factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), undefined, [ + factory.createIdentifier('exports'), + factory.createStringLiteral(entry), + factory.createObjectLiteralExpression([ + factory.createPropertyAssignment('configurable', factory.createTrue()), + factory.createPropertyAssignment('get', factory.createArrowFunction(undefined, undefined, [], undefined, undefined, factory.createPropertyAccessExpression(factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), entry))) + ]), + ]))); + } + return ts.visitEachChild(node, child => visit(child), ctx); + }; + return (sf) => { var _a; return (_a = ts.visitNode(sf, visit, ts.isSourceFile)) !== null && _a !== void 0 ? _a : 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); +} +exports.transformFileContents = transformFileContents; +function createVariable(factory, name, expression) { + return factory.createVariableStatement([], factory.createVariableDeclarationList([ + factory.createVariableDeclaration(name, undefined, undefined, expression), + ])); +} +function createAssignment(factory, name, expression) { + return factory.createExpressionStatement(factory.createBinaryExpression(factory.createIdentifier(name), ts.SyntaxKind.EqualsToken, expression)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsMkJBQW9DO0FBQ3BDLDJDQUE2QjtBQUM3QiwrQ0FBaUM7QUFJMUIsS0FBSyxVQUFVLGFBQWEsQ0FBQyxRQUFnQjtJQUNsRCxRQUFRLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzNCLE1BQU0sUUFBUSxHQUFHLE1BQU0sYUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNwRSxNQUFNLFdBQVcsR0FBRyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sYUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsV0FBVyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDakUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRXJCLFNBQVMsUUFBUSxDQUFDLEdBQUcsQ0FBVztRQUM5QixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztBQUNILENBQUM7QUFWRCxzQ0FVQztBQUVELFNBQWdCLHFCQUFxQixDQUFDLFFBQWdCLEVBQUUsUUFBZ0IsRUFBRSxRQUFnQjtJQUN4RixNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQ3BDLFFBQVEsRUFDUixRQUFRLEVBQ1IsRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQ3RCLElBQUksQ0FBQyw4Q0FBOEM7S0FDcEQsQ0FBQztJQUVGLDREQUE0RDtJQUM1RCxNQUFNLG1CQUFtQixHQUFHLFVBQVUsQ0FBQyxVQUFVO1NBQzlDLE1BQU0s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QyxVQUFVLENBQUMsV0FBVyxFQUN6QixVQUFVLENBQUMsQ0FBQyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRyYW5zZm9ybSBhIHNldCBvZiAuanMgZmlsZXMsIG1ha2luZyBhbGwgbW9kdWxlIGltcG9ydHMgbGF6eVxuICpcbiAqIFRoYXQgaXM6XG4gKlxuICogLSBGaW5kIGFsbCB0b3AtbGV2ZWwgcmVxdWlyZSgpIGFzc2lnbm1lbnRzLCBhbmQgcmVwbGFjZSB0aGVtIHdpdGggYSBmdW5jdGlvbiB0aGF0IHBlcmZvcm1zXG4gKiAgIHRoZSByZXF1aXJlKCkuIFRoYXQgd2F5LCB0aGUgcmVxdWlyZSgpIGlzIG9ubHkgZG9uZSBpZiBhbnkgb2YgdGhlIG9iamVjdHMgZnJvbSBpdHMgc2NvcGVcbiAqICAgYXJlIGFjdHVhbGx5IHVzZWQuXG4gKiAtIEZpbmQgYWxsICh0cmFuc3BpbGVkKSBgZXhwb3J0ICogZnJvbSAneHl6JztgIHN0YXRlbWVudHMgKGJ5IHNlYXJjaGluZyBmb3IgYW4gaW52b2NhdGlvblxuICogICBvZiBgX19leHBvcnRTdGFyKClgKTogbG9hZCB0aGUgYWN0dWFsIG1vZHVsZSwgZW51bWVyYXRlIHRoZSBlbnRyaWVzLCBhbmQgY3JlYXRlIGEgZ2V0dGVyXG4gKiAgIGZvciBlYWNoIGVudHJ5LlxuICovXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyB0cyBmcm9tICd0eXBlc2NyaXB0JztcblxudHlwZSBMb2dGbiA9ICguLi54OiBzdHJpbmdbXSkgPT4gdm9pZDtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyYW5zZm9ybUZpbGUoZmlsZW5hbWU6IHN0cmluZykge1xuICBwcm9ncmVzcyhmaWxlbmFtZSwgJy4uLiAnKTtcbiAgY29uc3QgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlbmFtZSwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgY29uc3QgdHJhbnNmb3JtZWQgPSB0cmFuc2Zvcm1GaWxlQ29udGVudHMoZmlsZW5hbWUsIGNvbnRlbnRzLCBwcm9ncmVzcyk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShmaWxlbmFtZSwgdHJhbnNmb3JtZWQsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gIHByb2dyZXNzKCcgRG9uZSFcXG4nKTtcblxuICBmdW5jdGlvbiBwcm9ncmVzcyguLi54OiBzdHJpbmdbXSkge1xuICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKHguam9pbignICcpKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNmb3JtRmlsZUNvbnRlbnRzKGZpbGVuYW1lOiBzdHJpbmcsIGNvbnRlbnRzOiBzdHJpbmcsIHByb2dyZXNzPzogTG9nRm4pIHtcbiAgY29uc3Qgc291cmNlRmlsZSA9IHRzLmNyZWF0ZVNvdXJjZUZpbGUoXG4gICAgZmlsZW5hbWUsXG4gICAgY29udGVudHMsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlIC8vIHNldFBhcmVudE5vZGVzLCBuZWVkIHRoaXMgZm9yIHRyZWUgYW5hbHlzaXNcbiAgKTtcblxuICAvLyBGaW5kIGFsbCB0b3AtbGV2ZWwgcmVxdWlyZXMgYW5kIHR1cm4gdGhlbSBpbnRvIGEgZnVuY3Rpb25cbiAgY29uc3QgdG9wTGV2ZWxBc3NpZ25tZW50cyA9IHNvdXJjZUZpbGUuc3RhdGVtZW50c1xuICAgIC5maWx0ZXIodHMuaXNWYXJpYWJsZVN0YXRlbWVudClcbiAgICAuZmlsdGVyKChzdG10KSA9PiBzdG10LmRlY2xhcmF0aW9uTGlzdC5kZWNsYXJhdGlvbnMubGVuZ3RoID09PSAxKVxuICAgIC5tYXAoKHN0bXQpID0+IFtzdG10LCBzdG10LmRlY2xhcmF0aW9uTGlzdC5kZWNsYXJhdGlvbnNbMF1dIGFzIGNvbnN0KTtcblxuICBwcm9ncmVzcz8uKGAke3RvcExldmVsQXNzaWdubWVudHMubGVuZ3RofSBkZWNsYXJhdGlvbnNgLCAnLi4uICcpO1xuXG4gIGNvbnN0IHRvcExldmVsUmVxdWlyZXMgPSB0b3BMZXZlbEFzc2lnbm1lbnRzXG4gICAgLmZsYXRNYXAoKFtzdG10LCBhXSkgPT4gYS5pbml0aWFsaXplciAmJiB0cy5pc0NhbGxFeHByZXNzaW9uKGEuaW5pdGlhbGl6ZXIpXG4gICAgICAmJiB0cy5pc0lkZW50aWZpZXIoYS5pbml0aWFsaXplci5leHByZXNzaW9uKSAmJiBhLmluaXRpYWxpemVyLmV4cHJlc3Npb24udGV4dCA9PT0gJ3JlcXVpcmUnXG4gICAgICAmJiB0cy5pc1N0cmluZ0xpdGVyYWwoYS5pbml0aWFsaXplci5hcmd1bWVudHNbMF0pXG4gICAgICAmJiB0cy5pc0lkZW50aWZpZXIoYS5uYW1lKVxuICAgICAgPyBbW3N0bXQsIGEubmFtZSwgYS5pbml0aWFsaXplci5hcmd1bWVudHNbMF0udGV4dF0gYXMgY29uc3RdIDogW10pO1xuXG4gIHByb2dyZXNzPy4oYCR7dG9wTGV2ZWxSZXF1aXJlcy5sZW5ndGh9IHJlcXVpcmVzYCwgJy4uLiAnKTtcblxuICBsZXQgZmlsZSA9IHNvdXJjZUZpbGU7XG5cbiAgZm9yIChjb25zdCBbc3RtdCwgYmluZGluZywgbW9kdWxlTmFtZV0gb2YgdG9wTGV2ZWxSZXF1aXJlcykge1xuICAgIGNvbnN0IHJlc3VsdCA9IHRzLnRyYW5zZm9ybShmaWxlLCBbKGN0eDogdHMuVHJhbnNmb3JtYXRpb25Db250ZXh0KTogdHMuVHJhbnNmb3JtZXI8dHMuU291cmNlRmlsZT4gPT4ge1xuICAgICAgY29uc3QgZmFjdG9yeSA9IGN0eC5mYWN0b3J5O1xuICAgICAgY29uc3QgdmlzaXQ6IHRzLlZpc2l0b3IgPSBub2RlID0+IHtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyB0aGUgc3RhdGVtZW50LCByZXBsYWNlIGl0IHdpdGggYSBmdW5jdGlvbiBkZWZpbml0aW9uXG4gICAgICAgIGlmIChub2RlID09PSBzdG10KSB7XG4gICAgICAgICAgcmV0dXJuIGNyZWF0ZVZhcmlhYmxlKGZhY3RvcnksIGJpbmRpbmcsXG4gICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUFycm93RnVuY3Rpb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFtdLCB1bmRlZmluZWQsIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVCbG9jayhbXG4gICAgICAgICAgICAgICAgLy8gdG1wID0gcmVxdWlyZSguLi4pXG4gICAgICAgICAgICAgICAgY3JlYXRlVmFyaWFibGUoZmFjdG9yeSwgJ3RtcCcsIGZhY3RvcnkuY3JlYXRlQ2FsbEV4cHJlc3Npb24oZmFjdG9yeS5jcmVhdGVJZGVudGlmaWVyKCdyZXF1aXJlJyksIFtdLCBbZmFjdG9yeS5jcmVhdGVTdHJpbmdMaXRlcmFsKG1vZHVsZU5hbWUpXSkpLFxuXG4gICAgICAgICAgICAgICAgLy8gPHRoaXNfZm4+ID0gKCkgPT4gdG1wXG4gICAgICAgICAgICAgICAgY3JlYXRlQXNzaWdubWVudChmYWN0b3J5LCBiaW5kaW5nLnRleHQsXG4gICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUFycm93RnVuY3Rpb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFtdLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgZmFjdG9yeS5jcmVhdGVJZGVudGlmaWVyKCd0bXAnKSkpLFxuXG4gICAgICAgICAgICAgICAgLy8gcmV0dXJuIHRtcFxuICAgICAgICAgICAgICAgIGZhY3RvcnkuY3JlYXRlUmV0dXJuU3RhdGVtZW50KGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcigndG1wJykpLFxuICAgICAgICAgICAgICBdKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBzaG9ydGhhbmQgcHJvcGVydHkgYXNzaWdubWVudCBhbmQgd2Ugd2UgYXJlIHRoZSBpZGVudGlmaWVyIGluIGl0LCBzcGxpdCBpdCBpbnRvIHR3b1xuICAgICAgICBpZiAodHMuaXNTaG9ydGhhbmRQcm9wZXJ0eUFzc2lnbm1lbnQobm9kZSkgJiYgdHMuaXNJZGVudGlmaWVyKG5vZGUubmFtZSkgJiYgbm9kZS5uYW1lLnRleHQgPT09IGJpbmRpbmcudGV4dCkge1xuICAgICAgICAgIHJldHVybiBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QXNzaWdubWVudChub2RlLm5hbWUudGV4dCwgZmFjdG9yeS5jcmVhdGVDYWxsRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoYmluZGluZy50ZXh0KSwgW10sIFtdKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB0aGlzIHdhcyBhbiBpZGVudGlmaWVyIHJlZmVyZW5jaW5nIHRoZSBvcmlnaW5hbCByZXF1aXJlZCBtb2R1bGUsIHR1cm4gaXQgaW50byBhIGZ1bmN0aW9uIGNhbGxcbiAgICAgICAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSAmJiBub2RlLnRleHQgPT09IGJpbmRpbmcudGV4dCkge1xuXG4gICAgICAgICAgLy8gSWdub3JlIHRoaXMgaWRlbnRpZmllciBpZiBpdCBpcyBub3QgaW4gUkhTIHBvc2l0aW9uXG4gICAgICAgICAgY29uc3QgaWdub3JlID0gbm9kZS5wYXJlbnQgJiYgKFxuICAgICAgICAgICAgKHRzLmlzUHJvcGVydHlBc3NpZ25tZW50KG5vZGUucGFyZW50KSAmJiBub2RlLnBhcmVudC5uYW1lID09PSBub2RlKSAgLy8geyBpZGVudDogdmFsdWUgfVxuICAgICAgICAgICAgfHwgKHRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKG5vZGUucGFyZW50KSAmJiBub2RlLnBhcmVudC5uYW1lID09PSBub2RlKSAvLyBvYmouaWRlbnQgPSAzO1xuICAgICAgICAgICAgfHwgdHMuaXNNZXRob2REZWNsYXJhdGlvbihub2RlLnBhcmVudCkgLy8gcHVibGljIGlkZW50KCkgeyAuLi4gfVxuICAgICAgICAgICAgfHwgdHMuaXNNZXRob2RTaWduYXR1cmUobm9kZS5wYXJlbnQpIC8vIGludGVyZmFjZSBYIHsgaWRlbnQoKTsgfVxuICAgICAgICAgICAgfHwgdHMuaXNQcm9wZXJ0eURlY2xhcmF0aW9uKG5vZGUucGFyZW50KSAvLyBjbGFzcyBYIHsgaWRlbnQ6IHN0cmluZyB9XG4gICAgICAgICAgICB8fCB0cy5pc1Byb3BlcnR5U2lnbmF0dXJlKG5vZGUucGFyZW50KSAvLyBpbnRlcmZhY2UgWCB7IGlkZW50OiBzdHJpbmcgfVxuICAgICAgICAgICAgfHwgdHMuaXNHZXRBY2Nlc3Nvcihub2RlLnBhcmVudCkgLy8gY2xhc3MgWCB7IGdldCBpZGVudCgpIHsgLi4uIH0gfVxuICAgICAgICAgICAgfHwgdHMuaXNHZXRBY2Nlc3NvckRlY2xhcmF0aW9uKG5vZGUucGFyZW50KSAvLyBpbnRlcmZhY2UgWCB7IGdldCBpZGVudDogc3RyaW5nIH1cbiAgICAgICAgICAgIHx8IHRzLmlzU2V0QWNjZXNzb3Iobm9kZS5wYXJlbnQpIC8vIGNsYXNzIFggeyBzZXQgaWRlbnQoKSB7IC4uLiB9IH1cbiAgICAgICAgICAgIHx8IHRzLmlzU2V0QWNjZXNzb3JEZWNsYXJhdGlvbihub2RlLnBhcmVudCkgLy8gaW50ZXJmYWNlIFggeyBzZXQgaWRlbnQ6IHN0cmluZyB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBXZSBzaG91bGQgYWxzbyBpZ25vcmUgdGhpcyBpZGVudGlmaWVyIGlmIGl0IGlzIHNoYWRvd2VkXG4gICAgICAgICAgLy8gTW9yZSBwbGFjZXMgYXJlIGFsc28gbm90IFJIUyBidXQgaWYgd2UgbGVhdmUgdGhvc2UsIGl0J2xsIGJsb3cgdXAgc3ludGFjdGljYWxseSBhbmQgdGhhdCdzIGdvb2RcblxuICAgICAgICAgIGlmICghaWdub3JlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFjdG9yeS5jcmVhdGVDYWxsRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoYmluZGluZy50ZXh0KSwgW10sIFtdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHMudmlzaXRFYWNoQ2hpbGQobm9kZSwgY2hpbGQgPT4gdmlzaXQoY2hpbGQpLCBjdHgpO1xuICAgICAgfTtcblxuICAgICAgcmV0dXJuIChzZjogdHMuU291cmNlRmlsZSkgPT4gdHMudmlzaXROb2RlKHNmLCB2aXNpdCwgdHMuaXNTb3VyY2VGaWxlKSA/PyBzZjtcbiAgICB9XSk7XG5cbiAgICBmaWxlID0gcmVzdWx0LnRyYW5zZm9ybWVkWzBdO1xuICAgIHByb2dyZXNzPy4oJ1gnKTtcbiAgfVxuXG4gIC8vIFJlcGxhY2UgX19leHBvcnRTdGFyXG5cbiAgZmlsZSA9IHRzLnRyYW5zZm9ybShmaWxlLCBbKGN0eDogdHMuVHJhbnNmb3JtYXRpb25Db250ZXh0KTogdHMuVHJhbnNmb3JtZXI8dHMuU291cmNlRmlsZT4gPT4ge1xuICAgIGNvbnN0IGZhY3RvcnkgPSBjdHguZmFjdG9yeTtcbiAgICBjb25zdCB2aXNpdDogdHMuVmlzaXRvciA9IG5vZGUgPT4ge1xuICAgICAgaWYgKG5vZGUucGFyZW50ICYmIHRzLmlzU291cmNlRmlsZShub2RlLnBhcmVudClcbiAgICAgICAgJiYgdHMuaXNFeHByZXNzaW9uU3RhdGVtZW50KG5vZGUpXG4gICAgICAgICYmIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKVxuICAgICAgICAmJiB0cy5pc0lkZW50aWZpZXIobm9kZS5leHByZXNzaW9uLmV4cHJlc3Npb24pXG4gICAgICAgICYmIG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uLnRleHQgPT09ICdfX2V4cG9ydFN0YXInXG4gICAgICAgICYmIG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHMubGVuZ3RoID09PSAyXG4gICAgICAgICYmIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXSlcbiAgICAgICAgJiYgdHMuaXNJZGVudGlmaWVyKG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHNbMF0uZXhwcmVzc2lvbilcbiAgICAgICAgJiYgbm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXS5leHByZXNzaW9uLnRleHQgPT09ICdyZXF1aXJlJ1xuICAgICAgICAmJiB0cy5pc1N0cmluZ0xpdGVyYWwobm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXS5hcmd1bWVudHNbMF0pKSB7XG4gICAgICAgICAgLy8gX19leHBvcnRTdGFyKHJlcXVpcmUoJ3NvbWV0aGluZycpLCBleHBvcnRzKTtcblxuICAgICAgICBjb25zdCByZXF1aXJlZE1vZHVsZSA9IG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHNbMF0uYXJndW1lbnRzWzBdLnRleHQ7XG5cbiAgICAgICAgY29uc3QgZmlsZSA9IHJlcXVpcmUucmVzb2x2ZShyZXF1aXJlZE1vZHVsZSwgeyBwYXRoczogW3BhdGguZGlybmFtZShmaWxlbmFtZSldIH0pO1xuICAgICAgICAvLyBGSVhNRTogU2hvdWxkIHByb2JhYmx5IGRvIHRoaXMgaW4gYSBzdWJwcm9jZXNzXG4gICAgICAgIGNvbnN0IG1vZHVsZSA9IHJlcXVpcmUoZmlsZSk7XG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3Qua2V5cyhtb2R1bGUpO1xuXG4gICAgICAgIHJldHVybiBlbnRyaWVzLm1hcCgoZW50cnkpID0+XG4gICAgICAgICAgZmFjdG9yeS5jcmVhdGVFeHByZXNzaW9uU3RhdGVtZW50KGZhY3RvcnkuY3JlYXRlQ2FsbEV4cHJlc3Npb24oXG4gICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ09iamVjdCcpLCBmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ2RlZmluZVByb3BlcnR5JykpLFxuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgW1xuICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ2V4cG9ydHMnKSxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVTdHJpbmdMaXRlcmFsKGVudHJ5KSxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVPYmplY3RMaXRlcmFsRXhwcmVzc2lvbihbXG4gICAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVQcm9wZXJ0eUFzc2lnbm1lbnQoJ2NvbmZpZ3VyYWJsZScsIGZhY3RvcnkuY3JlYXRlVHJ1ZSgpKSxcbiAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QXNzaWdubWVudCgnZ2V0JyxcbiAgICAgICAgICAgICAgICAgIGZhY3RvcnkuY3JlYXRlQXJyb3dGdW5jdGlvbih1bmRlZmluZWQsIHVuZGVmaW5lZCwgW10sIHVuZGVmaW5lZCwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihcbiAgICAgICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUNhbGxFeHByZXNzaW9uKGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcigncmVxdWlyZScpLCB1bmRlZmluZWQsIFtmYWN0b3J5LmNyZWF0ZVN0cmluZ0xpdGVyYWwocmVxdWlyZWRNb2R1bGUpXSksXG4gICAgICAgICAgICAgICAgICAgICAgZW50cnkpKSlcbiAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICBdXG4gICAgICAgICAgKSkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHMudmlzaXRFYWNoQ2hpbGQobm9kZSwgY2hpbGQgPT4gdmlzaXQoY2hpbGQpLCBjdHgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gKHNmOiB0cy5Tb3VyY2VGaWxlKSA9PiB0cy52aXNpdE5vZGUoc2YsIHZpc2l0LCB0cy5pc1NvdXJjZUZpbGUpID8/IHNmO1xuICB9XSkudHJhbnNmb3JtZWRbMF07XG5cblxuXG4gIC8vIFRvIHByaW50IHRoZSBBU1QsIHdlJ2xsIHVzZSBUeXBlU2NyaXB0J3MgcHJpbnRlclxuICBjb25zdCBwcmludGVyID0gdHMuY3JlYXRlUHJpbnRlcih7IG5ld0xpbmU6IHRzLk5ld0xpbmVLaW5kLkxpbmVGZWVkIH0pO1xuXG4gIHJldHVybiBwcmludGVyLnByaW50RmlsZShmaWxlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlVmFyaWFibGUoZmFjdG9yeTogdHMuTm9kZUZhY3RvcnksIG5hbWU6IHN0cmluZyB8IHRzLkJpbmRpbmdOYW1lLCBleHByZXNzaW9uOiB0cy5FeHByZXNzaW9uKSB7XG4gIHJldHVybiBmYWN0b3J5LmNyZWF0ZVZhcmlhYmxlU3RhdGVtZW50KFtdLFxuICAgIGZhY3RvcnkuY3JlYXRlVmFyaWFibGVEZWNsYXJhdGlvbkxpc3QoW1xuICAgICAgZmFjdG9yeS5jcmVhdGVWYXJpYWJsZURlY2xhcmF0aW9uKG5hbWUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBleHByZXNzaW9uKSxcbiAgICBdKSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFzc2lnbm1lbnQoZmFjdG9yeTogdHMuTm9kZUZhY3RvcnksIG5hbWU6IHN0cmluZywgZXhwcmVzc2lvbjogdHMuRXhwcmVzc2lvbikge1xuICByZXR1cm4gZmFjdG9yeS5jcmVhdGVFeHByZXNzaW9uU3RhdGVtZW50KFxuICAgIGZhY3RvcnkuY3JlYXRlQmluYXJ5RXhwcmVzc2lvbihcbiAgICAgIGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcihuYW1lKSxcbiAgICAgIHRzLlN5bnRheEtpbmQuRXF1YWxzVG9rZW4sXG4gICAgICBleHByZXNzaW9uKSk7XG59Il19 \ 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..b62ca9c322e87 --- /dev/null +++ b/tools/@aws-cdk/lazify/lib/index.ts @@ -0,0 +1,190 @@ +/** + * 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) { + 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[]) { + 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 + 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 } + ); + // We should also ignore this identifier if it is shadowed + // 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) => + factory.createExpressionStatement(factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), + undefined, + [ + factory.createIdentifier('exports'), + factory.createStringLiteral(entry), + factory.createObjectLiteralExpression([ + factory.createPropertyAssignment('configurable', factory.createTrue()), + factory.createPropertyAssignment('get', + factory.createArrowFunction(undefined, undefined, [], undefined, undefined, + factory.createPropertyAccessExpression( + factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), + entry))) + ]), + ] + ))); + } + + 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)); +} \ 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..9e6ce85625d98 --- /dev/null +++ b/tools/@aws-cdk/lazify/test/export-star.test.ts @@ -0,0 +1,22 @@ +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 }); +" +`); +}); \ 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..ee8fcafaff85f --- /dev/null +++ b/tools/@aws-cdk/lazify/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "rootDir": "lib", + "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": [ + "lib/**/*.ts" + ], + "exclude": [] +} From a404b08e3641828fba231d34aaba3c1cd9681433 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 14:23:02 +0200 Subject: [PATCH 02/16] Also replace lazy-index --- packages/aws-cdk-lib/lazy-index.ts | 259 ------------------ packages/aws-cdk-lib/package.json | 6 +- packages/aws-cdk-lib/scripts/gen.ts | 15 - tools/@aws-cdk/lazify/lib/index.ts | 60 ++-- .../@aws-cdk/lazify/test/export-star.test.ts | 10 + 5 files changed, 55 insertions(+), 295 deletions(-) delete mode 100644 packages/aws-cdk-lib/lazy-index.ts diff --git a/packages/aws-cdk-lib/lazy-index.ts b/packages/aws-cdk-lib/lazy-index.ts deleted file mode 100644 index 1369fd6fd8f31..0000000000000 --- a/packages/aws-cdk-lib/lazy-index.ts +++ /dev/null @@ -1,259 +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_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_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_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_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 c43a2c1b4a439..b1a8380889563 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -211,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/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/tools/@aws-cdk/lazify/lib/index.ts b/tools/@aws-cdk/lazify/lib/index.ts index b62ca9c322e87..206fb84843388 100644 --- a/tools/@aws-cdk/lazify/lib/index.ts +++ b/tools/@aws-cdk/lazify/lib/index.ts @@ -142,22 +142,27 @@ export function transformFileContents(filename: string, contents: string, progre const entries = Object.keys(module); return entries.map((entry) => - factory.createExpressionStatement(factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), - undefined, - [ - factory.createIdentifier('exports'), - factory.createStringLiteral(entry), - factory.createObjectLiteralExpression([ - factory.createPropertyAssignment('configurable', factory.createTrue()), - factory.createPropertyAssignment('get', - factory.createArrowFunction(undefined, undefined, [], undefined, undefined, - factory.createPropertyAccessExpression( - factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), - 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); @@ -187,4 +192,27 @@ function createAssignment(factory: ts.NodeFactory, name: string, expression: ts. 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/test/export-star.test.ts b/tools/@aws-cdk/lazify/test/export-star.test.ts index 9e6ce85625d98..ceb1930fe658f 100644 --- a/tools/@aws-cdk/lazify/test/export-star.test.ts +++ b/tools/@aws-cdk/lazify/test/export-star.test.ts @@ -19,4 +19,14 @@ test('replace __exportStar with getters', () => { 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 From 2a4c0a53c7ff039b31132268ddb558832cb69ca2 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 14:30:03 +0200 Subject: [PATCH 03/16] Add to workspaces --- lerna.json | 1 + package.json | 1 + 2 files changed, 2 insertions(+) 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 ee71e0f826505..1aca884d9b12d 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": [ From 7fe5bd2daeb36d342a495b610269090becd8138e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 15:07:43 +0200 Subject: [PATCH 04/16] Remove accidentally checked-in files --- tools/@aws-cdk/lazify/lib/index.d.ts | 4 - tools/@aws-cdk/lazify/lib/index.js | 162 --------------------------- 2 files changed, 166 deletions(-) delete mode 100644 tools/@aws-cdk/lazify/lib/index.d.ts delete mode 100644 tools/@aws-cdk/lazify/lib/index.js diff --git a/tools/@aws-cdk/lazify/lib/index.d.ts b/tools/@aws-cdk/lazify/lib/index.d.ts deleted file mode 100644 index 56a55a6f8d38a..0000000000000 --- a/tools/@aws-cdk/lazify/lib/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -type LogFn = (...x: string[]) => void; -export declare function transformFile(filename: string): Promise; -export declare function transformFileContents(filename: string, contents: string, progress?: LogFn): string; -export {}; diff --git a/tools/@aws-cdk/lazify/lib/index.js b/tools/@aws-cdk/lazify/lib/index.js deleted file mode 100644 index 47a0d393f68b4..0000000000000 --- a/tools/@aws-cdk/lazify/lib/index.js +++ /dev/null @@ -1,162 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.transformFileContents = exports.transformFile = void 0; -/** - * 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. - */ -const fs_1 = require("fs"); -const path = __importStar(require("path")); -const ts = __importStar(require("typescript")); -async function transformFile(filename) { - progress(filename, '... '); - const contents = await fs_1.promises.readFile(filename, { encoding: 'utf-8' }); - const transformed = transformFileContents(filename, contents, progress); - await fs_1.promises.writeFile(filename, transformed, { encoding: 'utf-8' }); - progress(' Done!\n'); - function progress(...x) { - process.stderr.write(x.join(' ')); - } -} -exports.transformFile = transformFile; -function transformFileContents(filename, contents, progress) { - 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]]); - progress === null || progress === void 0 ? void 0 : 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]] : []); - progress === null || progress === void 0 ? void 0 : progress(`${topLevelRequires.length} requires`, '... '); - let file = sourceFile; - for (const [stmt, binding, moduleName] of topLevelRequires) { - const result = ts.transform(file, [(ctx) => { - const factory = ctx.factory; - const visit = node => { - // If this is the statement, replace it with a function definition - 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 } - ); - // We should also ignore this identifier if it is shadowed - // 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) => { var _a; return (_a = ts.visitNode(sf, visit, ts.isSourceFile)) !== null && _a !== void 0 ? _a : sf; }; - }]); - file = result.transformed[0]; - progress === null || progress === void 0 ? void 0 : progress('X'); - } - // Replace __exportStar - file = ts.transform(file, [(ctx) => { - const factory = ctx.factory; - const visit = 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) => factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), undefined, [ - factory.createIdentifier('exports'), - factory.createStringLiteral(entry), - factory.createObjectLiteralExpression([ - factory.createPropertyAssignment('configurable', factory.createTrue()), - factory.createPropertyAssignment('get', factory.createArrowFunction(undefined, undefined, [], undefined, undefined, factory.createPropertyAccessExpression(factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), entry))) - ]), - ]))); - } - return ts.visitEachChild(node, child => visit(child), ctx); - }; - return (sf) => { var _a; return (_a = ts.visitNode(sf, visit, ts.isSourceFile)) !== null && _a !== void 0 ? _a : 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); -} -exports.transformFileContents = transformFileContents; -function createVariable(factory, name, expression) { - return factory.createVariableStatement([], factory.createVariableDeclarationList([ - factory.createVariableDeclaration(name, undefined, undefined, expression), - ])); -} -function createAssignment(factory, name, expression) { - return factory.createExpressionStatement(factory.createBinaryExpression(factory.createIdentifier(name), ts.SyntaxKind.EqualsToken, expression)); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsMkJBQW9DO0FBQ3BDLDJDQUE2QjtBQUM3QiwrQ0FBaUM7QUFJMUIsS0FBSyxVQUFVLGFBQWEsQ0FBQyxRQUFnQjtJQUNsRCxRQUFRLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzNCLE1BQU0sUUFBUSxHQUFHLE1BQU0sYUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNwRSxNQUFNLFdBQVcsR0FBRyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sYUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsV0FBVyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDakUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRXJCLFNBQVMsUUFBUSxDQUFDLEdBQUcsQ0FBVztRQUM5QixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztBQUNILENBQUM7QUFWRCxzQ0FVQztBQUVELFNBQWdCLHFCQUFxQixDQUFDLFFBQWdCLEVBQUUsUUFBZ0IsRUFBRSxRQUFnQjtJQUN4RixNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQ3BDLFFBQVEsRUFDUixRQUFRLEVBQ1IsRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQ3RCLElBQUksQ0FBQyw4Q0FBOEM7S0FDcEQsQ0FBQztJQUVGLDREQUE0RDtJQUM1RCxNQUFNLG1CQUFtQixHQUFHLFVBQVUsQ0FBQyxVQUFVO1NBQzlDLE1BQU0sQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUM7U0FDOUIsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDO1NBQ2hFLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQVUsQ0FBQyxDQUFDO0lBRXhFLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRyxHQUFHLG1CQUFtQixDQUFDLE1BQU0sZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBRWpFLE1BQU0sZ0JBQWdCLEdBQUcsbUJBQW1CO1NBQ3pDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDO1dBQ3RFLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEtBQUssU0FBUztXQUN4RixFQUFFLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1dBQzlDLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxQixDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBRXZFLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRyxHQUFHLGdCQUFnQixDQUFDLE1BQU0sV0FBVyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBRTFELElBQUksSUFBSSxHQUFHLFVBQVUsQ0FBQztJQUV0QixLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxJQUFJLGdCQUFnQixFQUFFO1FBQzFELE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUE2QixFQUFpQyxFQUFFO2dCQUNsRyxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDO2dCQUM1QixNQUFNLEtBQUssR0FBZSxJQUFJLENBQUMsRUFBRTtvQkFDL0Isa0VBQWtFO29CQUNsRSxJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7d0JBQ2pCLE9BQU8sY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQ3BDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUN4RSxPQUFPLENBQUMsV0FBVyxDQUFDOzRCQUNsQixxQkFBcUI7NEJBQ3JCLGNBQWMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQzs0QkFFaEosd0JBQXdCOzRCQUN4QixnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksRUFDcEMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7NEJBRS9HLGFBQWE7NEJBQ2IsT0FBTyxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQzt5QkFDL0QsQ0FBQyxDQUNILENBQ0YsQ0FBQztxQkFDSDtvQkFFRCxtR0FBbUc7b0JBQ25HLElBQUksRUFBRSxDQUFDLDZCQUE2QixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxJQUFJLEVBQUU7d0JBQzNHLE9BQU8sT0FBTyxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO3FCQUN2STtvQkFFRCxtR0FBbUc7b0JBQ25HLElBQUksRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxJQUFJLEVBQUU7d0JBRXZELHNEQUFzRDt3QkFDdEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUM1QixDQUFDLEVBQUUsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUUsbUJBQW1COytCQUNyRixDQUFDLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsaUJBQWlCOytCQUMzRixFQUFFLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLHlCQUF5QjsrQkFDN0QsRUFBRSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQywyQkFBMkI7K0JBQzdELEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsNEJBQTRCOytCQUNsRSxFQUFFLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGdDQUFnQzsrQkFDcEUsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsa0NBQWtDOytCQUNoRSxFQUFFLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLG9DQUFvQzsrQkFDN0UsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsa0NBQWtDOytCQUNoRSxFQUFFLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLG9DQUFvQzt5QkFDakYsQ0FBQzt3QkFDRiwwREFBMEQ7d0JBQzFELGtHQUFrRzt3QkFFbEcsSUFBSSxDQUFDLE1BQU0sRUFBRTs0QkFDWCxPQUFPLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQzt5QkFDckY7cUJBQ0Y7b0JBRUQsT0FBTyxFQUFFLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDN0QsQ0FBQyxDQUFDO2dCQUVGLE9BQU8sQ0FBQyxFQUFpQixFQUFFLEVBQUUsV0FBQyxPQUFBLE1BQUEsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsbUNBQUksRUFBRSxDQUFBLEVBQUEsQ0FBQztZQUMvRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRUosSUFBSSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0IsUUFBUSxhQUFSLFFBQVEsdUJBQVIsUUFBUSxDQUFHLEdBQUcsQ0FBQyxDQUFDO0tBQ2pCO0lBRUQsdUJBQXVCO0lBRXZCLElBQUksR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsR0FBNkIsRUFBaUMsRUFBRTtZQUMxRixNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDO1lBQzVCLE1BQU0sS0FBSyxHQUFlLElBQUksQ0FBQyxFQUFFO2dCQUMvQixJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO3VCQUMxQyxFQUFFLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDO3VCQUM5QixFQUFFLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQzt1QkFDcEMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQzt1QkFDM0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsSUFBSSxLQUFLLGNBQWM7dUJBQ2xELElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDO3VCQUN0QyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7dUJBQ2pELEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO3VCQUN4RCxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxLQUFLLFNBQVM7dUJBQzFELEVBQUUsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7b0JBQ2hFLCtDQUErQztvQkFFakQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztvQkFFdEUsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUNsRixpREFBaUQ7b0JBQ2pELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDN0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFFcEMsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDM0IsT0FBTyxDQUFDLHlCQUF5QixDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FDNUQsT0FBTyxDQUFDLDhCQUE4QixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsRUFBRSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxFQUN0SCxTQUFTLEVBQ1Q7d0JBQ0UsT0FBTyxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQzt3QkFDbkMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQzt3QkFDbEMsT0FBTyxDQUFDLDZCQUE2QixDQUFDOzRCQUNwQyxPQUFPLENBQUMsd0JBQXdCLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQzs0QkFDdEUsT0FBTyxDQUFDLHdCQUF3QixDQUFDLEtBQUssRUFDcEMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQ3hFLE9BQU8sQ0FBQyw4QkFBOEIsQ0FDcEMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQyxPQUFPLENBQUMsbUJBQW1CLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxFQUMzSCxLQUFLLENBQUMsQ0FBQyxDQUFDO3lCQUNmLENBQUM7cUJBQ0gsQ0FDRixDQUFDLENBQUMsQ0FBQztpQkFDUDtnQkFFRCxPQUFPLEVBQUUsQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzdELENBQUMsQ0FBQztZQUVGLE9BQU8sQ0FBQyxFQUFpQixFQUFFLEVBQUUsV0FBQyxPQUFBLE1BQUEsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsbUNBQUksRUFBRSxDQUFBLEVBQUEsQ0FBQztRQUMvRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUluQixtREFBbUQ7SUFDbkQsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFFdkUsT0FBTyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFoSkQsc0RBZ0pDO0FBRUQsU0FBUyxjQUFjLENBQUMsT0FBdUIsRUFBRSxJQUE2QixFQUFFLFVBQXlCO0lBQ3ZHLE9BQU8sT0FBTyxDQUFDLHVCQUF1QixDQUFDLEVBQUUsRUFDdkMsT0FBTyxDQUFDLDZCQUE2QixDQUFDO1FBQ3BDLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxVQUFVLENBQUM7S0FDMUUsQ0FBQyxDQUFDLENBQUM7QUFDUixDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxPQUF1QixFQUFFLElBQVksRUFBRSxVQUF5QjtJQUN4RixPQUFPLE9BQU8sQ0FBQyx5QkFBeUIsQ0FDdEMsT0FBTyxDQUFDLHNCQUFzQixDQUM1QixPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQzlCLEVBQUUsQ0FBQyxVQUFVLENBQUMsV0FBVyxFQUN6QixVQUFVLENBQUMsQ0FBQyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRyYW5zZm9ybSBhIHNldCBvZiAuanMgZmlsZXMsIG1ha2luZyBhbGwgbW9kdWxlIGltcG9ydHMgbGF6eVxuICpcbiAqIFRoYXQgaXM6XG4gKlxuICogLSBGaW5kIGFsbCB0b3AtbGV2ZWwgcmVxdWlyZSgpIGFzc2lnbm1lbnRzLCBhbmQgcmVwbGFjZSB0aGVtIHdpdGggYSBmdW5jdGlvbiB0aGF0IHBlcmZvcm1zXG4gKiAgIHRoZSByZXF1aXJlKCkuIFRoYXQgd2F5LCB0aGUgcmVxdWlyZSgpIGlzIG9ubHkgZG9uZSBpZiBhbnkgb2YgdGhlIG9iamVjdHMgZnJvbSBpdHMgc2NvcGVcbiAqICAgYXJlIGFjdHVhbGx5IHVzZWQuXG4gKiAtIEZpbmQgYWxsICh0cmFuc3BpbGVkKSBgZXhwb3J0ICogZnJvbSAneHl6JztgIHN0YXRlbWVudHMgKGJ5IHNlYXJjaGluZyBmb3IgYW4gaW52b2NhdGlvblxuICogICBvZiBgX19leHBvcnRTdGFyKClgKTogbG9hZCB0aGUgYWN0dWFsIG1vZHVsZSwgZW51bWVyYXRlIHRoZSBlbnRyaWVzLCBhbmQgY3JlYXRlIGEgZ2V0dGVyXG4gKiAgIGZvciBlYWNoIGVudHJ5LlxuICovXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyB0cyBmcm9tICd0eXBlc2NyaXB0JztcblxudHlwZSBMb2dGbiA9ICguLi54OiBzdHJpbmdbXSkgPT4gdm9pZDtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyYW5zZm9ybUZpbGUoZmlsZW5hbWU6IHN0cmluZykge1xuICBwcm9ncmVzcyhmaWxlbmFtZSwgJy4uLiAnKTtcbiAgY29uc3QgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlbmFtZSwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgY29uc3QgdHJhbnNmb3JtZWQgPSB0cmFuc2Zvcm1GaWxlQ29udGVudHMoZmlsZW5hbWUsIGNvbnRlbnRzLCBwcm9ncmVzcyk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShmaWxlbmFtZSwgdHJhbnNmb3JtZWQsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gIHByb2dyZXNzKCcgRG9uZSFcXG4nKTtcblxuICBmdW5jdGlvbiBwcm9ncmVzcyguLi54OiBzdHJpbmdbXSkge1xuICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKHguam9pbignICcpKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNmb3JtRmlsZUNvbnRlbnRzKGZpbGVuYW1lOiBzdHJpbmcsIGNvbnRlbnRzOiBzdHJpbmcsIHByb2dyZXNzPzogTG9nRm4pIHtcbiAgY29uc3Qgc291cmNlRmlsZSA9IHRzLmNyZWF0ZVNvdXJjZUZpbGUoXG4gICAgZmlsZW5hbWUsXG4gICAgY29udGVudHMsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlIC8vIHNldFBhcmVudE5vZGVzLCBuZWVkIHRoaXMgZm9yIHRyZWUgYW5hbHlzaXNcbiAgKTtcblxuICAvLyBGaW5kIGFsbCB0b3AtbGV2ZWwgcmVxdWlyZXMgYW5kIHR1cm4gdGhlbSBpbnRvIGEgZnVuY3Rpb25cbiAgY29uc3QgdG9wTGV2ZWxBc3NpZ25tZW50cyA9IHNvdXJjZUZpbGUuc3RhdGVtZW50c1xuICAgIC5maWx0ZXIodHMuaXNWYXJpYWJsZVN0YXRlbWVudClcbiAgICAuZmlsdGVyKChzdG10KSA9PiBzdG10LmRlY2xhcmF0aW9uTGlzdC5kZWNsYXJhdGlvbnMubGVuZ3RoID09PSAxKVxuICAgIC5tYXAoKHN0bXQpID0+IFtzdG10LCBzdG10LmRlY2xhcmF0aW9uTGlzdC5kZWNsYXJhdGlvbnNbMF1dIGFzIGNvbnN0KTtcblxuICBwcm9ncmVzcz8uKGAke3RvcExldmVsQXNzaWdubWVudHMubGVuZ3RofSBkZWNsYXJhdGlvbnNgLCAnLi4uICcpO1xuXG4gIGNvbnN0IHRvcExldmVsUmVxdWlyZXMgPSB0b3BMZXZlbEFzc2lnbm1lbnRzXG4gICAgLmZsYXRNYXAoKFtzdG10LCBhXSkgPT4gYS5pbml0aWFsaXplciAmJiB0cy5pc0NhbGxFeHByZXNzaW9uKGEuaW5pdGlhbGl6ZXIpXG4gICAgICAmJiB0cy5pc0lkZW50aWZpZXIoYS5pbml0aWFsaXplci5leHByZXNzaW9uKSAmJiBhLmluaXRpYWxpemVyLmV4cHJlc3Npb24udGV4dCA9PT0gJ3JlcXVpcmUnXG4gICAgICAmJiB0cy5pc1N0cmluZ0xpdGVyYWwoYS5pbml0aWFsaXplci5hcmd1bWVudHNbMF0pXG4gICAgICAmJiB0cy5pc0lkZW50aWZpZXIoYS5uYW1lKVxuICAgICAgPyBbW3N0bXQsIGEubmFtZSwgYS5pbml0aWFsaXplci5hcmd1bWVudHNbMF0udGV4dF0gYXMgY29uc3RdIDogW10pO1xuXG4gIHByb2dyZXNzPy4oYCR7dG9wTGV2ZWxSZXF1aXJlcy5sZW5ndGh9IHJlcXVpcmVzYCwgJy4uLiAnKTtcblxuICBsZXQgZmlsZSA9IHNvdXJjZUZpbGU7XG5cbiAgZm9yIChjb25zdCBbc3RtdCwgYmluZGluZywgbW9kdWxlTmFtZV0gb2YgdG9wTGV2ZWxSZXF1aXJlcykge1xuICAgIGNvbnN0IHJlc3VsdCA9IHRzLnRyYW5zZm9ybShmaWxlLCBbKGN0eDogdHMuVHJhbnNmb3JtYXRpb25Db250ZXh0KTogdHMuVHJhbnNmb3JtZXI8dHMuU291cmNlRmlsZT4gPT4ge1xuICAgICAgY29uc3QgZmFjdG9yeSA9IGN0eC5mYWN0b3J5O1xuICAgICAgY29uc3QgdmlzaXQ6IHRzLlZpc2l0b3IgPSBub2RlID0+IHtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyB0aGUgc3RhdGVtZW50LCByZXBsYWNlIGl0IHdpdGggYSBmdW5jdGlvbiBkZWZpbml0aW9uXG4gICAgICAgIGlmIChub2RlID09PSBzdG10KSB7XG4gICAgICAgICAgcmV0dXJuIGNyZWF0ZVZhcmlhYmxlKGZhY3RvcnksIGJpbmRpbmcsXG4gICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUFycm93RnVuY3Rpb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFtdLCB1bmRlZmluZWQsIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVCbG9jayhbXG4gICAgICAgICAgICAgICAgLy8gdG1wID0gcmVxdWlyZSguLi4pXG4gICAgICAgICAgICAgICAgY3JlYXRlVmFyaWFibGUoZmFjdG9yeSwgJ3RtcCcsIGZhY3RvcnkuY3JlYXRlQ2FsbEV4cHJlc3Npb24oZmFjdG9yeS5jcmVhdGVJZGVudGlmaWVyKCdyZXF1aXJlJyksIFtdLCBbZmFjdG9yeS5jcmVhdGVTdHJpbmdMaXRlcmFsKG1vZHVsZU5hbWUpXSkpLFxuXG4gICAgICAgICAgICAgICAgLy8gPHRoaXNfZm4+ID0gKCkgPT4gdG1wXG4gICAgICAgICAgICAgICAgY3JlYXRlQXNzaWdubWVudChmYWN0b3J5LCBiaW5kaW5nLnRleHQsXG4gICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUFycm93RnVuY3Rpb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFtdLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgZmFjdG9yeS5jcmVhdGVJZGVudGlmaWVyKCd0bXAnKSkpLFxuXG4gICAgICAgICAgICAgICAgLy8gcmV0dXJuIHRtcFxuICAgICAgICAgICAgICAgIGZhY3RvcnkuY3JlYXRlUmV0dXJuU3RhdGVtZW50KGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcigndG1wJykpLFxuICAgICAgICAgICAgICBdKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBzaG9ydGhhbmQgcHJvcGVydHkgYXNzaWdubWVudCBhbmQgd2Ugd2UgYXJlIHRoZSBpZGVudGlmaWVyIGluIGl0LCBzcGxpdCBpdCBpbnRvIHR3b1xuICAgICAgICBpZiAodHMuaXNTaG9ydGhhbmRQcm9wZXJ0eUFzc2lnbm1lbnQobm9kZSkgJiYgdHMuaXNJZGVudGlmaWVyKG5vZGUubmFtZSkgJiYgbm9kZS5uYW1lLnRleHQgPT09IGJpbmRpbmcudGV4dCkge1xuICAgICAgICAgIHJldHVybiBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QXNzaWdubWVudChub2RlLm5hbWUudGV4dCwgZmFjdG9yeS5jcmVhdGVDYWxsRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoYmluZGluZy50ZXh0KSwgW10sIFtdKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB0aGlzIHdhcyBhbiBpZGVudGlmaWVyIHJlZmVyZW5jaW5nIHRoZSBvcmlnaW5hbCByZXF1aXJlZCBtb2R1bGUsIHR1cm4gaXQgaW50byBhIGZ1bmN0aW9uIGNhbGxcbiAgICAgICAgaWYgKHRzLmlzSWRlbnRpZmllcihub2RlKSAmJiBub2RlLnRleHQgPT09IGJpbmRpbmcudGV4dCkge1xuXG4gICAgICAgICAgLy8gSWdub3JlIHRoaXMgaWRlbnRpZmllciBpZiBpdCBpcyBub3QgaW4gUkhTIHBvc2l0aW9uXG4gICAgICAgICAgY29uc3QgaWdub3JlID0gbm9kZS5wYXJlbnQgJiYgKFxuICAgICAgICAgICAgKHRzLmlzUHJvcGVydHlBc3NpZ25tZW50KG5vZGUucGFyZW50KSAmJiBub2RlLnBhcmVudC5uYW1lID09PSBub2RlKSAgLy8geyBpZGVudDogdmFsdWUgfVxuICAgICAgICAgICAgfHwgKHRzLmlzUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKG5vZGUucGFyZW50KSAmJiBub2RlLnBhcmVudC5uYW1lID09PSBub2RlKSAvLyBvYmouaWRlbnQgPSAzO1xuICAgICAgICAgICAgfHwgdHMuaXNNZXRob2REZWNsYXJhdGlvbihub2RlLnBhcmVudCkgLy8gcHVibGljIGlkZW50KCkgeyAuLi4gfVxuICAgICAgICAgICAgfHwgdHMuaXNNZXRob2RTaWduYXR1cmUobm9kZS5wYXJlbnQpIC8vIGludGVyZmFjZSBYIHsgaWRlbnQoKTsgfVxuICAgICAgICAgICAgfHwgdHMuaXNQcm9wZXJ0eURlY2xhcmF0aW9uKG5vZGUucGFyZW50KSAvLyBjbGFzcyBYIHsgaWRlbnQ6IHN0cmluZyB9XG4gICAgICAgICAgICB8fCB0cy5pc1Byb3BlcnR5U2lnbmF0dXJlKG5vZGUucGFyZW50KSAvLyBpbnRlcmZhY2UgWCB7IGlkZW50OiBzdHJpbmcgfVxuICAgICAgICAgICAgfHwgdHMuaXNHZXRBY2Nlc3Nvcihub2RlLnBhcmVudCkgLy8gY2xhc3MgWCB7IGdldCBpZGVudCgpIHsgLi4uIH0gfVxuICAgICAgICAgICAgfHwgdHMuaXNHZXRBY2Nlc3NvckRlY2xhcmF0aW9uKG5vZGUucGFyZW50KSAvLyBpbnRlcmZhY2UgWCB7IGdldCBpZGVudDogc3RyaW5nIH1cbiAgICAgICAgICAgIHx8IHRzLmlzU2V0QWNjZXNzb3Iobm9kZS5wYXJlbnQpIC8vIGNsYXNzIFggeyBzZXQgaWRlbnQoKSB7IC4uLiB9IH1cbiAgICAgICAgICAgIHx8IHRzLmlzU2V0QWNjZXNzb3JEZWNsYXJhdGlvbihub2RlLnBhcmVudCkgLy8gaW50ZXJmYWNlIFggeyBzZXQgaWRlbnQ6IHN0cmluZyB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBXZSBzaG91bGQgYWxzbyBpZ25vcmUgdGhpcyBpZGVudGlmaWVyIGlmIGl0IGlzIHNoYWRvd2VkXG4gICAgICAgICAgLy8gTW9yZSBwbGFjZXMgYXJlIGFsc28gbm90IFJIUyBidXQgaWYgd2UgbGVhdmUgdGhvc2UsIGl0J2xsIGJsb3cgdXAgc3ludGFjdGljYWxseSBhbmQgdGhhdCdzIGdvb2RcblxuICAgICAgICAgIGlmICghaWdub3JlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFjdG9yeS5jcmVhdGVDYWxsRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoYmluZGluZy50ZXh0KSwgW10sIFtdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHMudmlzaXRFYWNoQ2hpbGQobm9kZSwgY2hpbGQgPT4gdmlzaXQoY2hpbGQpLCBjdHgpO1xuICAgICAgfTtcblxuICAgICAgcmV0dXJuIChzZjogdHMuU291cmNlRmlsZSkgPT4gdHMudmlzaXROb2RlKHNmLCB2aXNpdCwgdHMuaXNTb3VyY2VGaWxlKSA/PyBzZjtcbiAgICB9XSk7XG5cbiAgICBmaWxlID0gcmVzdWx0LnRyYW5zZm9ybWVkWzBdO1xuICAgIHByb2dyZXNzPy4oJ1gnKTtcbiAgfVxuXG4gIC8vIFJlcGxhY2UgX19leHBvcnRTdGFyXG5cbiAgZmlsZSA9IHRzLnRyYW5zZm9ybShmaWxlLCBbKGN0eDogdHMuVHJhbnNmb3JtYXRpb25Db250ZXh0KTogdHMuVHJhbnNmb3JtZXI8dHMuU291cmNlRmlsZT4gPT4ge1xuICAgIGNvbnN0IGZhY3RvcnkgPSBjdHguZmFjdG9yeTtcbiAgICBjb25zdCB2aXNpdDogdHMuVmlzaXRvciA9IG5vZGUgPT4ge1xuICAgICAgaWYgKG5vZGUucGFyZW50ICYmIHRzLmlzU291cmNlRmlsZShub2RlLnBhcmVudClcbiAgICAgICAgJiYgdHMuaXNFeHByZXNzaW9uU3RhdGVtZW50KG5vZGUpXG4gICAgICAgICYmIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uKVxuICAgICAgICAmJiB0cy5pc0lkZW50aWZpZXIobm9kZS5leHByZXNzaW9uLmV4cHJlc3Npb24pXG4gICAgICAgICYmIG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uLnRleHQgPT09ICdfX2V4cG9ydFN0YXInXG4gICAgICAgICYmIG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHMubGVuZ3RoID09PSAyXG4gICAgICAgICYmIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXSlcbiAgICAgICAgJiYgdHMuaXNJZGVudGlmaWVyKG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHNbMF0uZXhwcmVzc2lvbilcbiAgICAgICAgJiYgbm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXS5leHByZXNzaW9uLnRleHQgPT09ICdyZXF1aXJlJ1xuICAgICAgICAmJiB0cy5pc1N0cmluZ0xpdGVyYWwobm9kZS5leHByZXNzaW9uLmFyZ3VtZW50c1swXS5hcmd1bWVudHNbMF0pKSB7XG4gICAgICAgICAgLy8gX19leHBvcnRTdGFyKHJlcXVpcmUoJ3NvbWV0aGluZycpLCBleHBvcnRzKTtcblxuICAgICAgICBjb25zdCByZXF1aXJlZE1vZHVsZSA9IG5vZGUuZXhwcmVzc2lvbi5hcmd1bWVudHNbMF0uYXJndW1lbnRzWzBdLnRleHQ7XG5cbiAgICAgICAgY29uc3QgZmlsZSA9IHJlcXVpcmUucmVzb2x2ZShyZXF1aXJlZE1vZHVsZSwgeyBwYXRoczogW3BhdGguZGlybmFtZShmaWxlbmFtZSldIH0pO1xuICAgICAgICAvLyBGSVhNRTogU2hvdWxkIHByb2JhYmx5IGRvIHRoaXMgaW4gYSBzdWJwcm9jZXNzXG4gICAgICAgIGNvbnN0IG1vZHVsZSA9IHJlcXVpcmUoZmlsZSk7XG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3Qua2V5cyhtb2R1bGUpO1xuXG4gICAgICAgIHJldHVybiBlbnRyaWVzLm1hcCgoZW50cnkpID0+XG4gICAgICAgICAgZmFjdG9yeS5jcmVhdGVFeHByZXNzaW9uU3RhdGVtZW50KGZhY3RvcnkuY3JlYXRlQ2FsbEV4cHJlc3Npb24oXG4gICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ09iamVjdCcpLCBmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ2RlZmluZVByb3BlcnR5JykpLFxuICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgW1xuICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUlkZW50aWZpZXIoJ2V4cG9ydHMnKSxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVTdHJpbmdMaXRlcmFsKGVudHJ5KSxcbiAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVPYmplY3RMaXRlcmFsRXhwcmVzc2lvbihbXG4gICAgICAgICAgICAgICAgZmFjdG9yeS5jcmVhdGVQcm9wZXJ0eUFzc2lnbm1lbnQoJ2NvbmZpZ3VyYWJsZScsIGZhY3RvcnkuY3JlYXRlVHJ1ZSgpKSxcbiAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QXNzaWdubWVudCgnZ2V0JyxcbiAgICAgICAgICAgICAgICAgIGZhY3RvcnkuY3JlYXRlQXJyb3dGdW5jdGlvbih1bmRlZmluZWQsIHVuZGVmaW5lZCwgW10sIHVuZGVmaW5lZCwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZVByb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihcbiAgICAgICAgICAgICAgICAgICAgICBmYWN0b3J5LmNyZWF0ZUNhbGxFeHByZXNzaW9uKGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcigncmVxdWlyZScpLCB1bmRlZmluZWQsIFtmYWN0b3J5LmNyZWF0ZVN0cmluZ0xpdGVyYWwocmVxdWlyZWRNb2R1bGUpXSksXG4gICAgICAgICAgICAgICAgICAgICAgZW50cnkpKSlcbiAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICBdXG4gICAgICAgICAgKSkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHMudmlzaXRFYWNoQ2hpbGQobm9kZSwgY2hpbGQgPT4gdmlzaXQoY2hpbGQpLCBjdHgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gKHNmOiB0cy5Tb3VyY2VGaWxlKSA9PiB0cy52aXNpdE5vZGUoc2YsIHZpc2l0LCB0cy5pc1NvdXJjZUZpbGUpID8/IHNmO1xuICB9XSkudHJhbnNmb3JtZWRbMF07XG5cblxuXG4gIC8vIFRvIHByaW50IHRoZSBBU1QsIHdlJ2xsIHVzZSBUeXBlU2NyaXB0J3MgcHJpbnRlclxuICBjb25zdCBwcmludGVyID0gdHMuY3JlYXRlUHJpbnRlcih7IG5ld0xpbmU6IHRzLk5ld0xpbmVLaW5kLkxpbmVGZWVkIH0pO1xuXG4gIHJldHVybiBwcmludGVyLnByaW50RmlsZShmaWxlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlVmFyaWFibGUoZmFjdG9yeTogdHMuTm9kZUZhY3RvcnksIG5hbWU6IHN0cmluZyB8IHRzLkJpbmRpbmdOYW1lLCBleHByZXNzaW9uOiB0cy5FeHByZXNzaW9uKSB7XG4gIHJldHVybiBmYWN0b3J5LmNyZWF0ZVZhcmlhYmxlU3RhdGVtZW50KFtdLFxuICAgIGZhY3RvcnkuY3JlYXRlVmFyaWFibGVEZWNsYXJhdGlvbkxpc3QoW1xuICAgICAgZmFjdG9yeS5jcmVhdGVWYXJpYWJsZURlY2xhcmF0aW9uKG5hbWUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBleHByZXNzaW9uKSxcbiAgICBdKSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFzc2lnbm1lbnQoZmFjdG9yeTogdHMuTm9kZUZhY3RvcnksIG5hbWU6IHN0cmluZywgZXhwcmVzc2lvbjogdHMuRXhwcmVzc2lvbikge1xuICByZXR1cm4gZmFjdG9yeS5jcmVhdGVFeHByZXNzaW9uU3RhdGVtZW50KFxuICAgIGZhY3RvcnkuY3JlYXRlQmluYXJ5RXhwcmVzc2lvbihcbiAgICAgIGZhY3RvcnkuY3JlYXRlSWRlbnRpZmllcihuYW1lKSxcbiAgICAgIHRzLlN5bnRheEtpbmQuRXF1YWxzVG9rZW4sXG4gICAgICBleHByZXNzaW9uKSk7XG59Il19 \ No newline at end of file From 089d1be01aa2cce01e3542fab7c14ad90517a894 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 15:34:07 +0200 Subject: [PATCH 05/16] Remove moved file --- packages/aws-cdk-lib/scripts/lazy-import.ts | 186 -------------------- 1 file changed, 186 deletions(-) delete mode 100644 packages/aws-cdk-lib/scripts/lazy-import.ts diff --git a/packages/aws-cdk-lib/scripts/lazy-import.ts b/packages/aws-cdk-lib/scripts/lazy-import.ts deleted file mode 100644 index 6bb4adebd6f0a..0000000000000 --- a/packages/aws-cdk-lib/scripts/lazy-import.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { promises as fs } from 'fs'; -import * as path from 'path'; -import * as ts from 'typescript'; - -function progress(...x: string[]) { - process.stderr.write(x.join(' ')); -} - -async function main(args: string[]) { - for (const arg of args) { - await transform(arg); - } -} - -async function transform(filename: string) { - if (!(await fs.stat(filename)).isFile()) { - return; - } - - progress(filename, '... '); - const sourceFile = ts.createSourceFile( - filename, - await fs.readFile(filename, { encoding: 'utf-8' }), - 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 - 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 } - ); - // We should also ignore this identifier if it is shadowed - // 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) => - factory.createExpressionStatement(factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('defineProperty')), - undefined, - [ - factory.createIdentifier('exports'), - factory.createStringLiteral(entry), - factory.createObjectLiteralExpression([ - factory.createPropertyAssignment('configurable', factory.createTrue()), - factory.createPropertyAssignment('get', - factory.createArrowFunction(undefined, undefined, [], undefined, undefined, - factory.createPropertyAccessExpression( - factory.createCallExpression(factory.createIdentifier('require'), undefined, [factory.createStringLiteral(requiredModule)]), - entry))) - ]), - ] - ))); - } - - 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 }); - - await fs.writeFile(filename, printer.printFile(file), { encoding: 'utf-8' }); - progress(' Done!\n'); -} - -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)); -} - - -main(process.argv.slice(2)).catch((e) => { - console.error(e); - process.exitCode = 1; -}); \ No newline at end of file From cedaae8035c4c03ac4167ab432fb3c39bee4573d Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 20 Sep 2023 17:14:30 +0200 Subject: [PATCH 06/16] Compile bin as well --- tools/@aws-cdk/lazify/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/@aws-cdk/lazify/tsconfig.json b/tools/@aws-cdk/lazify/tsconfig.json index ee8fcafaff85f..18e13ce9d820b 100644 --- a/tools/@aws-cdk/lazify/tsconfig.json +++ b/tools/@aws-cdk/lazify/tsconfig.json @@ -27,6 +27,7 @@ "target": "ES2019" }, "include": [ + "bin/**/*.ts", "lib/**/*.ts" ], "exclude": [] From c30313d72d61251290f6c7776e691c09b0bf187e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 10:11:15 +0200 Subject: [PATCH 07/16] Omg this config --- tools/@aws-cdk/lazify/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/@aws-cdk/lazify/tsconfig.json b/tools/@aws-cdk/lazify/tsconfig.json index 18e13ce9d820b..b6fb832634653 100644 --- a/tools/@aws-cdk/lazify/tsconfig.json +++ b/tools/@aws-cdk/lazify/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "rootDir": "lib", "alwaysStrict": true, "declaration": true, "esModuleInterop": true, From 4a2da797e786a78933c390585a7402641f7d442d Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 10:19:23 +0200 Subject: [PATCH 08/16] Quiet by default --- packages/aws-cdk-lib/package.json | 2 +- tools/@aws-cdk/lazify/bin/lazify.ts | 3 ++- tools/@aws-cdk/lazify/lib/index.ts | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 239881758c787..dbe45bd1d4fc7 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -42,7 +42,7 @@ "ts-node ./scripts/verify-imports-resolve-same.ts", "ts-node ./scripts/verify-imports-shielded.ts", "ts-node ./cx-api/build-tools/flag-report.ts", - "lazify ." + "env QUIET=1 lazify ." ] }, "cdk-package": { diff --git a/tools/@aws-cdk/lazify/bin/lazify.ts b/tools/@aws-cdk/lazify/bin/lazify.ts index 13929817a739f..d72759e9ce86e 100644 --- a/tools/@aws-cdk/lazify/bin/lazify.ts +++ b/tools/@aws-cdk/lazify/bin/lazify.ts @@ -4,13 +4,14 @@ 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); + await transformFile(f, verbose); } }); } diff --git a/tools/@aws-cdk/lazify/lib/index.ts b/tools/@aws-cdk/lazify/lib/index.ts index 206fb84843388..52536daee5d8f 100644 --- a/tools/@aws-cdk/lazify/lib/index.ts +++ b/tools/@aws-cdk/lazify/lib/index.ts @@ -16,7 +16,7 @@ import * as ts from 'typescript'; type LogFn = (...x: string[]) => void; -export async function transformFile(filename: string) { +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); @@ -24,7 +24,9 @@ export async function transformFile(filename: string) { progress(' Done!\n'); function progress(...x: string[]) { - process.stderr.write(x.join(' ')); + if (verbose) { + process.stderr.write(x.join(' ')); + } } } From 2cb1270db255a2df373eeb27fc6811ef75749d9f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 10:43:22 +0200 Subject: [PATCH 09/16] Add an ESM integ test --- .../init-javascript.integtest.ts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) 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..235e2c815c298 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 fs from 'fs-extra'; +import * as path from 'path'; 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']); + +}))); From 26f755c162461cadfbb63725d6c44eda61da8662 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 11:17:00 +0200 Subject: [PATCH 10/16] yarnlock --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 73626145a69fd..40e31b9ecb253 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== From bb0dfee1ae031eb1a4ee6124d20aa3f086aa193f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 11:23:25 +0200 Subject: [PATCH 11/16] Linterrr --- .../tests/init-javascript/init-javascript.integtest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 235e2c815c298..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,5 +1,5 @@ -import * as fs from 'fs-extra'; import * as path from 'path'; +import * as fs from 'fs-extra'; import { integTest, withTemporaryDirectory, ShellHelper, withPackages } from '../../lib'; ['app', 'sample-app'].forEach(template => { From 807f2c3d7ba0dae8bce3d5f59cbffa77288a7d36 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 13:48:31 +0200 Subject: [PATCH 12/16] Exclude custom resources --- .../.is_custom_resource | 0 .../lib/oidc-provider/.is_custom_resource | 0 .../docker-build-lambda/.is_custom_resource | 0 .../.is_custom_resource | 0 .../.is_custom_resource | 0 .../.is_custom_resource | 0 .../lib/drop-spam-handler/.is_custom_resource | 0 .../eval-nodejs-handler/.is_custom_resource | 0 .../.is_custom_resource | 0 .../cfn-utils-provider/.is_custom_resource | 0 .../approve-lambda/.is_custom_resource | 0 .../triggers/lib/lambda/.is_custom_resource | 0 tools/@aws-cdk/lazify/bin/lazify.ts | 24 +++++++++++-------- 13 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 packages/aws-cdk-lib/aws-ec2/lib/restrict-default-security-group-handler/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-iam/lib/oidc-provider/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-lambda/test/docker-build-lambda/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-logs/lib/log-retention-provider/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-route53/lib/delete-existing-record-set-handler/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-ses/lib/drop-spam-handler/.is_custom_resource create mode 100644 packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/eval-nodejs-handler/.is_custom_resource create mode 100644 packages/aws-cdk-lib/core/lib/custom-resource-provider/.is_custom_resource create mode 100644 packages/aws-cdk-lib/core/lib/private/cfn-utils-provider/.is_custom_resource create mode 100644 packages/aws-cdk-lib/pipelines/lib/private/approve-lambda/.is_custom_resource create mode 100644 packages/aws-cdk-lib/triggers/lib/lambda/.is_custom_resource 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/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/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/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/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/bin/lazify.ts b/tools/@aws-cdk/lazify/bin/lazify.ts index d72759e9ce86e..21b39730eedb5 100644 --- a/tools/@aws-cdk/lazify/bin/lazify.ts +++ b/tools/@aws-cdk/lazify/bin/lazify.ts @@ -7,25 +7,29 @@ async function main() { 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); - } - }); + 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, block: (x: string) => Promise) { +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 block(f); + await fileBlock(f); } - if (s.isDirectory() && path.basename(f) !== 'node_modules') { + if (s.isDirectory() && await dirBlock(f)) { for (const child of await fs.readdir(f)) { await recurse(path.join(f, child)); } From 6f4a2e719c47de94a5d909c4e240550016c1f121 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 14:07:49 +0200 Subject: [PATCH 13/16] Get rid of hash --- packages/aws-cdk-lib/aws-lambda/test/code.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..0ff49c265acdb 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', }, From c3e8d838e15b4c047471f7e9211700e5687af698 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 21 Sep 2023 14:23:12 +0200 Subject: [PATCH 14/16] Ignore .is_custom_resource everywhere --- packages/aws-cdk-lib/core/lib/asset-staging.ts | 1 + 1 file changed, 1 insertion(+) 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, }; From e37f94e52e37688ecd92b47d7b5236ae89d6265a Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 22 Sep 2023 13:58:18 +0200 Subject: [PATCH 15/16] Clarify --- tools/@aws-cdk/lazify/lib/index.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/@aws-cdk/lazify/lib/index.ts b/tools/@aws-cdk/lazify/lib/index.ts index 52536daee5d8f..79c1ae3432ed3 100644 --- a/tools/@aws-cdk/lazify/lib/index.ts +++ b/tools/@aws-cdk/lazify/lib/index.ts @@ -62,6 +62,18 @@ export function transformFileContents(filename: string, contents: string, progre 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, @@ -101,7 +113,11 @@ export function transformFileContents(filename: string, contents: string, progre || ts.isSetAccessor(node.parent) // class X { set ident() { ... } } || ts.isSetAccessorDeclaration(node.parent) // interface X { set ident: string } ); - // We should also ignore this identifier if it is shadowed + // 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) { From 641a7029b26e3c8f22a66cf38aa57ee9eb00ad7e Mon Sep 17 00:00:00 2001 From: Rico Hermans Date: Fri, 22 Sep 2023 16:04:45 +0200 Subject: [PATCH 16/16] Update code.test.ts --- packages/aws-cdk-lib/aws-lambda/test/code.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0ff49c265acdb..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]: Match.stringLikeRegexp('asset\.[0-9a-f]+'), + [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', },