From 0068b7feaf2a3866b24485debb08855d33c3e750 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 2 Jun 2022 18:49:40 -0400 Subject: [PATCH 01/41] new module for jsii utility functions --- packages/@jsii/utils/.gitignore | 8 + packages/@jsii/utils/.npmignore | 15 ++ packages/@jsii/utils/LICENSE | 202 +++++++++++++++++++++ packages/@jsii/utils/NOTICE | 2 + packages/@jsii/utils/README.md | 0 packages/@jsii/utils/jest.config.ts | 3 + packages/@jsii/utils/lib/assembly.ts | 98 ++++++++++ packages/@jsii/utils/lib/index.ts | 1 + packages/@jsii/utils/package.json | 37 ++++ packages/@jsii/utils/test/assembly.test.ts | 111 +++++++++++ packages/@jsii/utils/tsconfig.json | 5 + 11 files changed, 482 insertions(+) create mode 100644 packages/@jsii/utils/.gitignore create mode 100644 packages/@jsii/utils/.npmignore create mode 100644 packages/@jsii/utils/LICENSE create mode 100644 packages/@jsii/utils/NOTICE create mode 100644 packages/@jsii/utils/README.md create mode 100644 packages/@jsii/utils/jest.config.ts create mode 100644 packages/@jsii/utils/lib/assembly.ts create mode 100644 packages/@jsii/utils/lib/index.ts create mode 100644 packages/@jsii/utils/package.json create mode 100644 packages/@jsii/utils/test/assembly.test.ts create mode 100644 packages/@jsii/utils/tsconfig.json diff --git a/packages/@jsii/utils/.gitignore b/packages/@jsii/utils/.gitignore new file mode 100644 index 0000000000..f011fea9b2 --- /dev/null +++ b/packages/@jsii/utils/.gitignore @@ -0,0 +1,8 @@ +*.js +*.d.ts +node_modules/ +.nyc_output/ +coverage/ + +lib/version.ts +*.d.ts.map diff --git a/packages/@jsii/utils/.npmignore b/packages/@jsii/utils/.npmignore new file mode 100644 index 0000000000..4fd6a03ff5 --- /dev/null +++ b/packages/@jsii/utils/.npmignore @@ -0,0 +1,15 @@ +* + +!**/*.js +!**/*.d.ts +!bin/jsii +!bin/jsii-fix-peers + + +coverage + +# Don't include various configuration & state information +coverage +.eslintrc.* +tsconfig.json +*.tsbuildinfo diff --git a/packages/@jsii/utils/LICENSE b/packages/@jsii/utils/LICENSE new file mode 100644 index 0000000000..129acd53d9 --- /dev/null +++ b/packages/@jsii/utils/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 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + 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. \ No newline at end of file diff --git a/packages/@jsii/utils/NOTICE b/packages/@jsii/utils/NOTICE new file mode 100644 index 0000000000..dc4ac3f857 --- /dev/null +++ b/packages/@jsii/utils/NOTICE @@ -0,0 +1,2 @@ +jsii +Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@jsii/utils/README.md b/packages/@jsii/utils/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@jsii/utils/jest.config.ts b/packages/@jsii/utils/jest.config.ts new file mode 100644 index 0000000000..6da6af03e8 --- /dev/null +++ b/packages/@jsii/utils/jest.config.ts @@ -0,0 +1,3 @@ +import config from '../../../jest.config'; + +export default config; diff --git a/packages/@jsii/utils/lib/assembly.ts b/packages/@jsii/utils/lib/assembly.ts new file mode 100644 index 0000000000..fe4f03d2fb --- /dev/null +++ b/packages/@jsii/utils/lib/assembly.ts @@ -0,0 +1,98 @@ +import * as spec from '@jsii/spec'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as zlib from 'zlib'; + +export const SPEC_FILE_NAME = '.jsii'; +export const SPEC_FILE_NAME_COMPRESSED = `${SPEC_FILE_NAME}.gz`; + +/** + * Finds the path to the assembly file, which will be + * '.jsii' if uncompressed and '.jsii.gz' if compressed. + * + * @param directory path to a directory with an assembly file + * @returns path to the assembly file + */ +export function getAssemblyFile(directory: string) { + const compressedJsiiFile = path.join(directory, SPEC_FILE_NAME_COMPRESSED); + const compressedJsiiExists = fs.existsSync(compressedJsiiFile); + + const uncompressedJsiiFile = path.join(directory, SPEC_FILE_NAME); + const uncompressedJsiiExists = fs.existsSync(uncompressedJsiiFile); + + if (!compressedJsiiExists && !uncompressedJsiiExists) { + throw new Error( + `No ${SPEC_FILE_NAME} or ${SPEC_FILE_NAME_COMPRESSED} assembly file was found at ${directory}`, + ); + } + + return compressedJsiiExists ? compressedJsiiFile : uncompressedJsiiFile; +} + +/** + * Writes the assembly file either as .jsii or .jsii.gz if zipped + * + * @param directory the directory path to place the assembly file + * @param assembly the contents of the assembly + * @param zip whether or not to zip the assembly (.jsii.gz) + * @returns whether or not the assembly was zipped + */ +export function writeAssembly( + directory: string, + assembly: spec.Assembly, + zip: boolean, +) { + if (zip) { + // TODO: also write .jsii + fs.writeFileSync( + path.join(directory, SPEC_FILE_NAME_COMPRESSED), + zlib.gzipSync(JSON.stringify(assembly)), + ); + } else { + fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), assembly); + } + + return zip; +} + +/** + * Loads the assembly file and unzips compressed assemblies. + * + * @param directory the directory of the assembly file + * @returns the assembly file as json + */ +export function loadAssemblyFromPath(directory: string) { + const assemblyFile = getAssemblyFile(directory); + return loadAssemblyFromFile(assemblyFile); +} + +/** + * Loads the assembly file and unzips compressed assemblies. + * + * @param pathToFile the path to the assembly file + * @returns the assembly file as json + */ +export function loadAssemblyFromFile(pathToFile: string) { + const extname = path.extname(pathToFile); + if (extname === '.gz') { + return readZippedAssembly(pathToFile); + } else if (extname === '') { + return readAssembly(pathToFile); + } + + throw new Error( + `Assembly file must be named ${SPEC_FILE_NAME} or ${SPEC_FILE_NAME_COMPRESSED} but got ${path.basename( + pathToFile, + )}`, + ); +} + +function readAssembly(pathToFile: string) { + return fs.readJsonSync(pathToFile, { + encoding: 'utf-8', + }); +} + +function readZippedAssembly(pathToFile: string) { + return JSON.parse(zlib.gunzipSync(fs.readFileSync(pathToFile)).toString()); +} diff --git a/packages/@jsii/utils/lib/index.ts b/packages/@jsii/utils/lib/index.ts new file mode 100644 index 0000000000..b407c85a37 --- /dev/null +++ b/packages/@jsii/utils/lib/index.ts @@ -0,0 +1 @@ +export * from './assembly'; diff --git a/packages/@jsii/utils/package.json b/packages/@jsii/utils/package.json new file mode 100644 index 0000000000..8536950ac7 --- /dev/null +++ b/packages/@jsii/utils/package.json @@ -0,0 +1,37 @@ +{ + "name": "@jsii/utils", + "version": "0.0.0", + "description": "Utility functions for jsii assemblies", + "license": "Apache-2.0", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "homepage": "https://github.com/aws/jsii", + "bugs": { + "url": "https://github.com/aws/jsii/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/jsii.git", + "directory": "packages/@jsii/utils" + }, + "engines": { + "node": ">= 12.7.0" + }, + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc --build && npm run lint", + "watch": "tsc --build -w", + "lint": "eslint . --ext .js,.ts --ignore-path=.gitignore --ignore-pattern=webpack.config.js", + "lint:fix": "yarn lint --fix", + "test": "jest", + "test:update": "jest -u", + "package": "package-js" + }, + "dependencies": { + "fs-extra": "^10.1.0", + "@jsii/spec": "^0.0.0" + } +} diff --git a/packages/@jsii/utils/test/assembly.test.ts b/packages/@jsii/utils/test/assembly.test.ts new file mode 100644 index 0000000000..e16920c20f --- /dev/null +++ b/packages/@jsii/utils/test/assembly.test.ts @@ -0,0 +1,111 @@ +import * as spec from '@jsii/spec'; +import * as fs from 'fs-extra'; +import * as os from 'os'; +import * as path from 'path'; + +import { + loadAssemblyFromPath, + getAssemblyFile, + writeAssembly, + SPEC_FILE_NAME, + SPEC_FILE_NAME_COMPRESSED, +} from '../lib'; + +const TEST_ASSEMBLY: spec.Assembly = { + schema: spec.SchemaVersion.LATEST, + name: 'jsii-test-dep', + version: '1.2.4', + license: 'Apache-2.0', + description: 'A test assembly', + homepage: 'https://github.com/aws/jsii', + repository: { type: 'git', url: 'git://github.com/aws/jsii.git' }, + author: { + name: 'Amazon Web Services', + url: 'https://aws.amazon.com', + organization: true, + roles: ['author'], + }, + fingerprint: 'F1NG3RPR1N7', + dependencies: { + 'jsii-test-dep-dep': '3.2.1', + }, + jsiiVersion: '1.0.0', +}; + +describe('writeAssembly', () => { + test('can write compressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, true); + + expect( + fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED)), + ).toBeTruthy(); + }); + + test('can write uncompressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, false); + + expect(fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME))).toBeTruthy(); + }); +}); + +describe('getAssemblyFile', () => { + test('finds compressed assembly file', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, true); + + expect(getAssemblyFile(tmpdir)).toEqual( + path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED), + ); + }); + + test('finds uncompressed assembly file', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, false); + + expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); + }); + + test('prefers compressed file over uncompressed file', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, true); + writeAssembly(tmpdir, TEST_ASSEMBLY, false); + + expect(getAssemblyFile(tmpdir)).toEqual( + path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED), + ); + }); +}); + +describe('loadAssemblyFromPath', () => { + test('loads compressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, true); + + expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); + }); + + test('loads uncompressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, false); + + expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); + }); + + test('compressed and uncompressed assemblies are loaded identically', () => { + const compressedTmpDir = makeTempDir(); + const uncompressedTmpDir = makeTempDir(); + + writeAssembly(compressedTmpDir, TEST_ASSEMBLY, true); + writeAssembly(uncompressedTmpDir, TEST_ASSEMBLY, false); + + expect(loadAssemblyFromPath(compressedTmpDir)).toEqual( + loadAssemblyFromPath(uncompressedTmpDir), + ); + }); +}); + +function makeTempDir() { + return fs.mkdtempSync(path.join(os.tmpdir(), path.basename(__filename))); +} diff --git a/packages/@jsii/utils/tsconfig.json b/packages/@jsii/utils/tsconfig.json new file mode 100644 index 0000000000..61da87ff70 --- /dev/null +++ b/packages/@jsii/utils/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig-base", + "include": ["**/*.ts"], + "exclude": ["jest.config.ts"] +} From 74bd29c4d95bde02031252838e7b287dd172eb11 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 2 Jun 2022 18:52:22 -0400 Subject: [PATCH 02/41] update readme and package.json --- packages/@jsii/utils/README.md | 3 +++ packages/@jsii/utils/package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/@jsii/utils/README.md b/packages/@jsii/utils/README.md index e69de29bb2..38e3124455 100644 --- a/packages/@jsii/utils/README.md +++ b/packages/@jsii/utils/README.md @@ -0,0 +1,3 @@ +### jsii Utility Function Library + +This library stores utility functions to be used by modules that consume jsii. \ No newline at end of file diff --git a/packages/@jsii/utils/package.json b/packages/@jsii/utils/package.json index 8536950ac7..2100b27e7c 100644 --- a/packages/@jsii/utils/package.json +++ b/packages/@jsii/utils/package.json @@ -1,7 +1,7 @@ { "name": "@jsii/utils", "version": "0.0.0", - "description": "Utility functions for jsii assemblies", + "description": "Utility functions for jsii modules", "license": "Apache-2.0", "author": { "name": "Amazon Web Services", From 5bd3929010a423cf299d039077a552e6270c2577 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 2 Jun 2022 19:01:04 -0400 Subject: [PATCH 03/41] prove that new module works --- packages/jsii/lib/assembler.ts | 17 +++++++++++------ packages/jsii/package.json | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index bb8b902064..fd82cdc63c 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -1,5 +1,6 @@ import * as spec from '@jsii/spec'; import { PackageJson } from '@jsii/spec'; +import { writeAssembly, SPEC_FILE_NAME } from '@jsii/utils'; import * as Case from 'case'; import * as chalk from 'chalk'; import * as crypto from 'crypto'; @@ -277,12 +278,16 @@ export class Assembler implements Emitter { const validator = new Validator(this.projectInfo, assembly); const validationResult = validator.emit(); if (!validationResult.emitSkipped) { - const assemblyPath = path.join(this.projectInfo.projectRoot, '.jsii'); - LOG.trace(`Emitting assembly: ${chalk.blue(assemblyPath)}`); - fs.writeJsonSync(assemblyPath, _fingerprint(assembly), { - encoding: 'utf8', - spaces: 2, - }); + LOG.trace( + `Emitting assembly: ${chalk.blue( + path.join(this.projectInfo.projectRoot, SPEC_FILE_NAME), + )}`, + ); + writeAssembly( + this.projectInfo.projectRoot, + _fingerprint(assembly), + false, + ); } try { diff --git a/packages/jsii/package.json b/packages/jsii/package.json index 37a92f77e5..466c340d7b 100644 --- a/packages/jsii/package.json +++ b/packages/jsii/package.json @@ -37,6 +37,7 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "^0.0.0", + "@jsii/utils": "^0.0.0", "case": "^1.6.3", "chalk": "^4", "deep-equal": "^2.0.5", From 759b7d7650a3ffbe561b3fe9c4c6a7bd48748efb Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Fri, 3 Jun 2022 11:48:10 -0400 Subject: [PATCH 04/41] move spec file names to @jsii/spec and re-export in @jsii/utils --- packages/@jsii/spec/src/assembly.ts | 1 + packages/@jsii/utils/lib/assembly.ts | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@jsii/spec/src/assembly.ts b/packages/@jsii/spec/src/assembly.ts index 7fc1a165d7..10d28735c2 100644 --- a/packages/@jsii/spec/src/assembly.ts +++ b/packages/@jsii/spec/src/assembly.ts @@ -1,4 +1,5 @@ export const SPEC_FILE_NAME = '.jsii'; +export const SPEC_FILE_NAME_COMPRESSED = `${SPEC_FILE_NAME}.gz`; /** * A JSII assembly specification. diff --git a/packages/@jsii/utils/lib/assembly.ts b/packages/@jsii/utils/lib/assembly.ts index fe4f03d2fb..2b1dbd7def 100644 --- a/packages/@jsii/utils/lib/assembly.ts +++ b/packages/@jsii/utils/lib/assembly.ts @@ -3,8 +3,8 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as zlib from 'zlib'; -export const SPEC_FILE_NAME = '.jsii'; -export const SPEC_FILE_NAME_COMPRESSED = `${SPEC_FILE_NAME}.gz`; +export const SPEC_FILE_NAME = spec.SPEC_FILE_NAME; +export const SPEC_FILE_NAME_COMPRESSED = spec.SPEC_FILE_NAME_COMPRESSED; /** * Finds the path to the assembly file, which will be @@ -43,7 +43,6 @@ export function writeAssembly( zip: boolean, ) { if (zip) { - // TODO: also write .jsii fs.writeFileSync( path.join(directory, SPEC_FILE_NAME_COMPRESSED), zlib.gzipSync(JSON.stringify(assembly)), From ca54f787f7a785e8e18b7f1df240e2d36d3043e1 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Fri, 3 Jun 2022 12:33:28 -0400 Subject: [PATCH 05/41] update project structure for out-of-source building --- packages/@jsii/utils/.npmignore | 2 -- packages/@jsii/utils/{test => src}/assembly.test.ts | 2 +- packages/@jsii/utils/{lib => src}/assembly.ts | 0 packages/@jsii/utils/{lib => src}/index.ts | 0 packages/@jsii/utils/tsconfig.json | 9 +++++++-- 5 files changed, 8 insertions(+), 5 deletions(-) rename packages/@jsii/utils/{test => src}/assembly.test.ts (99%) rename packages/@jsii/utils/{lib => src}/assembly.ts (100%) rename packages/@jsii/utils/{lib => src}/index.ts (100%) diff --git a/packages/@jsii/utils/.npmignore b/packages/@jsii/utils/.npmignore index 4fd6a03ff5..db723ea806 100644 --- a/packages/@jsii/utils/.npmignore +++ b/packages/@jsii/utils/.npmignore @@ -2,8 +2,6 @@ !**/*.js !**/*.d.ts -!bin/jsii -!bin/jsii-fix-peers coverage diff --git a/packages/@jsii/utils/test/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts similarity index 99% rename from packages/@jsii/utils/test/assembly.test.ts rename to packages/@jsii/utils/src/assembly.test.ts index e16920c20f..72a4edbca8 100644 --- a/packages/@jsii/utils/test/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -9,7 +9,7 @@ import { writeAssembly, SPEC_FILE_NAME, SPEC_FILE_NAME_COMPRESSED, -} from '../lib'; +} from './assembly'; const TEST_ASSEMBLY: spec.Assembly = { schema: spec.SchemaVersion.LATEST, diff --git a/packages/@jsii/utils/lib/assembly.ts b/packages/@jsii/utils/src/assembly.ts similarity index 100% rename from packages/@jsii/utils/lib/assembly.ts rename to packages/@jsii/utils/src/assembly.ts diff --git a/packages/@jsii/utils/lib/index.ts b/packages/@jsii/utils/src/index.ts similarity index 100% rename from packages/@jsii/utils/lib/index.ts rename to packages/@jsii/utils/src/index.ts diff --git a/packages/@jsii/utils/tsconfig.json b/packages/@jsii/utils/tsconfig.json index 61da87ff70..543407f66c 100644 --- a/packages/@jsii/utils/tsconfig.json +++ b/packages/@jsii/utils/tsconfig.json @@ -1,5 +1,10 @@ { "extends": "../../../tsconfig-base", - "include": ["**/*.ts"], - "exclude": ["jest.config.ts"] + "compilerOptions": { + "rootDir": "src", + "outDir": "lib", + }, + "include": [ + "src/**/*.ts" + ], } From c802eb23eba57fb30e041b31c77b4983306e7d87 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Fri, 3 Jun 2022 14:06:15 -0400 Subject: [PATCH 06/41] getAssemblyFile returns path to SPEC_FILE_NAME, and loadAssemblyFromPath always loads SPEC_FILE_NAME first --- packages/@jsii/utils/src/assembly.test.ts | 28 +++++---- packages/@jsii/utils/src/assembly.ts | 70 +++++++++++++++-------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index 72a4edbca8..ac142242d6 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -40,6 +40,16 @@ describe('writeAssembly', () => { expect( fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED)), ).toBeTruthy(); + + // includes .jsii files with instructions for finding compressed file + const instructions = fs.readJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { + encoding: 'utf-8', + }); + expect(instructions).toEqual({ + schema: 'jsii/file-redirect', + compression: 'gzip', + filename: SPEC_FILE_NAME_COMPRESSED, + }); }); test('can write uncompressed assembly', () => { @@ -51,30 +61,18 @@ describe('writeAssembly', () => { }); describe('getAssemblyFile', () => { - test('finds compressed assembly file', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, true); - - expect(getAssemblyFile(tmpdir)).toEqual( - path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED), - ); - }); - - test('finds uncompressed assembly file', () => { + test('finds SPEC_FILE_NAME file when there is no compression', () => { const tmpdir = makeTempDir(); writeAssembly(tmpdir, TEST_ASSEMBLY, false); expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); }); - test('prefers compressed file over uncompressed file', () => { + test('finds SPEC_FILE_NAME file even when there is compression', () => { const tmpdir = makeTempDir(); writeAssembly(tmpdir, TEST_ASSEMBLY, true); - writeAssembly(tmpdir, TEST_ASSEMBLY, false); - expect(getAssemblyFile(tmpdir)).toEqual( - path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED), - ); + expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); }); }); diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 2b1dbd7def..99ff370e21 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -7,26 +7,22 @@ export const SPEC_FILE_NAME = spec.SPEC_FILE_NAME; export const SPEC_FILE_NAME_COMPRESSED = spec.SPEC_FILE_NAME_COMPRESSED; /** - * Finds the path to the assembly file, which will be - * '.jsii' if uncompressed and '.jsii.gz' if compressed. + * Finds the path to the SPEC_FILE_NAME file, which will either + * be the assembly or hold instructions to find the assembly. * * @param directory path to a directory with an assembly file * @returns path to the assembly file */ export function getAssemblyFile(directory: string) { - const compressedJsiiFile = path.join(directory, SPEC_FILE_NAME_COMPRESSED); - const compressedJsiiExists = fs.existsSync(compressedJsiiFile); + const dotJsiiFile = path.join(directory, SPEC_FILE_NAME); - const uncompressedJsiiFile = path.join(directory, SPEC_FILE_NAME); - const uncompressedJsiiExists = fs.existsSync(uncompressedJsiiFile); - - if (!compressedJsiiExists && !uncompressedJsiiExists) { + if (!fs.existsSync(dotJsiiFile)) { throw new Error( - `No ${SPEC_FILE_NAME} or ${SPEC_FILE_NAME_COMPRESSED} assembly file was found at ${directory}`, + `Expected to find ${SPEC_FILE_NAME} file in ${directory}, but no such file found`, ); } - return compressedJsiiExists ? compressedJsiiFile : uncompressedJsiiFile; + return dotJsiiFile; } /** @@ -43,6 +39,14 @@ export function writeAssembly( zip: boolean, ) { if (zip) { + // write .jsii file with instructions on opening the compressed file + fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), { + schema: 'jsii/file-redirect', + compression: 'gzip', + filename: SPEC_FILE_NAME_COMPRESSED, + }); + + // write actual assembly contents in .jsii.gz fs.writeFileSync( path.join(directory, SPEC_FILE_NAME_COMPRESSED), zlib.gzipSync(JSON.stringify(assembly)), @@ -55,7 +59,8 @@ export function writeAssembly( } /** - * Loads the assembly file and unzips compressed assemblies. + * Loads the assembly file and, if present, follows instructions + * found in the file to unzip compressed assemblies. * * @param directory the directory of the assembly file * @returns the assembly file as json @@ -66,24 +71,21 @@ export function loadAssemblyFromPath(directory: string) { } /** - * Loads the assembly file and unzips compressed assemblies. + * Loads the assembly file and, if present, follows instructions + * found in the file to unzip compressed assemblies. * - * @param pathToFile the path to the assembly file + * @param pathToFile the path to the SPEC_FILE_NAME file * @returns the assembly file as json */ export function loadAssemblyFromFile(pathToFile: string) { - const extname = path.extname(pathToFile); - if (extname === '.gz') { - return readZippedAssembly(pathToFile); - } else if (extname === '') { - return readAssembly(pathToFile); + const contents = readAssembly(pathToFile); + + // check if the file holds instructions to the actual assembly file + if (contents.schema === 'jsii/file-redirect') { + return findRedirectAssembly(pathToFile, contents); } - throw new Error( - `Assembly file must be named ${SPEC_FILE_NAME} or ${SPEC_FILE_NAME_COMPRESSED} but got ${path.basename( - pathToFile, - )}`, - ); + return contents; } function readAssembly(pathToFile: string) { @@ -92,6 +94,24 @@ function readAssembly(pathToFile: string) { }); } -function readZippedAssembly(pathToFile: string) { - return JSON.parse(zlib.gunzipSync(fs.readFileSync(pathToFile)).toString()); +function findRedirectAssembly( + pathToFile: string, + contents: Record, +) { + validateRedirectSchema(contents); + const redirectAssemblyFile = path.join( + path.dirname(pathToFile), + contents.filename, + ); + return JSON.parse( + zlib.gunzipSync(fs.readFileSync(redirectAssemblyFile)).toString(), + ); +} + +function validateRedirectSchema(contents: Record) { + if (contents.compression !== 'gzip' || contents.filename === undefined) { + throw new Error( + `Invalid redirect schema: compression must be gzip and filename must exist`, + ); + } } From 7d75f79b5aa9601414b2fcaa920ed60990b34eb4 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Fri, 3 Jun 2022 14:12:04 -0400 Subject: [PATCH 07/41] add tests on error messages --- packages/@jsii/utils/src/assembly.test.ts | 21 +++++++++++++++++++++ packages/@jsii/utils/src/assembly.ts | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index ac142242d6..2b390e870d 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -74,6 +74,14 @@ describe('getAssemblyFile', () => { expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); }); + + test('throws if SPEC_FILE_NAME file does not exist', () => { + const tmpdir = makeTempDir(); + + expect(() => getAssemblyFile(tmpdir)).toThrow( + `Expected to find ${SPEC_FILE_NAME} file in ${tmpdir}, but no such file found`, + ); + }); }); describe('loadAssemblyFromPath', () => { @@ -102,6 +110,19 @@ describe('loadAssemblyFromPath', () => { loadAssemblyFromPath(uncompressedTmpDir), ); }); + + test('throws if redirect schema is invalid', () => { + const tmpdir = makeTempDir(); + fs.writeJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { + schema: 'jsii/file-redirect', + compression: 'gzip', + // missing filename + }); + + expect(() => loadAssemblyFromPath(tmpdir)).toThrow( + 'Invalid redirect schema: compression must be gzip and filename must exist', + ); + }); }); function makeTempDir() { diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 99ff370e21..3bf378fdf7 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -11,7 +11,7 @@ export const SPEC_FILE_NAME_COMPRESSED = spec.SPEC_FILE_NAME_COMPRESSED; * be the assembly or hold instructions to find the assembly. * * @param directory path to a directory with an assembly file - * @returns path to the assembly file + * @returns path to the SPEC_FILE_NAME file */ export function getAssemblyFile(directory: string) { const dotJsiiFile = path.join(directory, SPEC_FILE_NAME); @@ -111,7 +111,7 @@ function findRedirectAssembly( function validateRedirectSchema(contents: Record) { if (contents.compression !== 'gzip' || contents.filename === undefined) { throw new Error( - `Invalid redirect schema: compression must be gzip and filename must exist`, + 'Invalid redirect schema: compression must be gzip and filename must exist', ); } } From b6abc5d2ecc64bc68a56ae0653d7cf7ced67667e Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Fri, 3 Jun 2022 15:22:02 -0400 Subject: [PATCH 08/41] fix formatting for writing assembly --- packages/@jsii/utils/src/assembly.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 3bf378fdf7..0ce74694fb 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -52,7 +52,10 @@ export function writeAssembly( zlib.gzipSync(JSON.stringify(assembly)), ); } else { - fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), assembly); + fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), assembly, { + encoding: 'utf8', + spaces: 2, + }); } return zip; From b820c0daaa9dbb97f23738b6b72691330e876040 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 14:44:36 -0400 Subject: [PATCH 09/41] add command line option compressAssembly --- packages/jsii/bin/jsii.ts | 6 ++++++ packages/jsii/lib/assembler.ts | 22 ++++++++++++++++------ packages/jsii/lib/compiler.ts | 6 ++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/jsii/bin/jsii.ts b/packages/jsii/bin/jsii.ts index bda4da504e..a8c1e5d3b4 100644 --- a/packages/jsii/bin/jsii.ts +++ b/packages/jsii/bin/jsii.ts @@ -69,6 +69,11 @@ const warningTypes = Object.keys(enabledWarnings); type: 'string', default: 'tsconfig.json', desc: 'Name of the typescript configuration file to generate with compiler settings', + }) + .option('compress-assembly', { + type: 'boolean', + default: false, + desc: 'Emit a compressed version of the assembly', }), ) .option('verbose', { @@ -115,6 +120,7 @@ const warningTypes = Object.keys(enabledWarnings); stripDeprecatedAllowListFile: argv['strip-deprecated'], addDeprecationWarnings: argv['add-deprecation-warnings'], generateTypeScriptConfig: argv['generate-tsconfig'], + compressAssembly: argv['compress-assembly'], }); const emitResult = argv.watch ? await compiler.watch() : compiler.emit(); diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index fd82cdc63c..cd79101254 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -46,6 +46,7 @@ export class Assembler implements Emitter { private readonly mainFile: string; private readonly tscRootDir?: string; + private readonly compressAssembly?: boolean; private _diagnostics = new Array(); private _deferred = new Array(); @@ -106,6 +107,8 @@ export class Assembler implements Emitter { ); } + this.compressAssembly = options.compressAssembly; + const dts = projectInfo.types; let mainFile = dts.replace(/\.d\.ts(x?)$/, '.ts$1'); @@ -278,16 +281,16 @@ export class Assembler implements Emitter { const validator = new Validator(this.projectInfo, assembly); const validationResult = validator.emit(); if (!validationResult.emitSkipped) { + const zipped = writeAssembly( + this.projectInfo.projectRoot, + _fingerprint(assembly), + this.compressAssembly ?? false, + ); LOG.trace( - `Emitting assembly: ${chalk.blue( + `${zipped ? 'Zipping' : 'Emitting'} assembly: ${chalk.blue( path.join(this.projectInfo.projectRoot, SPEC_FILE_NAME), )}`, ); - writeAssembly( - this.projectInfo.projectRoot, - _fingerprint(assembly), - false, - ); } try { @@ -2732,6 +2735,13 @@ export interface AssemblerOptions { * @default false */ readonly addDeprecationWarnings?: boolean; + + /** + * Whether to compress the assembly. + * + * @default false + */ + readonly compressAssembly?: boolean; } interface SubmoduleSpec { diff --git a/packages/jsii/lib/compiler.ts b/packages/jsii/lib/compiler.ts index ec3b3c4a09..943b723377 100644 --- a/packages/jsii/lib/compiler.ts +++ b/packages/jsii/lib/compiler.ts @@ -60,6 +60,11 @@ export interface CompilerOptions { * @default "tsconfig.json" */ generateTypeScriptConfig?: string; + /** + * Whether to compress the assembly + * @default false + */ + compressAssembly?: boolean; } export interface TypescriptConfig { @@ -248,6 +253,7 @@ export class Compiler implements Emitter { stripDeprecated: this.options.stripDeprecated, stripDeprecatedAllowListFile: this.options.stripDeprecatedAllowListFile, addDeprecationWarnings: this.options.addDeprecationWarnings, + compressAssembly: this.options.compressAssembly, }); try { From 8f0f909b0763c474078c04d48bdb6923af274e04 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 15:48:12 -0400 Subject: [PATCH 10/41] jsii-reflect change wip --- packages/jsii-reflect/lib/type-system.ts | 14 ++++++-------- packages/jsii-reflect/package.json | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/jsii-reflect/lib/type-system.ts b/packages/jsii-reflect/lib/type-system.ts index 0b696ebe0d..e12f32c3b9 100644 --- a/packages/jsii-reflect/lib/type-system.ts +++ b/packages/jsii-reflect/lib/type-system.ts @@ -1,4 +1,5 @@ import * as jsii from '@jsii/spec'; +import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -109,10 +110,7 @@ export class TypeSystem { // Load the assembly, but don't recurse if we already have an assembly with the same name. // Validation is not an insignificant time sink, and loading IS insignificant, so do a // load without validation first. This saves about 2/3rds of processing time. - const asm = await this.loadAssembly( - path.join(moduleDirectory, '.jsii'), - false, - ); + const asm = this.loadAssembly(getAssemblyFile(moduleDirectory), false); if (this.includesAssembly(asm.name)) { const existing = this.findAssembly(asm.name); if (existing.version !== asm.version) { @@ -154,11 +152,11 @@ export class TypeSystem { } } - public async loadFile( + public loadFile( file: string, options: { isRoot?: boolean; validate?: boolean } = {}, ) { - const assembly = await this.loadAssembly(file, options.validate !== false); + const assembly = this.loadAssembly(file, options.validate !== false); return this.addAssembly(assembly, options); } @@ -308,8 +306,8 @@ export class TypeSystem { * @param file Assembly file to load * @param validate Whether to validate the assembly or just assume it matches the schema */ - private async loadAssembly(file: string, validate = true) { - const spec = JSON.parse(await fs.readFile(file, { encoding: 'utf-8' })); + private loadAssembly(file: string, validate = true) { + const spec = loadAssemblyFromFile(file); const ass = validate ? jsii.validateAssembly(spec) : (spec as jsii.Assembly); diff --git a/packages/jsii-reflect/package.json b/packages/jsii-reflect/package.json index b614855cb8..0da940779c 100644 --- a/packages/jsii-reflect/package.json +++ b/packages/jsii-reflect/package.json @@ -36,6 +36,7 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "^0.0.0", + "@jsii/utils": "^0.0.0", "chalk": "^4", "fs-extra": "^10.1.0", "oo-ascii-tree": "^0.0.0", From f60a57a07755605f899532cbbd8b37780934a1e2 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 17:04:09 -0400 Subject: [PATCH 11/41] add validation prop to load assembly --- packages/@jsii/utils/src/assembly.test.ts | 16 +++++++++++++++ packages/@jsii/utils/src/assembly.ts | 24 ++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index 2b390e870d..dde2ec8434 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -123,6 +123,22 @@ describe('loadAssemblyFromPath', () => { 'Invalid redirect schema: compression must be gzip and filename must exist', ); }); + + test('throws if assembly is invalid', () => { + const tmpdir = makeTempDir(); + fs.writeJsonSync( + path.join(tmpdir, SPEC_FILE_NAME), + { + assembly: 'not a valid assembly', + }, + { + encoding: 'utf8', + spaces: 2, + }, + ); + + expect(() => loadAssemblyFromPath(tmpdir)).toThrow(/Invalid assembly/); + }); }); function makeTempDir() { diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 0ce74694fb..c10a4835a7 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -30,15 +30,15 @@ export function getAssemblyFile(directory: string) { * * @param directory the directory path to place the assembly file * @param assembly the contents of the assembly - * @param zip whether or not to zip the assembly (.jsii.gz) + * @param compress whether or not to zip the assembly (.jsii.gz) * @returns whether or not the assembly was zipped */ export function writeAssembly( directory: string, assembly: spec.Assembly, - zip: boolean, + compress = false, ) { - if (zip) { + if (compress) { // write .jsii file with instructions on opening the compressed file fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), { schema: 'jsii/file-redirect', @@ -58,7 +58,7 @@ export function writeAssembly( }); } - return zip; + return compress; } /** @@ -68,7 +68,7 @@ export function writeAssembly( * @param directory the directory of the assembly file * @returns the assembly file as json */ -export function loadAssemblyFromPath(directory: string) { +export function loadAssemblyFromPath(directory: string): spec.Assembly { const assemblyFile = getAssemblyFile(directory); return loadAssemblyFromFile(assemblyFile); } @@ -78,17 +78,23 @@ export function loadAssemblyFromPath(directory: string) { * found in the file to unzip compressed assemblies. * * @param pathToFile the path to the SPEC_FILE_NAME file + * @param validate whether to validate the contents of the file * @returns the assembly file as json */ -export function loadAssemblyFromFile(pathToFile: string) { - const contents = readAssembly(pathToFile); +export function loadAssemblyFromFile( + pathToFile: string, + validate = true, +): spec.Assembly { + let contents = readAssembly(pathToFile); // check if the file holds instructions to the actual assembly file if (contents.schema === 'jsii/file-redirect') { - return findRedirectAssembly(pathToFile, contents); + contents = findRedirectAssembly(pathToFile, contents); } - return contents; + return validate + ? spec.validateAssembly(contents) + : (contents as spec.Assembly); } function readAssembly(pathToFile: string) { From ded10362ccfeced23a17440350cf05a5d7d8366b Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 17:07:31 -0400 Subject: [PATCH 12/41] more progress --- packages/jsii-reflect/lib/type-system.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/jsii-reflect/lib/type-system.ts b/packages/jsii-reflect/lib/type-system.ts index e12f32c3b9..20cf647fb8 100644 --- a/packages/jsii-reflect/lib/type-system.ts +++ b/packages/jsii-reflect/lib/type-system.ts @@ -301,19 +301,6 @@ export class TypeSystem { return out; } - /** - * Load an assembly without adding it to the typesystem - * @param file Assembly file to load - * @param validate Whether to validate the assembly or just assume it matches the schema - */ - private loadAssembly(file: string, validate = true) { - const spec = loadAssemblyFromFile(file); - const ass = validate - ? jsii.validateAssembly(spec) - : (spec as jsii.Assembly); - return new Assembly(this, ass); - } - private addRoot(asm: Assembly) { if (!this.roots.map((r) => r.name).includes(asm.name)) { this.roots.push(asm); From 7742e784d556afd377f136cc446d4365694478ca Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 17:08:06 -0400 Subject: [PATCH 13/41] add validate to loadfrompath --- packages/@jsii/utils/src/assembly.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index c10a4835a7..1cd7684653 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -66,11 +66,15 @@ export function writeAssembly( * found in the file to unzip compressed assemblies. * * @param directory the directory of the assembly file + * @param validate whether to validate the contents of the file * @returns the assembly file as json */ -export function loadAssemblyFromPath(directory: string): spec.Assembly { +export function loadAssemblyFromPath( + directory: string, + validate = true, +): spec.Assembly { const assemblyFile = getAssemblyFile(directory); - return loadAssemblyFromFile(assemblyFile); + return loadAssemblyFromFile(assemblyFile, validate); } /** From 7f31887ffe830b8c989fc3e7beff30d0fab04f35 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Wed, 8 Jun 2022 17:10:41 -0400 Subject: [PATCH 14/41] fix type-system.ts --- packages/jsii-reflect/lib/type-system.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/jsii-reflect/lib/type-system.ts b/packages/jsii-reflect/lib/type-system.ts index 20cf647fb8..296c09885d 100644 --- a/packages/jsii-reflect/lib/type-system.ts +++ b/packages/jsii-reflect/lib/type-system.ts @@ -1,4 +1,3 @@ -import * as jsii from '@jsii/spec'; import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -301,6 +300,16 @@ export class TypeSystem { return out; } + /** + * Load an assembly without adding it to the typesystem + * @param file Assembly file to load + * @param validate Whether to validate the assembly or just assume it matches the schema + */ + private loadAssembly(file: string, validate = true) { + const contents = loadAssemblyFromFile(file, validate); + return new Assembly(this, contents); + } + private addRoot(asm: Assembly) { if (!this.roots.map((r) => r.name).includes(asm.name)) { this.roots.push(asm); From 7827f02f79771d33b9008e8c28ae68c417f7046b Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jun 2022 18:11:53 -0400 Subject: [PATCH 15/41] changes to jsii --- packages/jsii/lib/helpers.ts | 33 +++++++++++-- packages/jsii/lib/project-info.ts | 19 ++------ packages/jsii/test/compiler.test.ts | 63 +++++++++++++++++++++++-- packages/jsii/test/project-info.test.ts | 40 +++++++++++++++- 4 files changed, 129 insertions(+), 26 deletions(-) diff --git a/packages/jsii/lib/helpers.ts b/packages/jsii/lib/helpers.ts index 4e3300310f..eca970ff48 100644 --- a/packages/jsii/lib/helpers.ts +++ b/packages/jsii/lib/helpers.ts @@ -8,6 +8,7 @@ import * as spec from '@jsii/spec'; import { PackageJson } from '@jsii/spec'; +import { loadAssemblyFromPath, writeAssembly } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as os from 'os'; import * as path from 'path'; @@ -47,6 +48,7 @@ export interface HelperCompilationResult { * The generated assembly */ readonly assembly: spec.Assembly; + /** * Generated .js/.d.ts file(s) */ @@ -56,6 +58,11 @@ export interface HelperCompilationResult { * The packageInfo used */ readonly packageJson: PackageJson; + + /** + * Whether to compress the assembly file + */ + readonly compressAssembly: boolean; } /** @@ -116,7 +123,7 @@ export function compileJsiiForTest( if (errors.length > 0 || emitResult.emitSkipped) { throw new Error('There were compiler errors'); } - const assembly = fs.readJsonSync('.jsii', { encoding: 'utf-8' }); + const assembly = loadAssemblyFromPath(process.cwd()); const files: Record = {}; for (const filename of Object.keys(source)) { @@ -141,7 +148,13 @@ export function compileJsiiForTest( } } - return { assembly, files, packageJson } as HelperCompilationResult; + return { + assembly, + files, + packageJson, + compressAssembly: + isOptionsObject(options) && options.compressAssembly ? true : false, + } as HelperCompilationResult; }); } @@ -205,6 +218,7 @@ function makeProjectInfo( const { projectInfo } = loadProjectInfo(path.resolve(process.cwd(), '.')); return { projectInfo, packageJson }; } + export interface TestCompilationOptions { /** * The directory in which we write and compile the files @@ -224,6 +238,13 @@ export interface TestCompilationOptions { * @default - Use some default values */ readonly packageJson?: Partial; + + /** + * Whether to compress the assembly file. + * + * @default false + */ + readonly compressAssembly?: boolean; } function isOptionsObject( @@ -287,7 +308,11 @@ export class TestWorkspace { ); fs.ensureDirSync(modDir); - fs.writeJsonSync(path.join(modDir, '.jsii'), dependencyAssembly.assembly); + writeAssembly( + modDir, + dependencyAssembly.assembly, + dependencyAssembly.compressAssembly, + ); fs.writeJsonSync( path.join(modDir, 'package.json'), dependencyAssembly.packageJson, @@ -296,9 +321,7 @@ export class TestWorkspace { for (const [fileName, fileContents] of Object.entries( dependencyAssembly.files, )) { - // eslint-disable-next-line no-await-in-loop fs.ensureDirSync(path.dirname(path.join(modDir, fileName))); - // eslint-disable-next-line no-await-in-loop fs.writeFileSync(path.join(modDir, fileName), fileContents); } } diff --git a/packages/jsii/lib/project-info.ts b/packages/jsii/lib/project-info.ts index a514d2c088..3e91aecb03 100644 --- a/packages/jsii/lib/project-info.ts +++ b/packages/jsii/lib/project-info.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as log4js from 'log4js'; import * as path from 'path'; @@ -361,10 +362,9 @@ class DependencyResolver { return this.cache.get(jsiiFile)!; } - // eslint-disable-next-line no-await-in-loop - const assembly = this.loadAssembly(jsiiFile); - // Continue loading any dependencies declared in the asm + const assembly = loadAssemblyFromFile(jsiiFile); + // Continue loading any dependencies declared in the asm const resolvedDependencies = assembly.dependencies ? this.discoverDependencyTree( path.dirname(jsiiFile), @@ -379,17 +379,6 @@ class DependencyResolver { this.cache.set(jsiiFile, depInfo); return depInfo; } - - /** - * Load a JSII filename and validate it; cached to avoid redundant loads of the same JSII assembly - */ - private loadAssembly(jsiiFileName: string): spec.Assembly { - try { - return fs.readJsonSync(jsiiFileName); - } catch (e: any) { - throw new Error(`Error loading ${jsiiFileName}: ${e}`); - } - } } function _required(value: T, message: string): T { @@ -443,7 +432,7 @@ function _tryResolveAssembly( searchPath: string, ): string { if (localPackage) { - const result = path.join(localPackage, '.jsii'); + const result = getAssemblyFile(localPackage); if (!fs.existsSync(result)) { throw new Error(`Assembly does not exist: ${result}`); } diff --git a/packages/jsii/test/compiler.test.ts b/packages/jsii/test/compiler.test.ts index e8a3131c35..3d2faf378a 100644 --- a/packages/jsii/test/compiler.test.ts +++ b/packages/jsii/test/compiler.test.ts @@ -1,5 +1,7 @@ +import { loadAssemblyFromPath } from '@jsii/utils'; import { ensureDirSync, + existsSync, mkdtempSync, removeSync, writeFileSync, @@ -82,9 +84,7 @@ describe(Compiler, () => { compilationComplete: (emitResult) => { try { expect(emitResult.emitSkipped).toBeFalsy(); - const output = readFileSync(join(sourceDir, '.jsii'), { - encoding: 'utf-8', - }); + const output = JSON.stringify(loadAssemblyFromPath(sourceDir)); if (firstCompilation) { firstCompilation = false; expect(output).toContain('"MarkerA"'); @@ -138,7 +138,7 @@ describe(Compiler, () => { compiler.emit(); - const assembly = readJsonSync(join(sourceDir, '.jsii'), 'utf-8'); + const assembly = loadAssemblyFromPath(sourceDir); expect(assembly.metadata).toEqual( expect.objectContaining({ tscRootDir: rootDir, @@ -174,6 +174,61 @@ describe(Compiler, () => { removeSync(sourceDir); } }); + + describe('compressed assembly option', () => { + test('creates a gzipped assembly file', () => { + const sourceDir = mkdtempSync(join(tmpdir(), 'jsii-tmpdir')); + + try { + writeFileSync(join(sourceDir, 'index.ts'), 'export class MarkerA {}'); + + const compiler = new Compiler({ + projectInfo: _makeProjectInfo(sourceDir, 'index.d.ts'), + compressAssembly: true, + }); + + compiler.emit(); + + expect(existsSync(join(sourceDir, '.jsii.gz'))).toBeTruthy(); + } finally { + removeSync(sourceDir); + } + }); + + test('creates file equivalent to uncompressed file', () => { + const uncompressedSourceDir = mkdtempSync(join(tmpdir(), 'jsii-tmpdir')); + const compressedSourceDir = mkdtempSync(join(tmpdir(), 'jsii-tmpdir-2')); + + try { + const fileContents = 'export class MarkerA {}'; + writeFileSync(join(uncompressedSourceDir, 'index.ts'), fileContents); + writeFileSync(join(compressedSourceDir, 'index.ts'), fileContents); + + const uncompressedJsiiCompiler = new Compiler({ + projectInfo: _makeProjectInfo(uncompressedSourceDir, 'index.d.ts'), + }); + const compressedJsiiCompiler = new Compiler({ + projectInfo: _makeProjectInfo(compressedSourceDir, 'index.d.ts'), + compressAssembly: true, + }); + + uncompressedJsiiCompiler.emit(); + compressedJsiiCompiler.emit(); + + // The files we expect are there + expect(existsSync(join(uncompressedSourceDir, '.jsii'))).toBeTruthy(); + expect(existsSync(join(compressedSourceDir, '.jsii.gz'))).toBeTruthy(); + + const uncompressedJsii = loadAssemblyFromPath(uncompressedSourceDir); + const compressedJsii = loadAssemblyFromPath(compressedSourceDir); + + expect(compressedJsii).toEqual(uncompressedJsii); + } finally { + removeSync(uncompressedSourceDir); + removeSync(compressedSourceDir); + } + }); + }); }); function _makeProjectInfo(sourceDir: string, types: string): ProjectInfo { diff --git a/packages/jsii/test/project-info.test.ts b/packages/jsii/test/project-info.test.ts index ad68d5d81f..521bbfe03b 100644 --- a/packages/jsii/test/project-info.test.ts +++ b/packages/jsii/test/project-info.test.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { writeAssembly } from '@jsii/utils'; import * as clone from 'clone'; import * as fs from 'fs-extra'; import * as os from 'os'; @@ -59,6 +60,40 @@ describe('loadProjectInfo', () => { ]); })); + test('loads valid project (with zipped assembly)', () => + _withTestProject( + (projectRoot) => { + const { projectInfo: info } = loadProjectInfo(projectRoot); + expect(info.name).toBe(BASE_PROJECT.name); + expect(info.version).toBe(BASE_PROJECT.version); + expect(info.description).toBe(BASE_PROJECT.description); + expect(info.license).toBe(BASE_PROJECT.license); + expect(_stripUndefined(info.author)).toEqual({ + ...BASE_PROJECT.author, + roles: ['author'], + }); + expect(info.main).toBe(BASE_PROJECT.main); + expect(info.types).toBe(BASE_PROJECT.types); + expect(info.homepage).toBe(undefined); + expect(info.repository?.type).toBe('git'); + expect(info.repository?.url).toBe(BASE_PROJECT.repository.url); + expect(info.targets).toEqual({ + ...BASE_PROJECT.jsii.targets, + js: { npm: BASE_PROJECT.name }, + }); + expect(info.dependencies).toEqual({ + [TEST_DEP_ASSEMBLY.name]: + BASE_PROJECT.dependencies[TEST_DEP_ASSEMBLY.name], + }); + expect(info.dependencyClosure).toEqual([ + TEST_DEP_ASSEMBLY, + TEST_DEP_DEP_ASSEMBLY, + ]); + }, + undefined, + true /* compress assembly */, + )); + test('loads valid project (UNLICENSED)', () => _withTestProject( (projectRoot) => { @@ -294,6 +329,7 @@ const TEST_DEP_DEP_ASSEMBLY: spec.Assembly = { function _withTestProject( cb: (projectRoot: string) => T, gremlin?: (packageInfo: any) => void, + compressAssembly = false, ): T { const tmpdir = fs.mkdtempSync( path.join(os.tmpdir(), path.basename(__filename)), @@ -322,7 +358,7 @@ function _withTestProject( const jsiiTestDep = path.join(tmpdir, 'node_modules', 'jsii-test-dep'); writeNpmPackageSkeleton(jsiiTestDep); - fs.writeJsonSync(path.join(jsiiTestDep, '.jsii'), TEST_DEP_ASSEMBLY); + writeAssembly(jsiiTestDep, TEST_DEP_ASSEMBLY, compressAssembly); const jsiiTestDepDep = path.join( jsiiTestDep, 'node_modules', @@ -330,7 +366,7 @@ function _withTestProject( ); writeNpmPackageSkeleton(jsiiTestDepDep); - fs.writeJsonSync(path.join(jsiiTestDepDep, '.jsii'), TEST_DEP_DEP_ASSEMBLY); + writeAssembly(jsiiTestDepDep, TEST_DEP_DEP_ASSEMBLY, compressAssembly); return cb(tmpdir); } finally { From 45ad28cba737ed1deebf6720282aec62a4859345 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jun 2022 18:12:08 -0400 Subject: [PATCH 16/41] changes to rosetta, one test failing --- .../jsii-rosetta/lib/commands/coverage.ts | 2 +- packages/jsii-rosetta/lib/commands/extract.ts | 4 +- packages/jsii-rosetta/lib/commands/infuse.ts | 2 +- .../lib/commands/transliterate.ts | 12 +- .../jsii-rosetta/lib/commands/trim-cache.ts | 2 +- packages/jsii-rosetta/lib/jsii/assemblies.ts | 24 ++-- packages/jsii-rosetta/package.json | 1 + .../test/commands/extract.test.ts | 55 ++++++++- .../jsii-rosetta/test/commands/infuse.test.ts | 2 +- .../test/commands/transliterate.test.ts | 109 +++++++++++++++++- packages/jsii-rosetta/test/testutil.ts | 26 ++++- 11 files changed, 200 insertions(+), 39 deletions(-) diff --git a/packages/jsii-rosetta/lib/commands/coverage.ts b/packages/jsii-rosetta/lib/commands/coverage.ts index d223e41262..0021b96163 100644 --- a/packages/jsii-rosetta/lib/commands/coverage.ts +++ b/packages/jsii-rosetta/lib/commands/coverage.ts @@ -5,7 +5,7 @@ import { formatLocation } from '../snippet'; export async function checkCoverage(assemblyLocations: readonly string[]): Promise { logging.info(`Loading ${assemblyLocations.length} assemblies`); - const assemblies = await loadAssemblies(assemblyLocations, false); + const assemblies = loadAssemblies(assemblyLocations, false); const snippets = Array.from(await allTypeScriptSnippets(assemblies, true)); diff --git a/packages/jsii-rosetta/lib/commands/extract.ts b/packages/jsii-rosetta/lib/commands/extract.ts index 949c2007e7..81ffc3749a 100644 --- a/packages/jsii-rosetta/lib/commands/extract.ts +++ b/packages/jsii-rosetta/lib/commands/extract.ts @@ -94,7 +94,7 @@ export async function extractSnippets( const only = options.only ?? []; logging.info(`Loading ${assemblyLocations.length} assemblies`); - const assemblies = await loadAssemblies(assemblyLocations, options.validateAssemblies ?? false); + const assemblies = loadAssemblies(assemblyLocations, options.validateAssemblies ?? false); let snippets = Array.from(await allTypeScriptSnippets(assemblies, options.loose)); if (only.length > 0) { @@ -170,7 +170,7 @@ export async function extractSnippets( const output = options.trimCache ? new LanguageTablet() : await LanguageTablet.fromOptionalFile(options.cacheToFile); - output.addTablet(translator.tablet); + output.addTablets(translator.tablet); await output.save(options.cacheToFile); } diff --git a/packages/jsii-rosetta/lib/commands/infuse.ts b/packages/jsii-rosetta/lib/commands/infuse.ts index 183977b3d8..3fb1e86434 100644 --- a/packages/jsii-rosetta/lib/commands/infuse.ts +++ b/packages/jsii-rosetta/lib/commands/infuse.ts @@ -66,7 +66,7 @@ export async function infuse(assemblyLocations: string[], options?: InfuseOption } // Load tablet file and assemblies - const assemblies = await loadAssemblies(assemblyLocations, false); + const assemblies = loadAssemblies(assemblyLocations, false); const defaultTablets = await loadAllDefaultTablets(assemblies); const availableTranslations = new LanguageTablet(); diff --git a/packages/jsii-rosetta/lib/commands/transliterate.ts b/packages/jsii-rosetta/lib/commands/transliterate.ts index 45daec7333..586fc8d1b2 100644 --- a/packages/jsii-rosetta/lib/commands/transliterate.ts +++ b/packages/jsii-rosetta/lib/commands/transliterate.ts @@ -1,5 +1,6 @@ import { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind } from '@jsii/spec'; -import { readJson, writeJson } from 'fs-extra'; +import { loadAssemblyFromPath } from '@jsii/utils'; +import { writeJson } from 'fs-extra'; import { resolve } from 'path'; import { TargetLanguage } from '../languages'; @@ -98,8 +99,7 @@ export async function transliterateAssembly( for (const [location, loadAssembly] of assemblies.entries()) { for (const language of targetLanguages) { const now = new Date().getTime(); - // eslint-disable-next-line no-await-in-loop - const result = await loadAssembly(); + const result = loadAssembly(); if (result.targets?.[targetName(language)] == null) { // This language is not supported by the assembly, so we skip it... @@ -149,16 +149,16 @@ async function loadAssemblies( const result = new Map(); for (const directory of directories) { - const loader = () => readJson(resolve(directory, SPEC_FILE_NAME)); + const loader = () => loadAssemblyFromPath(directory); // eslint-disable-next-line no-await-in-loop - await rosetta.addAssembly(await loader(), directory); + await rosetta.addAssembly(loader(), directory); result.set(directory, loader); } return result; } -type AssemblyLoader = () => Promise>; +type AssemblyLoader = () => Mutable; function transliterateType(type: Type, rosetta: RosettaTabletReader, language: TargetLanguage): void { transliterateDocs({ api: 'type', fqn: type.fqn }, type.docs); diff --git a/packages/jsii-rosetta/lib/commands/trim-cache.ts b/packages/jsii-rosetta/lib/commands/trim-cache.ts index de87328489..4a8be800bd 100644 --- a/packages/jsii-rosetta/lib/commands/trim-cache.ts +++ b/packages/jsii-rosetta/lib/commands/trim-cache.ts @@ -18,7 +18,7 @@ export interface TrimCacheOptions { export async function trimCache(options: TrimCacheOptions): Promise { logging.info(`Loading ${options.assemblyLocations.length} assemblies`); - const assemblies = await loadAssemblies(options.assemblyLocations, false); + const assemblies = loadAssemblies(options.assemblyLocations, false); const snippets = Array.from(await allTypeScriptSnippets(assemblies)); diff --git a/packages/jsii-rosetta/lib/jsii/assemblies.ts b/packages/jsii-rosetta/lib/jsii/assemblies.ts index f9edbb06a6..b465ea0a13 100644 --- a/packages/jsii-rosetta/lib/jsii/assemblies.ts +++ b/packages/jsii-rosetta/lib/jsii/assemblies.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { loadAssemblyFromFile, getAssemblyFile } from '@jsii/utils'; import * as crypto from 'crypto'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -55,35 +56,28 @@ export interface LoadedAssembly { /** * Load assemblies by filename or directory */ -export async function loadAssemblies( +export function loadAssemblies( assemblyLocations: readonly string[], validateAssemblies: boolean, -): Promise { - return Promise.all(assemblyLocations.map(loadAssembly)); +): readonly LoadedAssembly[] { + return assemblyLocations.map(loadAssembly); - async function loadAssembly(location: string): Promise { - const stat = await fs.stat(location); + function loadAssembly(location: string): LoadedAssembly { + const stat = fs.statSync(location); if (stat.isDirectory()) { - return loadAssembly(path.join(location, '.jsii')); + return loadAssembly(getAssemblyFile(location)); } const directory = path.dirname(location); const pjLocation = path.join(directory, 'package.json'); - const [assembly, packageJson] = await Promise.all([ - loadAssemblyFromFile(location, validateAssemblies), - (await fs.pathExists(pjLocation)) ? fs.readJSON(pjLocation, { encoding: 'utf-8' }) : Promise.resolve(undefined), - ]); + const assembly = loadAssemblyFromFile(location, validateAssemblies); + const packageJson = fs.pathExistsSync(pjLocation) ? fs.readJSONSync(pjLocation, { encoding: 'utf-8' }) : undefined; return { assembly, directory, packageJson }; } } -async function loadAssemblyFromFile(filename: string, validate: boolean): Promise { - const contents = await fs.readJSON(filename, { encoding: 'utf-8' }); - return validate ? spec.validateAssembly(contents) : (contents as spec.Assembly); -} - /** * Load the default tablets for every assembly, if available * diff --git a/packages/jsii-rosetta/package.json b/packages/jsii-rosetta/package.json index dc4dcb8ed6..75f22cb121 100644 --- a/packages/jsii-rosetta/package.json +++ b/packages/jsii-rosetta/package.json @@ -28,6 +28,7 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "0.0.0", + "@jsii/utils": "0.0.0", "commonmark": "^0.30.0", "fs-extra": "^10.1.0", "typescript": "~3.9.10", diff --git a/packages/jsii-rosetta/test/commands/extract.test.ts b/packages/jsii-rosetta/test/commands/extract.test.ts index f85ce17322..6429b06128 100644 --- a/packages/jsii-rosetta/test/commands/extract.test.ts +++ b/packages/jsii-rosetta/test/commands/extract.test.ts @@ -1,3 +1,4 @@ +import { SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec'; import * as fs from 'fs-extra'; import { compileJsiiForTest } from 'jsii'; import * as path from 'path'; @@ -72,6 +73,50 @@ test('extract samples from test assembly', async () => { expect(tablet.snippetKeys.length).toEqual(1); }); +test('extract works from compressed test assembly', async () => { + const compressedAssembly = TestJsiiModule.fromSource( + { + 'index.ts': ` + export class ClassA { + public someMethod() { + } + } + export class ClassB { + public anotherMethod() { + } + } + `, + 'README.md': DUMMY_README, + }, + { + name: 'my_assembly', + jsii: DUMMY_JSII_CONFIG, + }, + { + compressAssembly: true, + }, + ); + + try { + // assert that assembly is zipped + expect(fs.existsSync(path.join(compressedAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy(); + + // behavior is as expected + const cacheToFile = path.join(compressedAssembly.moduleDirectory, 'test.tabl.json'); + // eslint-disable-next-line prettier/prettier + await extract.extractSnippets([compressedAssembly.moduleDirectory], { + cacheToFile, + ...defaultExtractOptions, + }); + + const tablet = new LanguageTablet(); + await tablet.load(cacheToFile); + expect(tablet.snippetKeys.length).toEqual(1); + } finally { + compressedAssembly.cleanup(); + } +}); + describe('with cache file', () => { let cacheTabletFile: string; beforeEach(async () => { @@ -233,7 +278,7 @@ describe('with cache file', () => { assembly.assembly.types!['my_assembly.ClassB'].docs = { example: 'ClassB.anotherMethod();', }; - await assembly.updateAssembly(); + assembly.updateAssembly(); const translationFunction = jest.fn().mockResolvedValue({ diagnostics: [], translatedSnippets: [] }); @@ -428,7 +473,7 @@ test('extract and infuse in one command', async () => { expect(locations).toContain('type'); expect(locations).toContain('moduleReadme'); - const assemblies = await loadAssemblies([assembly.moduleDirectory], false); + const assemblies = loadAssemblies([assembly.moduleDirectory], false); const types = assemblies[0].assembly.types; // infuse works as expected @@ -478,7 +523,7 @@ describe('infused examples', () => { // Nothing like this should happen in practice infusedAssembly.assembly.types!['my_assembly.ClassA'].docs!.custom!.exampleMetadata = 'infused fixture=myfix.ts-fixture'; - await infusedAssembly.updateAssembly(); + infusedAssembly.updateAssembly(); // Expect to return cached snippet regardless of change // No compilation should happen @@ -495,7 +540,7 @@ describe('infused examples', () => { test('skip loose mode', async () => { // Remove infused for now and add lit metadata that should fail infusedAssembly.assembly.types!['my_assembly.ClassA'].docs!.custom!.exampleMetadata = 'lit=integ.test.ts'; - await infusedAssembly.updateAssembly(); + infusedAssembly.updateAssembly(); const cacheToFile = path.join(infusedAssembly.moduleDirectory, 'test.tabl.json'); @@ -509,7 +554,7 @@ describe('infused examples', () => { // Add infused to metadata and update assembly infusedAssembly.assembly.types!['my_assembly.ClassA'].docs!.custom!.exampleMetadata = 'lit=integ.test.ts infused'; - await infusedAssembly.updateAssembly(); + infusedAssembly.updateAssembly(); // Expect same function call to succeed now await extract.extractSnippets([infusedAssembly.moduleDirectory], { diff --git a/packages/jsii-rosetta/test/commands/infuse.test.ts b/packages/jsii-rosetta/test/commands/infuse.test.ts index d0a20ea54b..5391803470 100644 --- a/packages/jsii-rosetta/test/commands/infuse.test.ts +++ b/packages/jsii-rosetta/test/commands/infuse.test.ts @@ -61,7 +61,7 @@ afterEach(() => assembly.cleanup()); test('examples are added in the assembly', async () => { await infuse([assembly.moduleDirectory]); - const assemblies = await loadAssemblies([assembly.moduleDirectory], false); + const assemblies = loadAssemblies([assembly.moduleDirectory], false); const types = assemblies[0].assembly.types; expect(types).toBeDefined(); expect(types!['my_assembly.ClassA'].docs?.example).toBeDefined(); diff --git a/packages/jsii-rosetta/test/commands/transliterate.test.ts b/packages/jsii-rosetta/test/commands/transliterate.test.ts index b7358984a5..23358896d5 100644 --- a/packages/jsii-rosetta/test/commands/transliterate.test.ts +++ b/packages/jsii-rosetta/test/commands/transliterate.test.ts @@ -1,4 +1,5 @@ import { Assembly, SPEC_FILE_NAME } from '@jsii/spec'; +import { writeAssembly } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as jsii from 'jsii'; import * as path from 'path'; @@ -15,7 +16,7 @@ jest.setTimeout(60_000); const targets = Object.values(TargetLanguage).reduce((tgt, lang) => { tgt[targetName(lang)] = { phony: true }; return tgt; -}, {} as Record); +}, {} as Record); test('single assembly, all languages', () => withTemporaryDirectory(async (tmpDir) => { @@ -1623,3 +1624,109 @@ export class ClassName implements IInterface { } }); })); + +test('transliterate works with zipped assembly files', async () => + withTemporaryDirectory(async (tmpDir) => { + // GIVEN + const compilationResult = jsii.compileJsiiForTest({ + 'README.md': ` +# README +\`\`\`ts +const object: IInterface = new ClassName('this', 1337, { foo: 'bar' }); +object.property = EnumType.OPTION_A; +object.methodCall(); +ClassName.staticMethod(EnumType.OPTION_B); +\`\`\` +`, + 'index.ts': ` +/** + * @example new ClassName('this', 1337, { property: EnumType.OPTION_B }); + */ +export enum EnumType { + /** + * @example new ClassName('this', 1337, { property: EnumType.OPTION_A }); + */ + OPTION_A = 1, + /** + * @example new ClassName('this', 1337, { property: EnumType.OPTION_B }); + */ + OPTION_B = 2, +} +export interface IInterface { + /** + * A property value. + * + * @example + * iface.property = EnumType.OPTION_B; + */ + property: EnumType; + /** + * An instance method call. + * + * @example + * iface.methodCall(); + */ + methodCall(): void; +} +export interface ClassNameProps { + readonly property?: EnumType; + readonly foo?: string; +} +export class ClassName implements IInterface { + /** + * A static method. It can be invoked easily. + * + * @example ClassName.staticMethod(); + */ + public static staticMethod(_enm?: EnumType): void { + // ... + } + public property: EnumType; + /** + * Create a new instance of ClassName. + * + * @example new ClassName('this', 1337, { property: EnumType.OPTION_B }); + */ + public constructor(_this: string, _elite: number, props: ClassNameProps) { + this.property = props.property ?? EnumType.OPTION_A; + } + public methodCall(): void { + // ... + } +}`, + }); + + writeAssembly( + tmpDir, + { + ...compilationResult.assembly, + targets: { ...targets }, + }, + true /* compress */, + ); + for (const [file, content] of Object.entries(compilationResult.files)) { + fs.writeFileSync(path.resolve(tmpDir, file), content, 'utf-8'); + } + fs.mkdirSync(path.resolve(tmpDir, 'rosetta')); + fs.writeFileSync( + path.resolve(tmpDir, 'rosetta', 'default.ts-fixture'), + `import { EnumType, IInterface, ClassName } from '.';\ndeclare const iface: IInterface\n/// here`, + 'utf-8', + ); + + // WHEN + // create outdir + const outdir = path.resolve(tmpDir, 'out'); + fs.mkdirSync(outdir); + + await expect( + transliterateAssembly([tmpDir], Object.values(TargetLanguage), { + strict: true, + outdir, + }), + ).resolves.not.toThrow(); + + Object.values(TargetLanguage).forEach((lang) => { + expect(fs.statSync(path.join(outdir, `${SPEC_FILE_NAME}.${lang}`)).isFile()).toBe(true); + }); + })); diff --git a/packages/jsii-rosetta/test/testutil.ts b/packages/jsii-rosetta/test/testutil.ts index 93a90c7606..37d52231a6 100644 --- a/packages/jsii-rosetta/test/testutil.ts +++ b/packages/jsii-rosetta/test/testutil.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { writeAssembly } from '@jsii/utils'; import * as fs from 'fs-extra'; import { PackageInfo, compileJsiiForTest, TestWorkspace } from 'jsii'; import * as os from 'os'; @@ -15,6 +16,13 @@ import { export type MultipleSources = { [key: string]: string; 'index.ts': string }; +export interface TestJsiiModuleOptions { + /** + * Whether or not to compress the assembly + */ + readonly compressAssembly?: boolean; +} + /** * Compile a jsii module from source, and produce an environment in which it is available as a module */ @@ -22,20 +30,26 @@ export class TestJsiiModule { public static fromSource( source: string | MultipleSources, packageInfo: Partial & { name: string; main?: string; types?: string }, + options: TestJsiiModuleOptions = {}, ): TestJsiiModule { - const asm = compileJsiiForTest(source, (pi) => { - Object.assign(pi, packageInfo); + const asm = compileJsiiForTest(source, { + packageJson: packageInfo, + compressAssembly: options.compressAssembly, }); const ws = TestWorkspace.create(); ws.addDependency(asm); - return new TestJsiiModule(asm.assembly, ws); + return new TestJsiiModule(asm.assembly, ws, asm.compressAssembly === true); } public readonly moduleDirectory: string; public readonly workspaceDirectory: string; - private constructor(public readonly assembly: spec.Assembly, public readonly workspace: TestWorkspace) { + private constructor( + public readonly assembly: spec.Assembly, + public readonly workspace: TestWorkspace, + private readonly compressAssembly: boolean, + ) { this.moduleDirectory = workspace.dependencyDir(assembly.name); this.workspaceDirectory = workspace.rootDirectory; } @@ -80,8 +94,8 @@ export class TestJsiiModule { /** * Update the file to reflect the latest changes to the assembly object. */ - public async updateAssembly() { - await fs.writeJSON(path.join(this.moduleDirectory, '.jsii'), this.assembly); + public updateAssembly() { + writeAssembly(this.moduleDirectory, this.assembly, this.compressAssembly); } public cleanup() { From 1b105bd4251992e246c7cb7775424b31ffd8d11f Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:04:49 -0400 Subject: [PATCH 17/41] jsii-rosetta uses centralized assembly helper functions --- packages/jsii-rosetta/lib/jsii/assemblies.ts | 41 ++++++++----------- packages/jsii-rosetta/lib/languages/python.ts | 4 ++ .../test/commands/extract.test.ts | 6 +-- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/jsii-rosetta/lib/jsii/assemblies.ts b/packages/jsii-rosetta/lib/jsii/assemblies.ts index b465ea0a13..7178a4c11a 100644 --- a/packages/jsii-rosetta/lib/jsii/assemblies.ts +++ b/packages/jsii-rosetta/lib/jsii/assemblies.ts @@ -1,5 +1,5 @@ import * as spec from '@jsii/spec'; -import { loadAssemblyFromFile, getAssemblyFile } from '@jsii/utils'; +import { loadAssemblyFromFile, loadAssemblyFromPath, getAssemblyFile, writeAssembly } from '@jsii/utils'; import * as crypto from 'crypto'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -230,12 +230,8 @@ export async function allTypeScriptSnippets( * Replaces the file where the original assembly file *should* be found with a new assembly file. * Recalculates the fingerprint of the assembly to avoid tampering detection. */ -export async function replaceAssembly(assembly: spec.Assembly, directory: string): Promise { - const fileName = path.join(directory, '.jsii'); - await fs.writeJson(fileName, _fingerprint(assembly), { - encoding: 'utf8', - spaces: 2, - }); +export function replaceAssembly(assembly: spec.Assembly, directory: string, compress = false) { + writeAssembly(directory, _fingerprint(assembly), compress); } /** @@ -290,24 +286,23 @@ export function findTypeLookupAssembly(startingDirectory: string): TypeLookupAss } function loadLookupAssembly(directory: string): TypeLookupAssembly | undefined { - const assemblyFile = path.join(directory, '.jsii'); - if (!fs.pathExistsSync(assemblyFile)) { + try { + const packageJson = fs.readJSONSync(path.join(directory, 'package.json'), { encoding: 'utf-8' }); + const assembly: spec.Assembly = loadAssemblyFromPath(directory); + const symbolIdMap = mkDict([ + ...Object.values(assembly.types ?? {}).map((type) => [type.symbolId ?? '', type.fqn] as const), + ...Object.entries(assembly.submodules ?? {}).map(([fqn, mod]) => [mod.symbolId ?? '', fqn] as const), + ]); + + return { + packageJson, + assembly, + directory, + symbolIdMap, + }; + } catch { return undefined; } - - const packageJson = fs.readJSONSync(path.join(directory, 'package.json'), { encoding: 'utf-8' }); - const assembly: spec.Assembly = fs.readJSONSync(assemblyFile, { encoding: 'utf-8' }); - const symbolIdMap = mkDict([ - ...Object.values(assembly.types ?? {}).map((type) => [type.symbolId ?? '', type.fqn] as const), - ...Object.entries(assembly.submodules ?? {}).map(([fqn, mod]) => [mod.symbolId ?? '', fqn] as const), - ]); - - return { - packageJson, - assembly, - directory, - symbolIdMap, - }; } function findPackageJsonLocation(currentPath: string): string | undefined { diff --git a/packages/jsii-rosetta/lib/languages/python.ts b/packages/jsii-rosetta/lib/languages/python.ts index c4e1c02579..6b03d41c46 100644 --- a/packages/jsii-rosetta/lib/languages/python.ts +++ b/packages/jsii-rosetta/lib/languages/python.ts @@ -843,6 +843,10 @@ function findPythonName(jsiiSymbol: JsiiSymbol): string | undefined { return recurse(jsiiSymbol.fqn); function recurse(fqn: string): string { + if (!fqn) { + // eslint-disable-next-line no-debugger + debugger; + } if (fqn === asm.name) { return jsiiTargetParameter(asm, 'python.module') ?? guessPythonPackageName(fqn); } diff --git a/packages/jsii-rosetta/test/commands/extract.test.ts b/packages/jsii-rosetta/test/commands/extract.test.ts index 6429b06128..8ac6c0cff3 100644 --- a/packages/jsii-rosetta/test/commands/extract.test.ts +++ b/packages/jsii-rosetta/test/commands/extract.test.ts @@ -1,4 +1,4 @@ -import { SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec'; +// import { SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec'; import * as fs from 'fs-extra'; import { compileJsiiForTest } from 'jsii'; import * as path from 'path'; @@ -60,7 +60,7 @@ beforeEach(() => { afterEach(() => assembly.cleanup()); -test('extract samples from test assembly', async () => { +test('extract works samples from test assembly', async () => { const cacheToFile = path.join(assembly.moduleDirectory, 'test.tabl.json'); await extract.extractSnippets([assembly.moduleDirectory], { cacheToFile, @@ -99,7 +99,7 @@ test('extract works from compressed test assembly', async () => { try { // assert that assembly is zipped - expect(fs.existsSync(path.join(compressedAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy(); + // expect(fs.existsSync(path.join(compressedAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy(); // behavior is as expected const cacheToFile = path.join(compressedAssembly.moduleDirectory, 'test.tabl.json'); From 9b42e8d467fe92ff849a3b752e448e25ffd73225 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:05:27 -0400 Subject: [PATCH 18/41] minor improvements --- packages/jsii/lib/helpers.ts | 2 +- packages/jsii/lib/project-info.ts | 2 +- packages/jsii/test/compiler.test.ts | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/jsii/lib/helpers.ts b/packages/jsii/lib/helpers.ts index eca970ff48..b3f7870e28 100644 --- a/packages/jsii/lib/helpers.ts +++ b/packages/jsii/lib/helpers.ts @@ -123,7 +123,7 @@ export function compileJsiiForTest( if (errors.length > 0 || emitResult.emitSkipped) { throw new Error('There were compiler errors'); } - const assembly = loadAssemblyFromPath(process.cwd()); + const assembly = loadAssemblyFromPath(process.cwd(), false); const files: Record = {}; for (const filename of Object.keys(source)) { diff --git a/packages/jsii/lib/project-info.ts b/packages/jsii/lib/project-info.ts index 3e91aecb03..8c09173424 100644 --- a/packages/jsii/lib/project-info.ts +++ b/packages/jsii/lib/project-info.ts @@ -440,7 +440,7 @@ function _tryResolveAssembly( } try { const dependencyDir = findDependencyDirectory(mod, searchPath); - return path.join(dependencyDir, '.jsii'); + return getAssemblyFile(dependencyDir); } catch (e: any) { throw new Error( `Unable to locate jsii assembly for "${mod}". If this module is not jsii-enabled, it must also be declared under bundledDependencies: ${e}`, diff --git a/packages/jsii/test/compiler.test.ts b/packages/jsii/test/compiler.test.ts index 3d2faf378a..aab70f4425 100644 --- a/packages/jsii/test/compiler.test.ts +++ b/packages/jsii/test/compiler.test.ts @@ -1,4 +1,8 @@ -import { loadAssemblyFromPath } from '@jsii/utils'; +import { + loadAssemblyFromPath, + SPEC_FILE_NAME, + SPEC_FILE_NAME_COMPRESSED, +} from '@jsii/utils'; import { ensureDirSync, existsSync, @@ -189,7 +193,9 @@ describe(Compiler, () => { compiler.emit(); - expect(existsSync(join(sourceDir, '.jsii.gz'))).toBeTruthy(); + expect( + existsSync(join(sourceDir, SPEC_FILE_NAME_COMPRESSED)), + ).toBeTruthy(); } finally { removeSync(sourceDir); } @@ -216,8 +222,12 @@ describe(Compiler, () => { compressedJsiiCompiler.emit(); // The files we expect are there - expect(existsSync(join(uncompressedSourceDir, '.jsii'))).toBeTruthy(); - expect(existsSync(join(compressedSourceDir, '.jsii.gz'))).toBeTruthy(); + expect( + existsSync(join(uncompressedSourceDir, SPEC_FILE_NAME)), + ).toBeTruthy(); + expect( + existsSync(join(compressedSourceDir, SPEC_FILE_NAME_COMPRESSED)), + ).toBeTruthy(); const uncompressedJsii = loadAssemblyFromPath(uncompressedSourceDir); const compressedJsii = loadAssemblyFromPath(compressedSourceDir); From af821cd6dda992cc4ab8cce91ecb3a842293cc2c Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:07:32 -0400 Subject: [PATCH 19/41] standardize spec_file_name --- packages/jsii-diff/bin/jsii-diff.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsii-diff/bin/jsii-diff.ts b/packages/jsii-diff/bin/jsii-diff.ts index 398b9d61b4..e52bb85911 100644 --- a/packages/jsii-diff/bin/jsii-diff.ts +++ b/packages/jsii-diff/bin/jsii-diff.ts @@ -215,7 +215,7 @@ type LoadAssemblyResult = { requested: string; resolved: string } & ( async function loadPackageNameFromAssembly( options: LoadOptions, ): Promise { - const JSII_ASSEMBLY_FILE = '.jsii'; + const JSII_ASSEMBLY_FILE = spec.SPEC_FILE_NAME; if (!(await fs.pathExists(JSII_ASSEMBLY_FILE))) { throw new Error( `No NPM package name given and no ${JSII_ASSEMBLY_FILE} file in the current directory. Please specify a package name.`, From e33bed08fbffd5864810c5613a9822184f598c89 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:17:53 -0400 Subject: [PATCH 20/41] remove all .jsii usage --- packages/@jsii/runtime/package.json | 3 ++- packages/@jsii/runtime/test/kernel-host.test.ts | 8 +++----- packages/jsii-rosetta/test/commands/infuse.test.ts | 4 ++-- packages/jsii/test/submodules.test.ts | 9 ++++----- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/@jsii/runtime/package.json b/packages/@jsii/runtime/package.json index b062563ce8..de59b50fda 100644 --- a/packages/@jsii/runtime/package.json +++ b/packages/@jsii/runtime/package.json @@ -36,7 +36,8 @@ "dependencies": { "@jsii/kernel": "^0.0.0", "@jsii/check-node": "0.0.0", - "@jsii/spec": "^0.0.0" + "@jsii/spec": "^0.0.0", + "@jsii/utils": "^0.0.0" }, "devDependencies": { "@scope/jsii-calc-base": "^0.0.0", diff --git a/packages/@jsii/runtime/test/kernel-host.test.ts b/packages/@jsii/runtime/test/kernel-host.test.ts index 53d821e400..f8f7b668e8 100644 --- a/packages/@jsii/runtime/test/kernel-host.test.ts +++ b/packages/@jsii/runtime/test/kernel-host.test.ts @@ -1,5 +1,6 @@ import { api } from '@jsii/kernel'; import * as spec from '@jsii/spec'; +import { loadAssemblyFromPath } from '@jsii/utils'; import * as child from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; @@ -86,12 +87,9 @@ function loadRequest(library: string): api.LoadRequest { }; function loadAssembly(): spec.Assembly { - const assemblyFile = path.resolve( - require.resolve(`${library}/package.json`), - '..', - '.jsii', + return loadAssemblyFromPath( + path.resolve(require.resolve(`${library}/package.json`), '..'), ); - return JSON.parse(fs.readFileSync(assemblyFile, { encoding: 'utf-8' })); } function packageLibrary(target: string): void { diff --git a/packages/jsii-rosetta/test/commands/infuse.test.ts b/packages/jsii-rosetta/test/commands/infuse.test.ts index 5391803470..2167e40640 100644 --- a/packages/jsii-rosetta/test/commands/infuse.test.ts +++ b/packages/jsii-rosetta/test/commands/infuse.test.ts @@ -1,4 +1,4 @@ -import * as spec from '@jsii/spec'; +import { loadAssemblyFromPath } from '@jsii/utils'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -71,7 +71,7 @@ test('infuse copies example metadata', async () => { await infuse([assembly.moduleDirectory]); // THEN: the metadata that used to be on the README snippet is also on the class example - const updatedAssembly = (await fs.readJson(path.join(assembly.moduleDirectory, '.jsii'))) as spec.Assembly; + const updatedAssembly = loadAssemblyFromPath(assembly.moduleDirectory); const typeDocs = updatedAssembly.types?.['my_assembly.ClassA']?.docs; expect(typeDocs?.custom?.exampleMetadata).toEqual('some=metadata infused'); diff --git a/packages/jsii/test/submodules.test.ts b/packages/jsii/test/submodules.test.ts index beeedc4bc5..2f19b33259 100644 --- a/packages/jsii/test/submodules.test.ts +++ b/packages/jsii/test/submodules.test.ts @@ -1,6 +1,5 @@ import * as spec from '@jsii/spec'; -import * as fs from 'fs-extra'; -import * as path from 'path'; +import { writeAssembly, loadAssemblyFromPath } from '@jsii/utils'; import { sourceToAssemblyHelper, @@ -262,15 +261,15 @@ test('will detect types from submodules even if the symbol identifier table is m ws.addDependency(makeDependencyWithSubmodule()); // Strip the symbolidentifiers from the assembly - const asmFile = path.join(ws.dependencyDir('testpkg'), '.jsii'); - const asm: spec.Assembly = fs.readJsonSync(asmFile); + const asmDir = ws.dependencyDir('testpkg'); + const asm: spec.Assembly = loadAssemblyFromPath(asmDir, false); for (const mod of Object.values(asm.submodules ?? {})) { delete mod.symbolId; } for (const type of Object.values(asm.types ?? {})) { delete type.symbolId; } - fs.writeJsonSync(asmFile, asm); + writeAssembly(asmDir, asm); // We can still use those types if we have a full-library import compileJsiiForTest( From cac5532d8179cd6657389c6981c972db398faa9a Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:30:45 -0400 Subject: [PATCH 21/41] move compress into a property bag --- packages/@jsii/spec/src/assembly.ts | 7 +++++++ packages/@jsii/utils/src/assembly.test.ts | 16 ++++++++-------- packages/@jsii/utils/src/assembly.ts | 9 ++++++++- packages/jsii/lib/assembler.ts | 8 +++----- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/@jsii/spec/src/assembly.ts b/packages/@jsii/spec/src/assembly.ts index 10d28735c2..7d1bd4a1c9 100644 --- a/packages/@jsii/spec/src/assembly.ts +++ b/packages/@jsii/spec/src/assembly.ts @@ -1,4 +1,11 @@ +/** + * Expected file name for jsii assembly or instructions to compressed assembly. + */ export const SPEC_FILE_NAME = '.jsii'; + +/** + * Expected file name for compressed assemblies. + */ export const SPEC_FILE_NAME_COMPRESSED = `${SPEC_FILE_NAME}.gz`; /** diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index dde2ec8434..d1b6821645 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -35,7 +35,7 @@ const TEST_ASSEMBLY: spec.Assembly = { describe('writeAssembly', () => { test('can write compressed assembly', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, true); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); expect( fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED)), @@ -54,7 +54,7 @@ describe('writeAssembly', () => { test('can write uncompressed assembly', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, false); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); expect(fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME))).toBeTruthy(); }); @@ -63,14 +63,14 @@ describe('writeAssembly', () => { describe('getAssemblyFile', () => { test('finds SPEC_FILE_NAME file when there is no compression', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, false); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); }); test('finds SPEC_FILE_NAME file even when there is compression', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, true); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); }); @@ -87,14 +87,14 @@ describe('getAssemblyFile', () => { describe('loadAssemblyFromPath', () => { test('loads compressed assembly', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, true); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); }); test('loads uncompressed assembly', () => { const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, false); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); }); @@ -103,8 +103,8 @@ describe('loadAssemblyFromPath', () => { const compressedTmpDir = makeTempDir(); const uncompressedTmpDir = makeTempDir(); - writeAssembly(compressedTmpDir, TEST_ASSEMBLY, true); - writeAssembly(uncompressedTmpDir, TEST_ASSEMBLY, false); + writeAssembly(compressedTmpDir, TEST_ASSEMBLY, { compress: true }); + writeAssembly(uncompressedTmpDir, TEST_ASSEMBLY, { compress: false }); expect(loadAssemblyFromPath(compressedTmpDir)).toEqual( loadAssemblyFromPath(uncompressedTmpDir), diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 1cd7684653..510bb65da0 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -3,7 +3,14 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as zlib from 'zlib'; +/** + * Expected file name for jsii assembly or instructions to compressed assembly. + */ export const SPEC_FILE_NAME = spec.SPEC_FILE_NAME; + +/** + * Expected file name for compressed assemblies. + */ export const SPEC_FILE_NAME_COMPRESSED = spec.SPEC_FILE_NAME_COMPRESSED; /** @@ -36,7 +43,7 @@ export function getAssemblyFile(directory: string) { export function writeAssembly( directory: string, assembly: spec.Assembly, - compress = false, + { compress = false }: { compress?: boolean } = {}, ) { if (compress) { // write .jsii file with instructions on opening the compressed file diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index fd82cdc63c..735a34885d 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -283,11 +283,9 @@ export class Assembler implements Emitter { path.join(this.projectInfo.projectRoot, SPEC_FILE_NAME), )}`, ); - writeAssembly( - this.projectInfo.projectRoot, - _fingerprint(assembly), - false, - ); + writeAssembly(this.projectInfo.projectRoot, _fingerprint(assembly), { + compress: false, + }); } try { From 417df72e985427b4e60623b8f7a3514a30277811 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 15:42:14 -0400 Subject: [PATCH 22/41] refactor schema validation error message --- packages/@jsii/utils/src/assembly.test.ts | 9 ++++++--- packages/@jsii/utils/src/assembly.ts | 13 ++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index d1b6821645..256c5d6652 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -115,12 +115,15 @@ describe('loadAssemblyFromPath', () => { const tmpdir = makeTempDir(); fs.writeJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { schema: 'jsii/file-redirect', - compression: 'gzip', - // missing filename + compression: '7zip', }); expect(() => loadAssemblyFromPath(tmpdir)).toThrow( - 'Invalid redirect schema: compression must be gzip and filename must exist', + [ + 'Invalid redirect schema', + " compression must be 'gzip' but received '7zip'", + " schema must include property 'filename'", + ].join('\n'), ); }); diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 510bb65da0..68fe8bfb80 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -129,9 +129,16 @@ function findRedirectAssembly( } function validateRedirectSchema(contents: Record) { - if (contents.compression !== 'gzip' || contents.filename === undefined) { - throw new Error( - 'Invalid redirect schema: compression must be gzip and filename must exist', + const errors = []; + if (contents.compression !== 'gzip') { + errors.push( + `compression must be 'gzip' but received '${contents.compression}'`, ); + } else if (contents.filename === undefined) { + errors.push("schema must include property 'filename'"); + } + + if (errors.length !== 0) { + throw new Error(`Invalid redirect schema:\n ${errors.join('\n ')}`); } } From 8f7504facc2c0e76df0fbc6014dbded385604da4 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 17:25:01 -0400 Subject: [PATCH 23/41] update kernel --- packages/@jsii/kernel/package.json | 1 + packages/@jsii/kernel/src/kernel.ts | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/@jsii/kernel/package.json b/packages/@jsii/kernel/package.json index dd5e07aae1..7d0517723c 100644 --- a/packages/@jsii/kernel/package.json +++ b/packages/@jsii/kernel/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@jsii/spec": "^0.0.0", + "@jsii/utils": "^0.0.0", "fs-extra": "^10.1.0", "tar": "^6.1.11" }, diff --git a/packages/@jsii/kernel/src/kernel.ts b/packages/@jsii/kernel/src/kernel.ts index 8a8e0eb50f..51ac24f4bf 100644 --- a/packages/@jsii/kernel/src/kernel.ts +++ b/packages/@jsii/kernel/src/kernel.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { loadAssemblyFromPath } from '@jsii/utils'; import * as cp from 'child_process'; import * as fs from 'fs-extra'; import * as os from 'os'; @@ -114,13 +115,14 @@ export class Kernel { } // read .jsii metadata from the root of the package - const jsiiMetadataFile = path.join(packageDir, spec.SPEC_FILE_NAME); - if (!fs.pathExistsSync(jsiiMetadataFile)) { + let assmSpec; + try { + assmSpec = loadAssemblyFromPath(packageDir); + } catch { throw new Error( `Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`, ); } - const assmSpec = fs.readJsonSync(jsiiMetadataFile) as spec.Assembly; // load the module and capture it's closure const closure = this._execute( From fc9ec85498c64ca4677bf5bc175e3846fc28eb0a Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 17:40:12 -0400 Subject: [PATCH 24/41] npmignore --- packages/jsii-pacmak/lib/npm-modules.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jsii-pacmak/lib/npm-modules.ts b/packages/jsii-pacmak/lib/npm-modules.ts index 8de84393ed..9eb2dccb04 100644 --- a/packages/jsii-pacmak/lib/npm-modules.ts +++ b/packages/jsii-pacmak/lib/npm-modules.ts @@ -150,6 +150,7 @@ async function updateNpmIgnore( ); } + includePattern('Include .jsii.gz', spec.SPEC_FILE_NAME_COMPRESSED); includePattern('Include .jsii', spec.SPEC_FILE_NAME); if (modified) { From a0ac235f91618a7978cfbfc58ae4d781b753d745 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 13 Jun 2022 17:40:29 -0400 Subject: [PATCH 25/41] update for new writeassembly function sig --- packages/jsii-rosetta/lib/jsii/assemblies.ts | 8 ++++++-- packages/jsii-rosetta/test/commands/transliterate.test.ts | 2 +- packages/jsii-rosetta/test/testutil.ts | 2 +- packages/jsii/lib/helpers.ts | 8 +++----- packages/jsii/test/project-info.test.ts | 8 ++++++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/jsii-rosetta/lib/jsii/assemblies.ts b/packages/jsii-rosetta/lib/jsii/assemblies.ts index 7178a4c11a..5d625eae04 100644 --- a/packages/jsii-rosetta/lib/jsii/assemblies.ts +++ b/packages/jsii-rosetta/lib/jsii/assemblies.ts @@ -230,8 +230,12 @@ export async function allTypeScriptSnippets( * Replaces the file where the original assembly file *should* be found with a new assembly file. * Recalculates the fingerprint of the assembly to avoid tampering detection. */ -export function replaceAssembly(assembly: spec.Assembly, directory: string, compress = false) { - writeAssembly(directory, _fingerprint(assembly), compress); +export function replaceAssembly( + assembly: spec.Assembly, + directory: string, + { compress = false }: { compress?: boolean } = {}, +) { + writeAssembly(directory, _fingerprint(assembly), { compress }); } /** diff --git a/packages/jsii-rosetta/test/commands/transliterate.test.ts b/packages/jsii-rosetta/test/commands/transliterate.test.ts index 23358896d5..a1151a76c5 100644 --- a/packages/jsii-rosetta/test/commands/transliterate.test.ts +++ b/packages/jsii-rosetta/test/commands/transliterate.test.ts @@ -1702,7 +1702,7 @@ export class ClassName implements IInterface { ...compilationResult.assembly, targets: { ...targets }, }, - true /* compress */, + { compress: true }, ); for (const [file, content] of Object.entries(compilationResult.files)) { fs.writeFileSync(path.resolve(tmpDir, file), content, 'utf-8'); diff --git a/packages/jsii-rosetta/test/testutil.ts b/packages/jsii-rosetta/test/testutil.ts index 37d52231a6..5ae5107902 100644 --- a/packages/jsii-rosetta/test/testutil.ts +++ b/packages/jsii-rosetta/test/testutil.ts @@ -95,7 +95,7 @@ export class TestJsiiModule { * Update the file to reflect the latest changes to the assembly object. */ public updateAssembly() { - writeAssembly(this.moduleDirectory, this.assembly, this.compressAssembly); + writeAssembly(this.moduleDirectory, this.assembly, { compress: this.compressAssembly }); } public cleanup() { diff --git a/packages/jsii/lib/helpers.ts b/packages/jsii/lib/helpers.ts index b3f7870e28..806569f797 100644 --- a/packages/jsii/lib/helpers.ts +++ b/packages/jsii/lib/helpers.ts @@ -308,11 +308,9 @@ export class TestWorkspace { ); fs.ensureDirSync(modDir); - writeAssembly( - modDir, - dependencyAssembly.assembly, - dependencyAssembly.compressAssembly, - ); + writeAssembly(modDir, dependencyAssembly.assembly, { + compress: dependencyAssembly.compressAssembly, + }); fs.writeJsonSync( path.join(modDir, 'package.json'), dependencyAssembly.packageJson, diff --git a/packages/jsii/test/project-info.test.ts b/packages/jsii/test/project-info.test.ts index 521bbfe03b..05cf30adf1 100644 --- a/packages/jsii/test/project-info.test.ts +++ b/packages/jsii/test/project-info.test.ts @@ -358,7 +358,9 @@ function _withTestProject( const jsiiTestDep = path.join(tmpdir, 'node_modules', 'jsii-test-dep'); writeNpmPackageSkeleton(jsiiTestDep); - writeAssembly(jsiiTestDep, TEST_DEP_ASSEMBLY, compressAssembly); + writeAssembly(jsiiTestDep, TEST_DEP_ASSEMBLY, { + compress: compressAssembly, + }); const jsiiTestDepDep = path.join( jsiiTestDep, 'node_modules', @@ -366,7 +368,9 @@ function _withTestProject( ); writeNpmPackageSkeleton(jsiiTestDepDep); - writeAssembly(jsiiTestDepDep, TEST_DEP_DEP_ASSEMBLY, compressAssembly); + writeAssembly(jsiiTestDepDep, TEST_DEP_DEP_ASSEMBLY, { + compress: compressAssembly, + }); return cb(tmpdir); } finally { From df487795328b953a86391610d059bad31503208b Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Tue, 14 Jun 2022 14:46:47 -0400 Subject: [PATCH 26/41] remove debugging logic --- packages/@jsii/utils/src/assembly.ts | 6 ++++++ packages/jsii-rosetta/lib/languages/python.ts | 4 ---- packages/jsii-rosetta/test/commands/extract.test.ts | 7 +++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 68fe8bfb80..a99686a781 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -96,13 +96,19 @@ export function loadAssemblyFromFile( pathToFile: string, validate = true, ): spec.Assembly { + const startTime = Date.now(); + let compressed = false; let contents = readAssembly(pathToFile); // check if the file holds instructions to the actual assembly file if (contents.schema === 'jsii/file-redirect') { contents = findRedirectAssembly(pathToFile, contents); + compressed = true; } + // eslint-disable-next-line prettier/prettier + console.log(`compressed: ${compressed} -- time: ${(Date.now()-startTime) / 1000}\n${pathToFile}`); + return validate ? spec.validateAssembly(contents) : (contents as spec.Assembly); diff --git a/packages/jsii-rosetta/lib/languages/python.ts b/packages/jsii-rosetta/lib/languages/python.ts index 6b03d41c46..c4e1c02579 100644 --- a/packages/jsii-rosetta/lib/languages/python.ts +++ b/packages/jsii-rosetta/lib/languages/python.ts @@ -843,10 +843,6 @@ function findPythonName(jsiiSymbol: JsiiSymbol): string | undefined { return recurse(jsiiSymbol.fqn); function recurse(fqn: string): string { - if (!fqn) { - // eslint-disable-next-line no-debugger - debugger; - } if (fqn === asm.name) { return jsiiTargetParameter(asm, 'python.module') ?? guessPythonPackageName(fqn); } diff --git a/packages/jsii-rosetta/test/commands/extract.test.ts b/packages/jsii-rosetta/test/commands/extract.test.ts index 8ac6c0cff3..1c2b5db23a 100644 --- a/packages/jsii-rosetta/test/commands/extract.test.ts +++ b/packages/jsii-rosetta/test/commands/extract.test.ts @@ -1,4 +1,4 @@ -// import { SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec'; +import { SPEC_FILE_NAME_COMPRESSED } from '@jsii/spec'; import * as fs from 'fs-extra'; import { compileJsiiForTest } from 'jsii'; import * as path from 'path'; @@ -60,7 +60,7 @@ beforeEach(() => { afterEach(() => assembly.cleanup()); -test('extract works samples from test assembly', async () => { +test('extract samples from test assembly', async () => { const cacheToFile = path.join(assembly.moduleDirectory, 'test.tabl.json'); await extract.extractSnippets([assembly.moduleDirectory], { cacheToFile, @@ -99,11 +99,10 @@ test('extract works from compressed test assembly', async () => { try { // assert that assembly is zipped - // expect(fs.existsSync(path.join(compressedAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy(); + expect(fs.existsSync(path.join(compressedAssembly.moduleDirectory, SPEC_FILE_NAME_COMPRESSED))).toBeTruthy(); // behavior is as expected const cacheToFile = path.join(compressedAssembly.moduleDirectory, 'test.tabl.json'); - // eslint-disable-next-line prettier/prettier await extract.extractSnippets([compressedAssembly.moduleDirectory], { cacheToFile, ...defaultExtractOptions, From f06ca4a66cdf052b00067e849f0c3157e6c30af7 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Tue, 14 Jun 2022 15:49:07 -0400 Subject: [PATCH 27/41] fix test --- packages/@jsii/utils/src/assembly.test.ts | 2 +- packages/@jsii/utils/src/assembly.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts index 256c5d6652..caf64c0560 100644 --- a/packages/@jsii/utils/src/assembly.test.ts +++ b/packages/@jsii/utils/src/assembly.test.ts @@ -120,7 +120,7 @@ describe('loadAssemblyFromPath', () => { expect(() => loadAssemblyFromPath(tmpdir)).toThrow( [ - 'Invalid redirect schema', + 'Invalid redirect schema:', " compression must be 'gzip' but received '7zip'", " schema must include property 'filename'", ].join('\n'), diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts index 68fe8bfb80..4e46f81a1d 100644 --- a/packages/@jsii/utils/src/assembly.ts +++ b/packages/@jsii/utils/src/assembly.ts @@ -134,7 +134,8 @@ function validateRedirectSchema(contents: Record) { errors.push( `compression must be 'gzip' but received '${contents.compression}'`, ); - } else if (contents.filename === undefined) { + } + if (contents.filename === undefined) { errors.push("schema must include property 'filename'"); } From 550282a44074cc449326a6a041abd3f6f2c7b42c Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 15:43:37 -0400 Subject: [PATCH 28/41] more @jsii/utils to @jsii/spec --- packages/@jsii/spec/package.json | 3 +- .../@jsii/spec/src/assembly-utils.test.ts | 152 ++++++++++++++++++ packages/@jsii/spec/src/assembly-utils.ts | 139 ++++++++++++++++ 3 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 packages/@jsii/spec/src/assembly-utils.test.ts create mode 100644 packages/@jsii/spec/src/assembly-utils.ts diff --git a/packages/@jsii/spec/package.json b/packages/@jsii/spec/package.json index bac3fe6a96..8641234a7a 100644 --- a/packages/@jsii/spec/package.json +++ b/packages/@jsii/spec/package.json @@ -31,7 +31,8 @@ "package": "package-js" }, "dependencies": { - "ajv": "^8.11.0" + "ajv": "^8.11.0", + "fs-extra": "^10.1.0" }, "devDependencies": { "jsii-build-tools": "^0.0.0", diff --git a/packages/@jsii/spec/src/assembly-utils.test.ts b/packages/@jsii/spec/src/assembly-utils.test.ts new file mode 100644 index 0000000000..338b52d503 --- /dev/null +++ b/packages/@jsii/spec/src/assembly-utils.test.ts @@ -0,0 +1,152 @@ +import * as fs from 'fs-extra'; +import * as os from 'os'; +import * as path from 'path'; + +import { + SPEC_FILE_NAME, + SPEC_FILE_NAME_COMPRESSED, + Assembly, + SchemaVersion, +} from './assembly'; +import { + loadAssemblyFromPath, + getAssemblyFile, + writeAssembly, +} from './assembly-utils'; + +const TEST_ASSEMBLY: Assembly = { + schema: SchemaVersion.LATEST, + name: 'jsii-test-dep', + version: '1.2.4', + license: 'Apache-2.0', + description: 'A test assembly', + homepage: 'https://github.com/aws/jsii', + repository: { type: 'git', url: 'git://github.com/aws/jsii.git' }, + author: { + name: 'Amazon Web Services', + url: 'https://aws.amazon.com', + organization: true, + roles: ['author'], + }, + fingerprint: 'F1NG3RPR1N7', + dependencies: { + 'jsii-test-dep-dep': '3.2.1', + }, + jsiiVersion: '1.0.0', +}; + +describe('writeAssembly', () => { + test('can write compressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); + + expect( + fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED)), + ).toBeTruthy(); + + // includes .jsii files with instructions for finding compressed file + const instructions = fs.readJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { + encoding: 'utf-8', + }); + expect(instructions).toEqual({ + schema: 'jsii/file-redirect', + compression: 'gzip', + filename: SPEC_FILE_NAME_COMPRESSED, + }); + }); + + test('can write uncompressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); + + expect(fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME))).toBeTruthy(); + }); +}); + +describe('getAssemblyFile', () => { + test('finds SPEC_FILE_NAME file when there is no compression', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); + + expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); + }); + + test('finds SPEC_FILE_NAME file even when there is compression', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); + + expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); + }); + + test('throws if SPEC_FILE_NAME file does not exist', () => { + const tmpdir = makeTempDir(); + + expect(() => getAssemblyFile(tmpdir)).toThrow( + `Expected to find ${SPEC_FILE_NAME} file in ${tmpdir}, but no such file found`, + ); + }); +}); + +describe('loadAssemblyFromPath', () => { + test('loads compressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); + + expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); + }); + + test('loads uncompressed assembly', () => { + const tmpdir = makeTempDir(); + writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); + + expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); + }); + + test('compressed and uncompressed assemblies are loaded identically', () => { + const compressedTmpDir = makeTempDir(); + const uncompressedTmpDir = makeTempDir(); + + writeAssembly(compressedTmpDir, TEST_ASSEMBLY, { compress: true }); + writeAssembly(uncompressedTmpDir, TEST_ASSEMBLY, { compress: false }); + + expect(loadAssemblyFromPath(compressedTmpDir)).toEqual( + loadAssemblyFromPath(uncompressedTmpDir), + ); + }); + + test('throws if redirect schema is invalid', () => { + const tmpdir = makeTempDir(); + fs.writeJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { + schema: 'jsii/file-redirect', + compression: '7zip', + }); + + expect(() => loadAssemblyFromPath(tmpdir)).toThrow( + [ + 'Invalid redirect schema:', + " compression must be 'gzip' but received '7zip'", + " schema must include property 'filename'", + ].join('\n'), + ); + }); + + test('throws if assembly is invalid', () => { + const tmpdir = makeTempDir(); + fs.writeJsonSync( + path.join(tmpdir, SPEC_FILE_NAME), + { + assembly: 'not a valid assembly', + }, + { + encoding: 'utf8', + spaces: 2, + }, + ); + + expect(() => loadAssemblyFromPath(tmpdir)).toThrow(/Invalid assembly/); + }); +}); + +function makeTempDir() { + return fs.mkdtempSync(path.join(os.tmpdir(), path.basename(__filename))); +} diff --git a/packages/@jsii/spec/src/assembly-utils.ts b/packages/@jsii/spec/src/assembly-utils.ts new file mode 100644 index 0000000000..c27c755420 --- /dev/null +++ b/packages/@jsii/spec/src/assembly-utils.ts @@ -0,0 +1,139 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as zlib from 'zlib'; + +import { + Assembly, + SPEC_FILE_NAME, + SPEC_FILE_NAME_COMPRESSED, +} from './assembly'; +import { validateAssembly } from './validate-assembly'; + +/** + * Finds the path to the SPEC_FILE_NAME file, which will either + * be the assembly or hold instructions to find the assembly. + * + * @param directory path to a directory with an assembly file + * @returns path to the SPEC_FILE_NAME file + */ +export function getAssemblyFile(directory: string) { + const dotJsiiFile = path.join(directory, SPEC_FILE_NAME); + + if (!fs.existsSync(dotJsiiFile)) { + throw new Error( + `Expected to find ${SPEC_FILE_NAME} file in ${directory}, but no such file found`, + ); + } + + return dotJsiiFile; +} + +/** + * Writes the assembly file either as .jsii or .jsii.gz if zipped + * + * @param directory the directory path to place the assembly file + * @param assembly the contents of the assembly + * @param compress whether or not to zip the assembly (.jsii.gz) + * @returns whether or not the assembly was zipped + */ +export function writeAssembly( + directory: string, + assembly: Assembly, + { compress = false }: { compress?: boolean } = {}, +) { + if (compress) { + // write .jsii file with instructions on opening the compressed file + fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), { + schema: 'jsii/file-redirect', + compression: 'gzip', + filename: SPEC_FILE_NAME_COMPRESSED, + }); + + // write actual assembly contents in .jsii.gz + fs.writeFileSync( + path.join(directory, SPEC_FILE_NAME_COMPRESSED), + zlib.gzipSync(JSON.stringify(assembly)), + ); + } else { + fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), assembly, { + encoding: 'utf8', + spaces: 2, + }); + } + + return compress; +} + +/** + * Loads the assembly file and, if present, follows instructions + * found in the file to unzip compressed assemblies. + * + * @param directory the directory of the assembly file + * @param validate whether to validate the contents of the file + * @returns the assembly file as json + */ +export function loadAssemblyFromPath( + directory: string, + validate = true, +): Assembly { + const assemblyFile = getAssemblyFile(directory); + return loadAssemblyFromFile(assemblyFile, validate); +} + +/** + * Loads the assembly file and, if present, follows instructions + * found in the file to unzip compressed assemblies. + * + * @param pathToFile the path to the SPEC_FILE_NAME file + * @param validate whether to validate the contents of the file + * @returns the assembly file as json + */ +export function loadAssemblyFromFile( + pathToFile: string, + validate = true, +): Assembly { + let contents = readAssembly(pathToFile); + + // check if the file holds instructions to the actual assembly file + if (contents.schema === 'jsii/file-redirect') { + contents = findRedirectAssembly(pathToFile, contents); + } + + return validate ? validateAssembly(contents) : (contents as Assembly); +} + +function readAssembly(pathToFile: string) { + return fs.readJsonSync(pathToFile, { + encoding: 'utf-8', + }); +} + +function findRedirectAssembly( + pathToFile: string, + contents: Record, +) { + validateRedirectSchema(contents); + const redirectAssemblyFile = path.join( + path.dirname(pathToFile), + contents.filename, + ); + return JSON.parse( + zlib.gunzipSync(fs.readFileSync(redirectAssemblyFile)).toString(), + ); +} + +function validateRedirectSchema(contents: Record) { + const errors = []; + if (contents.compression !== 'gzip') { + errors.push( + `compression must be 'gzip' but received '${contents.compression}'`, + ); + } + if (contents.filename === undefined) { + errors.push("schema must include property 'filename'"); + } + + if (errors.length !== 0) { + throw new Error(`Invalid redirect schema:\n ${errors.join('\n ')}`); + } +} From 97e080f344fd231b0ef81e0b42e5710bfad2d926 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 15:51:20 -0400 Subject: [PATCH 29/41] update example usage --- packages/jsii/lib/assembler.ts | 3 +-- packages/jsii/package.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index c742de42b8..2e311c7cf2 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -1,6 +1,5 @@ import * as spec from '@jsii/spec'; -import { PackageJson } from '@jsii/spec'; -import { writeAssembly, SPEC_FILE_NAME } from '@jsii/utils'; +import { writeAssembly, SPEC_FILE_NAME, PackageJson } from '@jsii/spec'; import * as chalk from 'chalk'; import * as crypto from 'crypto'; import * as deepEqual from 'fast-deep-equal/es6'; diff --git a/packages/jsii/package.json b/packages/jsii/package.json index 20f8c0e124..005cb48fe1 100644 --- a/packages/jsii/package.json +++ b/packages/jsii/package.json @@ -37,7 +37,6 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "^0.0.0", - "@jsii/utils": "^0.0.0", "case": "^1.6.3", "chalk": "^4", "fast-deep-equal": "^3.1.3", From 013d3d2a3c81c81295771c8b43a8047a19d3dde3 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 15:51:31 -0400 Subject: [PATCH 30/41] export functions from @jsii/spec --- packages/@jsii/spec/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@jsii/spec/src/index.ts b/packages/@jsii/spec/src/index.ts index 4b318ab612..c299db2127 100644 --- a/packages/@jsii/spec/src/index.ts +++ b/packages/@jsii/spec/src/index.ts @@ -1,4 +1,5 @@ export * from './assembly'; +export * from './assembly-utils'; export * from './configuration'; export * from './name-tree'; export * from './validate-assembly'; From f7f60a4ac3669ddd6ad78d3b3f204cf723077cfd Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 15:51:56 -0400 Subject: [PATCH 31/41] remove @jsii/utils --- packages/@jsii/utils/.gitignore | 8 - packages/@jsii/utils/.npmignore | 13 -- packages/@jsii/utils/LICENSE | 202 ---------------------- packages/@jsii/utils/NOTICE | 2 - packages/@jsii/utils/README.md | 3 - packages/@jsii/utils/jest.config.ts | 3 - packages/@jsii/utils/package.json | 37 ---- packages/@jsii/utils/src/assembly.test.ts | 149 ---------------- packages/@jsii/utils/src/assembly.ts | 145 ---------------- packages/@jsii/utils/src/index.ts | 1 - packages/@jsii/utils/tsconfig.json | 10 -- 11 files changed, 573 deletions(-) delete mode 100644 packages/@jsii/utils/.gitignore delete mode 100644 packages/@jsii/utils/.npmignore delete mode 100644 packages/@jsii/utils/LICENSE delete mode 100644 packages/@jsii/utils/NOTICE delete mode 100644 packages/@jsii/utils/README.md delete mode 100644 packages/@jsii/utils/jest.config.ts delete mode 100644 packages/@jsii/utils/package.json delete mode 100644 packages/@jsii/utils/src/assembly.test.ts delete mode 100644 packages/@jsii/utils/src/assembly.ts delete mode 100644 packages/@jsii/utils/src/index.ts delete mode 100644 packages/@jsii/utils/tsconfig.json diff --git a/packages/@jsii/utils/.gitignore b/packages/@jsii/utils/.gitignore deleted file mode 100644 index f011fea9b2..0000000000 --- a/packages/@jsii/utils/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.js -*.d.ts -node_modules/ -.nyc_output/ -coverage/ - -lib/version.ts -*.d.ts.map diff --git a/packages/@jsii/utils/.npmignore b/packages/@jsii/utils/.npmignore deleted file mode 100644 index db723ea806..0000000000 --- a/packages/@jsii/utils/.npmignore +++ /dev/null @@ -1,13 +0,0 @@ -* - -!**/*.js -!**/*.d.ts - - -coverage - -# Don't include various configuration & state information -coverage -.eslintrc.* -tsconfig.json -*.tsbuildinfo diff --git a/packages/@jsii/utils/LICENSE b/packages/@jsii/utils/LICENSE deleted file mode 100644 index 129acd53d9..0000000000 --- a/packages/@jsii/utils/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - 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 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - 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. \ No newline at end of file diff --git a/packages/@jsii/utils/NOTICE b/packages/@jsii/utils/NOTICE deleted file mode 100644 index dc4ac3f857..0000000000 --- a/packages/@jsii/utils/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -jsii -Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@jsii/utils/README.md b/packages/@jsii/utils/README.md deleted file mode 100644 index 38e3124455..0000000000 --- a/packages/@jsii/utils/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### jsii Utility Function Library - -This library stores utility functions to be used by modules that consume jsii. \ No newline at end of file diff --git a/packages/@jsii/utils/jest.config.ts b/packages/@jsii/utils/jest.config.ts deleted file mode 100644 index 6da6af03e8..0000000000 --- a/packages/@jsii/utils/jest.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -import config from '../../../jest.config'; - -export default config; diff --git a/packages/@jsii/utils/package.json b/packages/@jsii/utils/package.json deleted file mode 100644 index 2100b27e7c..0000000000 --- a/packages/@jsii/utils/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@jsii/utils", - "version": "0.0.0", - "description": "Utility functions for jsii modules", - "license": "Apache-2.0", - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com" - }, - "homepage": "https://github.com/aws/jsii", - "bugs": { - "url": "https://github.com/aws/jsii/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/aws/jsii.git", - "directory": "packages/@jsii/utils" - }, - "engines": { - "node": ">= 12.7.0" - }, - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc --build && npm run lint", - "watch": "tsc --build -w", - "lint": "eslint . --ext .js,.ts --ignore-path=.gitignore --ignore-pattern=webpack.config.js", - "lint:fix": "yarn lint --fix", - "test": "jest", - "test:update": "jest -u", - "package": "package-js" - }, - "dependencies": { - "fs-extra": "^10.1.0", - "@jsii/spec": "^0.0.0" - } -} diff --git a/packages/@jsii/utils/src/assembly.test.ts b/packages/@jsii/utils/src/assembly.test.ts deleted file mode 100644 index caf64c0560..0000000000 --- a/packages/@jsii/utils/src/assembly.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import * as spec from '@jsii/spec'; -import * as fs from 'fs-extra'; -import * as os from 'os'; -import * as path from 'path'; - -import { - loadAssemblyFromPath, - getAssemblyFile, - writeAssembly, - SPEC_FILE_NAME, - SPEC_FILE_NAME_COMPRESSED, -} from './assembly'; - -const TEST_ASSEMBLY: spec.Assembly = { - schema: spec.SchemaVersion.LATEST, - name: 'jsii-test-dep', - version: '1.2.4', - license: 'Apache-2.0', - description: 'A test assembly', - homepage: 'https://github.com/aws/jsii', - repository: { type: 'git', url: 'git://github.com/aws/jsii.git' }, - author: { - name: 'Amazon Web Services', - url: 'https://aws.amazon.com', - organization: true, - roles: ['author'], - }, - fingerprint: 'F1NG3RPR1N7', - dependencies: { - 'jsii-test-dep-dep': '3.2.1', - }, - jsiiVersion: '1.0.0', -}; - -describe('writeAssembly', () => { - test('can write compressed assembly', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); - - expect( - fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME_COMPRESSED)), - ).toBeTruthy(); - - // includes .jsii files with instructions for finding compressed file - const instructions = fs.readJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { - encoding: 'utf-8', - }); - expect(instructions).toEqual({ - schema: 'jsii/file-redirect', - compression: 'gzip', - filename: SPEC_FILE_NAME_COMPRESSED, - }); - }); - - test('can write uncompressed assembly', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); - - expect(fs.existsSync(path.join(tmpdir, SPEC_FILE_NAME))).toBeTruthy(); - }); -}); - -describe('getAssemblyFile', () => { - test('finds SPEC_FILE_NAME file when there is no compression', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); - - expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); - }); - - test('finds SPEC_FILE_NAME file even when there is compression', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); - - expect(getAssemblyFile(tmpdir)).toEqual(path.join(tmpdir, SPEC_FILE_NAME)); - }); - - test('throws if SPEC_FILE_NAME file does not exist', () => { - const tmpdir = makeTempDir(); - - expect(() => getAssemblyFile(tmpdir)).toThrow( - `Expected to find ${SPEC_FILE_NAME} file in ${tmpdir}, but no such file found`, - ); - }); -}); - -describe('loadAssemblyFromPath', () => { - test('loads compressed assembly', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: true }); - - expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); - }); - - test('loads uncompressed assembly', () => { - const tmpdir = makeTempDir(); - writeAssembly(tmpdir, TEST_ASSEMBLY, { compress: false }); - - expect(loadAssemblyFromPath(tmpdir)).toEqual(TEST_ASSEMBLY); - }); - - test('compressed and uncompressed assemblies are loaded identically', () => { - const compressedTmpDir = makeTempDir(); - const uncompressedTmpDir = makeTempDir(); - - writeAssembly(compressedTmpDir, TEST_ASSEMBLY, { compress: true }); - writeAssembly(uncompressedTmpDir, TEST_ASSEMBLY, { compress: false }); - - expect(loadAssemblyFromPath(compressedTmpDir)).toEqual( - loadAssemblyFromPath(uncompressedTmpDir), - ); - }); - - test('throws if redirect schema is invalid', () => { - const tmpdir = makeTempDir(); - fs.writeJsonSync(path.join(tmpdir, SPEC_FILE_NAME), { - schema: 'jsii/file-redirect', - compression: '7zip', - }); - - expect(() => loadAssemblyFromPath(tmpdir)).toThrow( - [ - 'Invalid redirect schema:', - " compression must be 'gzip' but received '7zip'", - " schema must include property 'filename'", - ].join('\n'), - ); - }); - - test('throws if assembly is invalid', () => { - const tmpdir = makeTempDir(); - fs.writeJsonSync( - path.join(tmpdir, SPEC_FILE_NAME), - { - assembly: 'not a valid assembly', - }, - { - encoding: 'utf8', - spaces: 2, - }, - ); - - expect(() => loadAssemblyFromPath(tmpdir)).toThrow(/Invalid assembly/); - }); -}); - -function makeTempDir() { - return fs.mkdtempSync(path.join(os.tmpdir(), path.basename(__filename))); -} diff --git a/packages/@jsii/utils/src/assembly.ts b/packages/@jsii/utils/src/assembly.ts deleted file mode 100644 index 4e46f81a1d..0000000000 --- a/packages/@jsii/utils/src/assembly.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as spec from '@jsii/spec'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as zlib from 'zlib'; - -/** - * Expected file name for jsii assembly or instructions to compressed assembly. - */ -export const SPEC_FILE_NAME = spec.SPEC_FILE_NAME; - -/** - * Expected file name for compressed assemblies. - */ -export const SPEC_FILE_NAME_COMPRESSED = spec.SPEC_FILE_NAME_COMPRESSED; - -/** - * Finds the path to the SPEC_FILE_NAME file, which will either - * be the assembly or hold instructions to find the assembly. - * - * @param directory path to a directory with an assembly file - * @returns path to the SPEC_FILE_NAME file - */ -export function getAssemblyFile(directory: string) { - const dotJsiiFile = path.join(directory, SPEC_FILE_NAME); - - if (!fs.existsSync(dotJsiiFile)) { - throw new Error( - `Expected to find ${SPEC_FILE_NAME} file in ${directory}, but no such file found`, - ); - } - - return dotJsiiFile; -} - -/** - * Writes the assembly file either as .jsii or .jsii.gz if zipped - * - * @param directory the directory path to place the assembly file - * @param assembly the contents of the assembly - * @param compress whether or not to zip the assembly (.jsii.gz) - * @returns whether or not the assembly was zipped - */ -export function writeAssembly( - directory: string, - assembly: spec.Assembly, - { compress = false }: { compress?: boolean } = {}, -) { - if (compress) { - // write .jsii file with instructions on opening the compressed file - fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), { - schema: 'jsii/file-redirect', - compression: 'gzip', - filename: SPEC_FILE_NAME_COMPRESSED, - }); - - // write actual assembly contents in .jsii.gz - fs.writeFileSync( - path.join(directory, SPEC_FILE_NAME_COMPRESSED), - zlib.gzipSync(JSON.stringify(assembly)), - ); - } else { - fs.writeJsonSync(path.join(directory, SPEC_FILE_NAME), assembly, { - encoding: 'utf8', - spaces: 2, - }); - } - - return compress; -} - -/** - * Loads the assembly file and, if present, follows instructions - * found in the file to unzip compressed assemblies. - * - * @param directory the directory of the assembly file - * @param validate whether to validate the contents of the file - * @returns the assembly file as json - */ -export function loadAssemblyFromPath( - directory: string, - validate = true, -): spec.Assembly { - const assemblyFile = getAssemblyFile(directory); - return loadAssemblyFromFile(assemblyFile, validate); -} - -/** - * Loads the assembly file and, if present, follows instructions - * found in the file to unzip compressed assemblies. - * - * @param pathToFile the path to the SPEC_FILE_NAME file - * @param validate whether to validate the contents of the file - * @returns the assembly file as json - */ -export function loadAssemblyFromFile( - pathToFile: string, - validate = true, -): spec.Assembly { - let contents = readAssembly(pathToFile); - - // check if the file holds instructions to the actual assembly file - if (contents.schema === 'jsii/file-redirect') { - contents = findRedirectAssembly(pathToFile, contents); - } - - return validate - ? spec.validateAssembly(contents) - : (contents as spec.Assembly); -} - -function readAssembly(pathToFile: string) { - return fs.readJsonSync(pathToFile, { - encoding: 'utf-8', - }); -} - -function findRedirectAssembly( - pathToFile: string, - contents: Record, -) { - validateRedirectSchema(contents); - const redirectAssemblyFile = path.join( - path.dirname(pathToFile), - contents.filename, - ); - return JSON.parse( - zlib.gunzipSync(fs.readFileSync(redirectAssemblyFile)).toString(), - ); -} - -function validateRedirectSchema(contents: Record) { - const errors = []; - if (contents.compression !== 'gzip') { - errors.push( - `compression must be 'gzip' but received '${contents.compression}'`, - ); - } - if (contents.filename === undefined) { - errors.push("schema must include property 'filename'"); - } - - if (errors.length !== 0) { - throw new Error(`Invalid redirect schema:\n ${errors.join('\n ')}`); - } -} diff --git a/packages/@jsii/utils/src/index.ts b/packages/@jsii/utils/src/index.ts deleted file mode 100644 index b407c85a37..0000000000 --- a/packages/@jsii/utils/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './assembly'; diff --git a/packages/@jsii/utils/tsconfig.json b/packages/@jsii/utils/tsconfig.json deleted file mode 100644 index 543407f66c..0000000000 --- a/packages/@jsii/utils/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../../tsconfig-base", - "compilerOptions": { - "rootDir": "src", - "outDir": "lib", - }, - "include": [ - "src/**/*.ts" - ], -} From 8d380404bce35258298abaca782a0cbfad937786 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:10:34 -0400 Subject: [PATCH 32/41] update kernel --- packages/@jsii/kernel/package.json | 1 - packages/@jsii/kernel/src/kernel.ts | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/@jsii/kernel/package.json b/packages/@jsii/kernel/package.json index 884a4125e1..bda7ffa0c6 100644 --- a/packages/@jsii/kernel/package.json +++ b/packages/@jsii/kernel/package.json @@ -32,7 +32,6 @@ }, "dependencies": { "@jsii/spec": "^0.0.0", - "@jsii/utils": "^0.0.0", "fs-extra": "^10.1.0", "tar": "^6.1.11" }, diff --git a/packages/@jsii/kernel/src/kernel.ts b/packages/@jsii/kernel/src/kernel.ts index 51ac24f4bf..0e237b5f8c 100644 --- a/packages/@jsii/kernel/src/kernel.ts +++ b/packages/@jsii/kernel/src/kernel.ts @@ -1,5 +1,4 @@ import * as spec from '@jsii/spec'; -import { loadAssemblyFromPath } from '@jsii/utils'; import * as cp from 'child_process'; import * as fs from 'fs-extra'; import * as os from 'os'; @@ -117,7 +116,7 @@ export class Kernel { // read .jsii metadata from the root of the package let assmSpec; try { - assmSpec = loadAssemblyFromPath(packageDir); + assmSpec = spec.loadAssemblyFromPath(packageDir); } catch { throw new Error( `Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`, From d657866e1438e66aaa7e9ac77d5f34d05f5dad58 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:13:30 -0400 Subject: [PATCH 33/41] update kernel --- packages/@jsii/runtime/package.json | 3 +-- packages/@jsii/runtime/test/kernel-host.test.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@jsii/runtime/package.json b/packages/@jsii/runtime/package.json index f31ed3ada5..aa1ee66cbb 100644 --- a/packages/@jsii/runtime/package.json +++ b/packages/@jsii/runtime/package.json @@ -36,8 +36,7 @@ "dependencies": { "@jsii/kernel": "^0.0.0", "@jsii/check-node": "0.0.0", - "@jsii/spec": "^0.0.0", - "@jsii/utils": "^0.0.0" + "@jsii/spec": "^0.0.0" }, "devDependencies": { "@scope/jsii-calc-base": "^0.0.0", diff --git a/packages/@jsii/runtime/test/kernel-host.test.ts b/packages/@jsii/runtime/test/kernel-host.test.ts index f8f7b668e8..355c0cf855 100644 --- a/packages/@jsii/runtime/test/kernel-host.test.ts +++ b/packages/@jsii/runtime/test/kernel-host.test.ts @@ -1,6 +1,5 @@ import { api } from '@jsii/kernel'; import * as spec from '@jsii/spec'; -import { loadAssemblyFromPath } from '@jsii/utils'; import * as child from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; @@ -87,7 +86,7 @@ function loadRequest(library: string): api.LoadRequest { }; function loadAssembly(): spec.Assembly { - return loadAssemblyFromPath( + return spec.loadAssemblyFromPath( path.resolve(require.resolve(`${library}/package.json`), '..'), ); } From d9af12d108af0db640b057124152c26cd6e2afb0 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:15:42 -0400 Subject: [PATCH 34/41] update jsii-reflect --- packages/jsii-reflect/lib/type-system.ts | 2 +- packages/jsii-reflect/package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/jsii-reflect/lib/type-system.ts b/packages/jsii-reflect/lib/type-system.ts index 296c09885d..65286e0d0a 100644 --- a/packages/jsii-reflect/lib/type-system.ts +++ b/packages/jsii-reflect/lib/type-system.ts @@ -1,4 +1,4 @@ -import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/utils'; +import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/spec'; import * as fs from 'fs-extra'; import * as path from 'path'; diff --git a/packages/jsii-reflect/package.json b/packages/jsii-reflect/package.json index 83c398a370..b5c64e2166 100644 --- a/packages/jsii-reflect/package.json +++ b/packages/jsii-reflect/package.json @@ -36,7 +36,6 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "^0.0.0", - "@jsii/utils": "^0.0.0", "chalk": "^4", "fs-extra": "^10.1.0", "oo-ascii-tree": "^0.0.0", From e7bfd191f561b89a0843f4dfea9590014ec3504a Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:17:37 -0400 Subject: [PATCH 35/41] reupdate kernel and runtime --- packages/@jsii/kernel/src/kernel.ts | 3 ++- packages/@jsii/runtime/test/kernel-host.test.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@jsii/kernel/src/kernel.ts b/packages/@jsii/kernel/src/kernel.ts index 0e237b5f8c..040d597d42 100644 --- a/packages/@jsii/kernel/src/kernel.ts +++ b/packages/@jsii/kernel/src/kernel.ts @@ -1,4 +1,5 @@ import * as spec from '@jsii/spec'; +import { loadAssemblyFromPath } from '@jsii/spec'; import * as cp from 'child_process'; import * as fs from 'fs-extra'; import * as os from 'os'; @@ -116,7 +117,7 @@ export class Kernel { // read .jsii metadata from the root of the package let assmSpec; try { - assmSpec = spec.loadAssemblyFromPath(packageDir); + assmSpec = loadAssemblyFromPath(packageDir); } catch { throw new Error( `Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`, diff --git a/packages/@jsii/runtime/test/kernel-host.test.ts b/packages/@jsii/runtime/test/kernel-host.test.ts index 355c0cf855..1c9087b623 100644 --- a/packages/@jsii/runtime/test/kernel-host.test.ts +++ b/packages/@jsii/runtime/test/kernel-host.test.ts @@ -1,5 +1,6 @@ import { api } from '@jsii/kernel'; import * as spec from '@jsii/spec'; +import { loadAssemblyFromPath } from '@jsii/spec'; import * as child from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; @@ -86,7 +87,7 @@ function loadRequest(library: string): api.LoadRequest { }; function loadAssembly(): spec.Assembly { - return spec.loadAssemblyFromPath( + return loadAssemblyFromPath( path.resolve(require.resolve(`${library}/package.json`), '..'), ); } From 35c4e0a36eba5dd5d6dce0dd0e354bb342ac1039 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:19:39 -0400 Subject: [PATCH 36/41] update jsii-rosetta --- packages/jsii-rosetta/lib/commands/transliterate.ts | 3 +-- packages/jsii-rosetta/lib/jsii/assemblies.ts | 2 +- packages/jsii-rosetta/package.json | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/jsii-rosetta/lib/commands/transliterate.ts b/packages/jsii-rosetta/lib/commands/transliterate.ts index 586fc8d1b2..f6538840b1 100644 --- a/packages/jsii-rosetta/lib/commands/transliterate.ts +++ b/packages/jsii-rosetta/lib/commands/transliterate.ts @@ -1,5 +1,4 @@ -import { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind } from '@jsii/spec'; -import { loadAssemblyFromPath } from '@jsii/utils'; +import { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind, loadAssemblyFromPath } from '@jsii/spec'; import { writeJson } from 'fs-extra'; import { resolve } from 'path'; diff --git a/packages/jsii-rosetta/lib/jsii/assemblies.ts b/packages/jsii-rosetta/lib/jsii/assemblies.ts index 5d625eae04..a488f8e111 100644 --- a/packages/jsii-rosetta/lib/jsii/assemblies.ts +++ b/packages/jsii-rosetta/lib/jsii/assemblies.ts @@ -1,5 +1,5 @@ import * as spec from '@jsii/spec'; -import { loadAssemblyFromFile, loadAssemblyFromPath, getAssemblyFile, writeAssembly } from '@jsii/utils'; +import { loadAssemblyFromFile, loadAssemblyFromPath, getAssemblyFile, writeAssembly } from '@jsii/spec'; import * as crypto from 'crypto'; import * as fs from 'fs-extra'; import * as path from 'path'; diff --git a/packages/jsii-rosetta/package.json b/packages/jsii-rosetta/package.json index 8bdfea8c90..a1f9146108 100644 --- a/packages/jsii-rosetta/package.json +++ b/packages/jsii-rosetta/package.json @@ -28,7 +28,6 @@ "dependencies": { "@jsii/check-node": "0.0.0", "@jsii/spec": "0.0.0", - "@jsii/utils": "0.0.0", "commonmark": "^0.30.0", "fs-extra": "^10.1.0", "typescript-3.9": "npm:typescript@~3.9.10", From c4dce184111d3db11d865c27c0774c16ecb7aa0f Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:22:09 -0400 Subject: [PATCH 37/41] more rosetta --- packages/jsii-rosetta/test/commands/infuse.test.ts | 2 +- packages/jsii-rosetta/test/commands/transliterate.test.ts | 3 +-- packages/jsii-rosetta/test/testutil.ts | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/jsii-rosetta/test/commands/infuse.test.ts b/packages/jsii-rosetta/test/commands/infuse.test.ts index 2167e40640..28cfffb5c7 100644 --- a/packages/jsii-rosetta/test/commands/infuse.test.ts +++ b/packages/jsii-rosetta/test/commands/infuse.test.ts @@ -1,4 +1,4 @@ -import { loadAssemblyFromPath } from '@jsii/utils'; +import { loadAssemblyFromPath } from '@jsii/spec'; import * as fs from 'fs-extra'; import * as path from 'path'; diff --git a/packages/jsii-rosetta/test/commands/transliterate.test.ts b/packages/jsii-rosetta/test/commands/transliterate.test.ts index a1151a76c5..585fe66c47 100644 --- a/packages/jsii-rosetta/test/commands/transliterate.test.ts +++ b/packages/jsii-rosetta/test/commands/transliterate.test.ts @@ -1,5 +1,4 @@ -import { Assembly, SPEC_FILE_NAME } from '@jsii/spec'; -import { writeAssembly } from '@jsii/utils'; +import { Assembly, SPEC_FILE_NAME, writeAssembly } from '@jsii/spec'; import * as fs from 'fs-extra'; import * as jsii from 'jsii'; import * as path from 'path'; diff --git a/packages/jsii-rosetta/test/testutil.ts b/packages/jsii-rosetta/test/testutil.ts index 5ae5107902..a54efa47ba 100644 --- a/packages/jsii-rosetta/test/testutil.ts +++ b/packages/jsii-rosetta/test/testutil.ts @@ -1,5 +1,4 @@ -import * as spec from '@jsii/spec'; -import { writeAssembly } from '@jsii/utils'; +import { Assembly, writeAssembly } from '@jsii/spec'; import * as fs from 'fs-extra'; import { PackageInfo, compileJsiiForTest, TestWorkspace } from 'jsii'; import * as os from 'os'; @@ -46,7 +45,7 @@ export class TestJsiiModule { public readonly workspaceDirectory: string; private constructor( - public readonly assembly: spec.Assembly, + public readonly assembly: Assembly, public readonly workspace: TestWorkspace, private readonly compressAssembly: boolean, ) { From ded94555ea2379dd3580443ce6dc5d9c6942c1ba Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 16:29:38 -0400 Subject: [PATCH 38/41] update jsii --- packages/jsii/lib/helpers.ts | 3 +-- packages/jsii/lib/project-info.ts | 2 +- packages/jsii/test/compiler.test.ts | 2 +- packages/jsii/test/project-info.test.ts | 2 +- packages/jsii/test/submodules.test.ts | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/jsii/lib/helpers.ts b/packages/jsii/lib/helpers.ts index 2c377d431e..d600ba9ad6 100644 --- a/packages/jsii/lib/helpers.ts +++ b/packages/jsii/lib/helpers.ts @@ -7,8 +7,7 @@ */ import * as spec from '@jsii/spec'; -import { PackageJson } from '@jsii/spec'; -import { loadAssemblyFromPath, writeAssembly } from '@jsii/utils'; +import { PackageJson, loadAssemblyFromPath, writeAssembly } from '@jsii/spec'; import * as fs from 'fs-extra'; import * as os from 'os'; import * as path from 'path'; diff --git a/packages/jsii/lib/project-info.ts b/packages/jsii/lib/project-info.ts index 02ddf5974c..154260328e 100644 --- a/packages/jsii/lib/project-info.ts +++ b/packages/jsii/lib/project-info.ts @@ -1,5 +1,5 @@ import * as spec from '@jsii/spec'; -import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/utils'; +import { getAssemblyFile, loadAssemblyFromFile } from '@jsii/spec'; import * as fs from 'fs-extra'; import * as log4js from 'log4js'; import * as path from 'path'; diff --git a/packages/jsii/test/compiler.test.ts b/packages/jsii/test/compiler.test.ts index 2113c0699f..162c6bf79a 100644 --- a/packages/jsii/test/compiler.test.ts +++ b/packages/jsii/test/compiler.test.ts @@ -2,7 +2,7 @@ import { loadAssemblyFromPath, SPEC_FILE_NAME, SPEC_FILE_NAME_COMPRESSED, -} from '@jsii/utils'; +} from '@jsii/spec'; import { ensureDirSync, existsSync, diff --git a/packages/jsii/test/project-info.test.ts b/packages/jsii/test/project-info.test.ts index 516db751bb..0f3920dbdf 100644 --- a/packages/jsii/test/project-info.test.ts +++ b/packages/jsii/test/project-info.test.ts @@ -1,5 +1,5 @@ import * as spec from '@jsii/spec'; -import { writeAssembly } from '@jsii/utils'; +import { writeAssembly } from '@jsii/spec'; import * as clone from 'clone'; import * as fs from 'fs-extra'; import * as os from 'os'; diff --git a/packages/jsii/test/submodules.test.ts b/packages/jsii/test/submodules.test.ts index 2f19b33259..988589a8d6 100644 --- a/packages/jsii/test/submodules.test.ts +++ b/packages/jsii/test/submodules.test.ts @@ -1,5 +1,5 @@ import * as spec from '@jsii/spec'; -import { writeAssembly, loadAssemblyFromPath } from '@jsii/utils'; +import { writeAssembly, loadAssemblyFromPath } from '@jsii/spec'; import { sourceToAssemblyHelper, From 925bf7b4677653f57343f69a551f72b1be88f908 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 17:43:24 -0400 Subject: [PATCH 39/41] npmignore --- packages/jsii-calc/.npmignore | 4 ++-- packages/jsii-pacmak/lib/npm-modules.ts | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/jsii-calc/.npmignore b/packages/jsii-calc/.npmignore index 8eec677f1c..e65f85f65b 100644 --- a/packages/jsii-calc/.npmignore +++ b/packages/jsii-calc/.npmignore @@ -3,9 +3,9 @@ !*.d.ts *.tgz -# Include .jsii +# Include .jsii and .jsii.gz !.jsii - +!.jsii.gz # Exclude jsii outdir dist diff --git a/packages/jsii-pacmak/lib/npm-modules.ts b/packages/jsii-pacmak/lib/npm-modules.ts index 9eb2dccb04..81f2820c83 100644 --- a/packages/jsii-pacmak/lib/npm-modules.ts +++ b/packages/jsii-pacmak/lib/npm-modules.ts @@ -150,8 +150,11 @@ async function updateNpmIgnore( ); } - includePattern('Include .jsii.gz', spec.SPEC_FILE_NAME_COMPRESSED); - includePattern('Include .jsii', spec.SPEC_FILE_NAME); + includePattern( + 'Include .jsii and .jsii.gz', + spec.SPEC_FILE_NAME, + spec.SPEC_FILE_NAME_COMPRESSED, + ); if (modified) { await fs.writeFile(npmIgnorePath, `${lines.join('\n')}\n`); From af248581c4a0673e31795687ae4a0b2236e8df29 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Mon, 27 Jun 2022 18:06:44 -0400 Subject: [PATCH 40/41] more npmignores --- packages/@scope/jsii-calc-base-of-base/.npmignore | 3 ++- packages/@scope/jsii-calc-base/.npmignore | 3 ++- packages/@scope/jsii-calc-lib/.npmignore | 3 ++- packages/jsii-calc/.npmignore | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/@scope/jsii-calc-base-of-base/.npmignore b/packages/@scope/jsii-calc-base-of-base/.npmignore index 5ae704cff8..2f2ad5326e 100644 --- a/packages/@scope/jsii-calc-base-of-base/.npmignore +++ b/packages/@scope/jsii-calc-base-of-base/.npmignore @@ -4,8 +4,9 @@ *.tgz -# Include .jsii +# Include .jsii and .jsii.gz !.jsii +!.jsii.gz # Exclude jsii outdir diff --git a/packages/@scope/jsii-calc-base/.npmignore b/packages/@scope/jsii-calc-base/.npmignore index 5ae704cff8..2f2ad5326e 100644 --- a/packages/@scope/jsii-calc-base/.npmignore +++ b/packages/@scope/jsii-calc-base/.npmignore @@ -4,8 +4,9 @@ *.tgz -# Include .jsii +# Include .jsii and .jsii.gz !.jsii +!.jsii.gz # Exclude jsii outdir diff --git a/packages/@scope/jsii-calc-lib/.npmignore b/packages/@scope/jsii-calc-lib/.npmignore index 5ae704cff8..2f2ad5326e 100644 --- a/packages/@scope/jsii-calc-lib/.npmignore +++ b/packages/@scope/jsii-calc-lib/.npmignore @@ -4,8 +4,9 @@ *.tgz -# Include .jsii +# Include .jsii and .jsii.gz !.jsii +!.jsii.gz # Exclude jsii outdir diff --git a/packages/jsii-calc/.npmignore b/packages/jsii-calc/.npmignore index e65f85f65b..b3913a2580 100644 --- a/packages/jsii-calc/.npmignore +++ b/packages/jsii-calc/.npmignore @@ -7,6 +7,7 @@ !.jsii !.jsii.gz + # Exclude jsii outdir dist From 329c15307cf89ede2d7eb043eec80f092d68d08b Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Tue, 28 Jun 2022 11:21:02 -0400 Subject: [PATCH 41/41] add error message to blind catch --- packages/@jsii/kernel/src/kernel.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@jsii/kernel/src/kernel.ts b/packages/@jsii/kernel/src/kernel.ts index 040d597d42..0939152902 100644 --- a/packages/@jsii/kernel/src/kernel.ts +++ b/packages/@jsii/kernel/src/kernel.ts @@ -118,10 +118,8 @@ export class Kernel { let assmSpec; try { assmSpec = loadAssemblyFromPath(packageDir); - } catch { - throw new Error( - `Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`, - ); + } catch (e: any) { + throw new Error(`Error for package tarball ${req.tarball}: ${e.message}`); } // load the module and capture it's closure