Skip to content

Commit 31ce1e9

Browse files
authored
chore(core): create submodule exports in core (#6079)
* chore(core): create submodule exports in core * chore(core): organize submodules * chore(core): submodules linting * chore(core): submodule readmes * chore(core): update readme about Metro package exports support * chore(core): add compatibility redirect files for core submodules * chore(core): add files entry in pkg.json * chore(core): add files pkg.json enforcement * chore(core): import submodules in core root index
1 parent d40d02a commit 31ce1e9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+261
-23
lines changed

README.md

Lines changed: 5 additions & 0 deletions

packages/cloudfront-signer/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
"@smithy/url-parser": "^3.0.0",
2525
"tslib": "^2.6.2"
2626
},
27+
"files": [
28+
"dist-*/**"
29+
],
2730
"devDependencies": {
2831
"@tsconfig/recommended": "1.0.1",
2932
"concurrently": "7.0.0",

packages/core/README.md

Lines changed: 35 additions & 1 deletion

packages/core/client.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Do not edit:
3+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
4+
*/
5+
module.exports = require("./dist-cjs/submodules/client/index.js");

packages/core/httpAuthSchemes.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Do not edit:
3+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
4+
*/
5+
module.exports = require("./dist-cjs/submodules/httpAuthSchemes/index.js");

packages/core/package.json

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "3.575.0",
44
"description": "Core functions & classes shared by multiple AWS SDK clients",
55
"scripts": {
6-
"build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
6+
"build": "yarn lint && concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
77
"build:cjs": "node ../../scripts/compilation/inline core",
88
"build:es": "tsc -p tsconfig.es.json",
99
"build:include:deps": "lerna run --scope $npm_package_name --include-dependencies build",
@@ -18,6 +18,43 @@
1818
"main": "./dist-cjs/index.js",
1919
"module": "./dist-es/index.js",
2020
"types": "./dist-types/index.d.ts",
21+
"exports": {
22+
".": {
23+
"node": "./dist-cjs/index.js",
24+
"import": "./dist-es/index.js",
25+
"require": "./dist-cjs/index.js",
26+
"types": "./dist-types/index.d.ts"
27+
},
28+
"./package.json": {
29+
"node": "./package.json",
30+
"import": "./package.json",
31+
"require": "./package.json"
32+
},
33+
"./client": {
34+
"node": "./dist-cjs/submodules/client/index.js",
35+
"import": "./dist-es/submodules/client/index.js",
36+
"require": "./dist-cjs/submodules/client/index.js",
37+
"types": "./dist-types/submodules/client/index.d.ts"
38+
},
39+
"./httpAuthSchemes": {
40+
"node": "./dist-cjs/submodules/httpAuthSchemes/index.js",
41+
"import": "./dist-es/submodules/httpAuthSchemes/index.js",
42+
"require": "./dist-cjs/submodules/httpAuthSchemes/index.js",
43+
"types": "./dist-types/submodules/httpAuthSchemes/index.d.ts"
44+
},
45+
"./protocols": {
46+
"node": "./dist-cjs/submodules/protocols/index.js",
47+
"import": "./dist-es/submodules/protocols/index.js",
48+
"require": "./dist-cjs/submodules/protocols/index.js",
49+
"types": "./dist-types/submodules/protocols/index.d.ts"
50+
}
51+
},
52+
"files": [
53+
"dist-*/**",
54+
"./client.js",
55+
"./httpAuthSchemes.js",
56+
"./protocols.js"
57+
],
2158
"sideEffects": false,
2259
"author": {
2360
"name": "AWS SDK for JavaScript Team",

packages/core/protocols.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Do not edit:
3+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
4+
*/
5+
module.exports = require("./dist-cjs/submodules/protocols/index.js");

packages/core/scripts/lint.js

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,98 @@
11
const fs = require("fs");
22
const path = require("path");
3-
const assert = require("assert");
43

54
const root = path.join(__dirname, "..");
65

76
const pkgJson = require(path.join(root, "package.json"));
8-
const srcFolders = fs.readdirSync(path.join(root, "src"));
7+
const tsconfigs = {
8+
cjs: require(path.join(root, "tsconfig.cjs.json")),
9+
es: require(path.join(root, "tsconfig.es.json")),
10+
types: require(path.join(root, "tsconfig.types.json")),
11+
};
12+
const submodules = fs.readdirSync(path.join(root, "src", "submodules"));
913

10-
assert(pkgJson.exports === undefined, "We cannot support package.json exports yet.");
14+
const errors = [];
1115

16+
for (const submodule of submodules) {
17+
const submodulePath = path.join(root, "src", "submodules", submodule);
18+
if (fs.existsSync(submodulePath) && fs.lstatSync(submodulePath).isDirectory()) {
19+
// package.json metadata.
20+
if (!pkgJson.exports[`./${submodule}`]) {
21+
errors.push(`${submodule} submodule is missing exports statement in package.json`);
22+
pkgJson.exports[`./${submodule}`] = {
23+
node: `./dist-cjs/submodules/${submodule}/index.js`,
24+
import: `./dist-es/submodules/${submodule}/index.js`,
25+
require: `./dist-cjs/submodules/${submodule}/index.js`,
26+
types: `./dist-types/submodules/${submodule}/index.d.ts`,
27+
};
28+
fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n");
29+
}
30+
if (!pkgJson.files.includes(`./${submodule}.js`)) {
31+
pkgJson.files.push(`./${submodule}.js`);
32+
errors.push(`package.json files array missing ${submodule}.js compatibility redirect file.`);
33+
fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n");
34+
}
35+
// tsconfig metadata.
36+
for (const [kind, tsconfig] of Object.entries(tsconfigs)) {
37+
if (!tsconfig.compilerOptions.paths?.[`@aws-sdk/core/${submodule}`]) {
38+
errors.push(`${submodule} submodule is missing paths entry in tsconfig.${kind}.json`);
39+
40+
tsconfig.compilerOptions.paths[`@aws-sdk/core/${submodule}`] = [`./src/submodules/${submodule}/index.ts`];
41+
fs.writeFileSync(path.join(root, `tsconfig.${kind}.json`), JSON.stringify(tsconfig, null, 2) + "\n");
42+
}
43+
}
44+
// compatibility redirect file.
45+
const compatibilityRedirectFile = path.join(root, `${submodule}.js`);
46+
if (!fs.existsSync(compatibilityRedirectFile)) {
47+
errors.push(`${submodule} is missing compatibility redirect file in the package root folder.`);
48+
fs.writeFileSync(
49+
compatibilityRedirectFile,
50+
`
1251
/**
13-
* We probably can't enable package.json exports until
14-
* dropping support for Node.js 14.x and TypeScript 4.6.
52+
* Do not edit:
53+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
1554
*/
16-
process.exit(0);
17-
18-
for (const srcFolder of srcFolders) {
19-
if (fs.lstatSync(path.join(root, "src", srcFolder)).isDirectory()) {
20-
if (!pkgJson.exports["./" + srcFolder]) {
21-
throw new Error(`${srcFolder} is missing exports statement in package.json`);
55+
module.exports = require("./dist-cjs/submodules/${submodule}/index.js");
56+
`
57+
);
2258
}
2359
}
2460
}
61+
62+
/**
63+
* Check for cross-submodule relative imports.
64+
*/
65+
66+
const walk = require("../../../scripts/utils/walk");
67+
68+
(async () => {
69+
for await (const item of walk(path.join(root, "src", "submodules"))) {
70+
// depth within the submodule where 1 is at the root of the submodule.
71+
const depth = item.split("core/src/submodules/")[1].split("/").length - 1;
72+
const sourceCode = fs.readFileSync(item, "utf-8");
73+
74+
const relativeImports = [];
75+
relativeImports.push(
76+
...new Set(
77+
[...(sourceCode.toString().match(/(from |import\()"(.*?)";/g) || [])]
78+
.map((_) => _.replace(/from "/g, "").replace(/";$/, ""))
79+
.filter((_) => _.startsWith("."))
80+
)
81+
);
82+
83+
for (const i of relativeImports) {
84+
const relativeImportDepth = i.split("..").length - 1;
85+
if (relativeImportDepth >= depth) {
86+
errors.push(
87+
`relative import ${i} in ${item
88+
.split("packages/")
89+
.pop()} crosses submodule boundaries. Use @scope/package/submodule import instead.`
90+
);
91+
}
92+
}
93+
}
94+
})().then(() => {
95+
if (errors.length) {
96+
throw new Error(errors.join("\n"));
97+
}
98+
});

packages/core/src/index.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1-
export * from "./client/index";
2-
export * from "./httpAuthSchemes/index";
3-
export * from "./protocols/index";
1+
/**
2+
* Submodules annotated with "Legacy" are from prior to the submodule system.
3+
* They are exported from the package's root index to preserve backwards compatibility.
4+
*
5+
* New development should go in a proper submodule and not be exported from the root index.
6+
*/
7+
8+
/**
9+
* Legacy submodule.
10+
*/
11+
export * from "./submodules/client/index";
12+
/**
13+
* Legacy submodule.
14+
*/
15+
export * from "./submodules/httpAuthSchemes/index";
16+
/**
17+
* Legacy submodule.
18+
*/
19+
export * from "./submodules/protocols/index";
20+
21+
/**
22+
* Warning: do not export any additional submodules from the root of this package. See readme.md for
23+
* guide on developing submodules.
24+
*/
Lines changed: 3 additions & 0 deletions
Lines changed: 3 additions & 0 deletions
Lines changed: 3 additions & 0 deletions

packages/core/tsconfig.cjs.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
"compilerOptions": {
33
"rootDir": "./src",
44
"outDir": "./dist-cjs",
5-
"baseUrl": "."
5+
"baseUrl": ".",
6+
"paths": {
7+
"@aws-sdk/core/client": ["./src/submodules/client/index.ts"],
8+
"@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"],
9+
"@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"]
10+
}
611
},
712
"extends": "../../tsconfig.cjs.json",
813
"include": ["src/"]

packages/core/tsconfig.es.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
"compilerOptions": {
33
"rootDir": "./src",
44
"outDir": "./dist-es",
5-
"baseUrl": "."
5+
"baseUrl": ".",
6+
"paths": {
7+
"@aws-sdk/core/client": ["./src/submodules/client/index.ts"],
8+
"@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"],
9+
"@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"]
10+
}
611
},
712
"extends": "../../tsconfig.es.json",
813
"include": ["src/"]

packages/core/tsconfig.types.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
"compilerOptions": {
33
"baseUrl": ".",
44
"declarationDir": "dist-types",
5-
"rootDir": "src"
5+
"rootDir": "src",
6+
"paths": {
7+
"@aws-sdk/core/client": ["./src/submodules/client/index.ts"],
8+
"@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"],
9+
"@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"]
10+
}
611
},
712
"extends": "../../tsconfig.types.json",
813
"include": ["src/"]

scripts/compilation/Inliner.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = class Inliner {
1919
this.isPackage = fs.existsSync(path.join(root, "packages", pkg));
2020
this.isLib = fs.existsSync(path.join(root, "lib", pkg));
2121
this.isClient = !this.isPackage && !this.isLib;
22+
this.isCore = pkg === "core";
2223
this.subfolder = this.isPackage ? "packages" : this.isLib ? "lib" : "clients";
2324

2425
this.packageDirectory = path.join(root, this.subfolder, pkg);
@@ -149,9 +150,9 @@ module.exports = class Inliner {
149150
(variant) => "*/" + path.basename(variant).replace(/.js$/, "")
150151
);
151152

152-
await esbuild.build({
153+
const buildOptions = {
153154
platform: this.platform,
154-
target: ["node14"],
155+
target: ["node16"],
155156
bundle: true,
156157
format: "cjs",
157158
mainFields: ["main"],
@@ -164,7 +165,27 @@ module.exports = class Inliner {
164165
keepNames: true,
165166
packages: "external",
166167
external: ["@smithy/*", "@aws-sdk/*", "node_modules/*", ...this.variantExternalsForEsBuild],
167-
});
168+
};
169+
170+
if (!this.isCore) {
171+
await esbuild.build(buildOptions);
172+
}
173+
174+
if (this.isCore) {
175+
const submodules = fs.readdirSync(path.join(root, this.subfolder, this.package, "src", "submodules"));
176+
for (const submodule of submodules) {
177+
fs.rmSync(path.join(path.join(root, this.subfolder, this.package, "dist-cjs", "submodules", submodule)), {
178+
recursive: true,
179+
force: true,
180+
});
181+
await esbuild.build({
182+
...buildOptions,
183+
entryPoints: [path.join(root, this.subfolder, this.package, "src", "submodules", submodule, "index.ts")],
184+
outfile: path.join(root, this.subfolder, this.package, "dist-cjs", "submodules", submodule, "index.js"),
185+
});
186+
}
187+
}
188+
168189
return this;
169190
}
170191

@@ -173,7 +194,7 @@ module.exports = class Inliner {
173194
* These now become re-exports of the index to preserve deep-import behavior.
174195
*/
175196
async rewriteStubs() {
176-
if (this.bailout) {
197+
if (this.bailout || this.isCore) {
177198
return this;
178199
}
179200

scripts/runtime-dependency-version-check/package-json-enforcement.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ module.exports = function (pkgJsonFilePath, overwrite = false) {
5555
errors.push(`browser and react-native fields are different in ${pkgJson.name}`);
5656
}
5757

58+
if (!pkgJson.files) {
59+
errors.push(`no files entry in ${pkgJson.name}`);
60+
}
61+
5862
if (typeof pkgJson.browser === "object" && typeof pkgJson["react-native"] === "object") {
5963
const browserCanonical = Object.entries(pkgJson.browser).reduce((acc, [k, v]) => {
6064
if (!k.includes("dist-cjs/") || typeof v === "boolean") {

0 commit comments

Comments
 (0)