Skip to content

Commit 1523384

Browse files
authored
feat!: adds Node.js subpath exports (#75)
* feat: get a list of solutions * feat: generate main barrel * feat: adds exports * chore: projen synth * feat: add root export * chore: projen synth * refactor: use libdir * refactor: into a component * docs: use cases * refactor: solutions prop * refactor: generateBarrel * refactor: generateSubPathExports * docs: Construct Bootstrap * refactor: rename for clarity * refactor: rename for clarity
1 parent d2160f3 commit 1523384

File tree

9 files changed

+88
-3
lines changed

9 files changed

+88
-3
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.gitignore

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.prettierignore

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projen/files.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projenrc.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ReleasableCommits, awscdk, github, javascript, release } from 'projen';
22
import { ArrowParens, NodePackageManager } from 'projen/lib/javascript';
3+
import { SubPathExports } from './projenrc/sub-path-exports';
34

45
let cdkVersion = '2.168.0';
56
const project = new awscdk.AwsCdkConstructLibrary({
@@ -106,4 +107,6 @@ project.addTask('integ:update', {
106107
receiveArgs: true,
107108
});
108109

110+
new SubPathExports(project);
111+
109112
project.synth();

CONTRIBUTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,19 @@ export class MyConstruct extends Resource {
109109
* Other import methods normally require access to the context API which is beyond the scope of these constructs. We'd like to address this in the future.
110110
* Constructs should implement an interface so that the import methods (e.g. `.fromSomethingAttributes()`) can return the interface type.
111111

112+
## Construct Bootstrap
113+
114+
To init a new construct, follow these steps:
115+
116+
1. Create a new construct directory in `./src/${YOUR_CONSTRUCT_NAME}`
117+
2. Create an empty barrel file `./src/${YOUR_CONSTRUCT_NAME}/index.ts`
118+
3. Run `npm run default`
119+
120+
This will produce the following changes:
121+
122+
1. Updates to the root barrel file to export the construct.
123+
2. Update to the `package.json` to create Node.js subpath exports to allow subpath imports (`import * as cur from "@open-constructs/aws-cdk/aws-cur"`).
124+
112125
## Testing
113126

114127
Tests are fundamental to building good constructs. The following testing guidelines should be followed:

package.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projenrc/sub-path-exports.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { readdirSync } from 'fs';
2+
import path from 'path';
3+
import { Component, SourceCode } from 'projen';
4+
import type { TypeScriptProject } from 'projen/lib/typescript';
5+
6+
/**
7+
* Dynamically generate Node.js subpath exports and root barrel file.
8+
*
9+
* @see https://nodejs.org/api/packages.html#subpath-patterns
10+
*/
11+
export class SubPathExports extends Component {
12+
private readonly solutions: string[];
13+
14+
constructor(public readonly project: TypeScriptProject) {
15+
super(project);
16+
17+
/**
18+
* Gather all solution directories (e.g. `aws-codeartifact`, `aws-cur`).
19+
*/
20+
this.solutions = readdirSync(path.join(project.outdir, project.srcdir), {
21+
encoding: 'utf8',
22+
withFileTypes: true,
23+
})
24+
.filter(entry => entry.isDirectory())
25+
.map(entry => entry.name)
26+
.sort((a, b) => a.localeCompare(b));
27+
28+
this.generateBarrel();
29+
this.generateSubPathExports();
30+
}
31+
32+
private generateBarrel() {
33+
const sourceCode = new SourceCode(this.project, path.join(this.project.srcdir, 'index.ts'));
34+
35+
sourceCode.line('// ' + sourceCode.marker);
36+
37+
for (const solution of this.solutions) {
38+
const exportedName = solution.split('-').join('_');
39+
sourceCode.line(`export * as ${exportedName} from './${solution}';`);
40+
}
41+
}
42+
43+
private generateSubPathExports() {
44+
const subPathExport = (...chunks: string[]) => './' + path.posix.join(this.project.libdir, ...chunks);
45+
46+
const subPathExports: Record<string, string> = {
47+
'.': subPathExport('index.js'),
48+
};
49+
50+
for (const solution of this.solutions) {
51+
subPathExports[`./${solution}`] = subPathExport(solution, 'index.js');
52+
}
53+
54+
this.project.package.addField('exports', subPathExports);
55+
}
56+
}

src/index.ts

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)