Skip to content

Commit 0db0dbb

Browse files
chore: pr feedback
Add some doc comments and cleanup. Changes the `Module` interface to an abstract base class that is extended by `Package` and `Submodule` to avoid repeating module build and emit logic. Change dynamic getters for module submodules and types to be built and set in constructor to avoid unecessary recomputation.
1 parent 7cbb109 commit 0db0dbb

File tree

12 files changed

+239
-329
lines changed

12 files changed

+239
-329
lines changed
Lines changed: 91 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -1,254 +1,130 @@
11
import { CodeMaker } from 'codemaker';
2-
import { Assembly, Type, Submodule as JsiiSubmodule } from 'jsii-reflect';
3-
import { join } from 'path';
2+
import { Type, Submodule as JsiiSubmodule } from 'jsii-reflect';
3+
import { EmitContext } from './emit-context';
44
import { GoClass, Enum, Interface } from './types';
5+
import { findTypeInTree, goModuleName, flatMap } from './util';
56

6-
type ModuleType = Interface | Enum | GoClass;
7-
type ModuleTypes = ModuleType[];
8-
9-
// TODO: Make this a class?
10-
export interface Module {
11-
root: RootModule;
12-
packageName: string;
13-
moduleName: string;
14-
filePath: string;
15-
file: string;
16-
submodules: Submodule[];
17-
types: ModuleTypes;
18-
hasSubmodules(): boolean;
19-
}
20-
21-
function buildSubmodules(
22-
root: RootModule,
23-
parent: Module,
24-
submodules: readonly JsiiSubmodule[],
25-
): Submodule[] {
26-
return submodules.map((sm) => new Submodule(root, parent, sm));
27-
}
28-
29-
function unknownType(type: Type): never {
30-
throw new Error(`Type: ${type.name} is not an interface, enum, or class`);
31-
}
32-
33-
function buildModuleTypes(parent: Module, types: readonly Type[]): ModuleTypes {
34-
return types.map(
35-
(type: Type): ModuleType => {
36-
if (type.isInterfaceType()) {
37-
return new Interface(parent, type);
38-
} else if (type.isClassType()) {
39-
return new GoClass(parent, type);
40-
} else if (type.isEnumType()) {
41-
return new Enum(parent, type);
42-
}
43-
return unknownType(type);
44-
},
45-
);
46-
}
47-
48-
function findTypeInTree(module: Module, fqn: string): ModuleType | undefined {
49-
const result = module.types.find((t) => t.type.fqn === fqn);
50-
51-
if (result) {
52-
return result;
53-
} else if (module.hasSubmodules()) {
54-
return module.submodules.reduce((accum: ModuleType | undefined, sm) => {
55-
return accum || findTypeInTree(sm, fqn);
56-
}, undefined);
57-
}
58-
59-
return undefined;
60-
}
61-
7+
// JSII golang runtime module name
628
const JSII_MODULE_NAME = 'github.com/aws-cdk/jsii/jsii';
63-
export abstract class ModuleFile {
64-
public constructor(public readonly file: string) {}
65-
public open(code: CodeMaker): void {
66-
code.openFile(this.file);
67-
}
689

69-
public close(code: CodeMaker): void {
70-
code.closeFile(this.file);
71-
}
72-
}
10+
export type ModuleType = Interface | Enum | GoClass;
11+
type ModuleTypes = ModuleType[];
7312

74-
export class RootModule extends ModuleFile implements Module {
75-
private readonly assembly: Assembly;
76-
public readonly packageName: string;
77-
public readonly moduleName: string;
13+
/*
14+
* Module represents a single `.go` source file within a package. This can be the root package file or a submodule
15+
*/
16+
export abstract class Module {
17+
public readonly root: Module;
7818
public readonly file: string;
79-
public readonly filePath: string;
80-
public readonly root: RootModule;
81-
82-
public constructor(assembly: Assembly) {
83-
const packageName = assembly.name
84-
.replace('@', '')
85-
.replace(/[^a-z0-9_.]/gi, '');
86-
const filePath = join(...packageName.split('.'));
87-
const file = `${filePath}.go`;
88-
super(file);
89-
90-
this.assembly = assembly;
91-
this.root = this;
92-
this.packageName = packageName;
93-
// moduleName == packageName for root;
94-
this.moduleName = packageName;
95-
this.filePath = filePath;
96-
this.file = file;
97-
}
19+
public readonly submodules: Submodule[];
20+
public readonly types: ModuleTypes;
21+
// public readonly dependencies: Module[];
9822

99-
public get types(): ModuleTypes {
100-
return buildModuleTypes(this, Object.values(this.assembly.types));
101-
}
23+
public constructor(
24+
private readonly typeSpec: readonly Type[],
25+
private readonly submoduleSpec: readonly JsiiSubmodule[],
26+
public readonly moduleName: string,
27+
public readonly filePath: string,
28+
// If no root is provided, this module is the root
29+
root?: Module,
30+
) {
31+
this.file = `${filePath}.go`;
32+
this.root = root || this;
33+
this.submodules = this.submoduleSpec.map(
34+
(sm) => new Submodule(this.root, this, sm),
35+
);
10236

103-
public get submodules(): Submodule[] {
104-
return buildSubmodules(this, this, this.assembly.submodules);
37+
this.types = this.typeSpec.map(
38+
(type: Type): ModuleType => {
39+
if (type.isInterfaceType()) {
40+
return new Interface(this, type);
41+
} else if (type.isClassType()) {
42+
return new GoClass(this, type);
43+
} else if (type.isEnumType()) {
44+
return new Enum(this, type);
45+
}
46+
throw new Error(
47+
`Type: ${type.name} with kind ${type.kind} is not a supported type`,
48+
);
49+
},
50+
);
10551
}
10652

107-
public get dependencies(): Set<Module> {
108-
return new Set(
109-
this.types
110-
.reduce(
111-
(accum: Module[], t: ModuleType) => [...accum, ...t.dependencies],
112-
[],
113-
)
114-
.filter((mod) => mod.packageName !== this.packageName),
115-
);
53+
/*
54+
* Modules that types within this module reference
55+
*/
56+
public get dependencies(): Module[] {
57+
return flatMap(
58+
this.types,
59+
(t: ModuleType): Module[] => t.dependencies,
60+
).filter((mod) => mod.moduleName !== this.moduleName);
11661
}
11762

118-
public hasSubmodules(): boolean {
119-
return Boolean(this.submodules.length);
63+
/*
64+
* The module names of this modules dependencies. Used for import statements
65+
*/
66+
public get dependencyImports(): Set<string> {
67+
return new Set(this.dependencies.map((mod) => mod.moduleName));
12068
}
12169

70+
/*
71+
* Search for a type with a `fqn` within this. Searches all Children modules as well.
72+
*/
12273
public findType(fqn: string): ModuleType | undefined {
12374
return findTypeInTree(this, fqn);
12475
}
12576

126-
public emit(code: CodeMaker): void {
127-
this.open(code);
128-
code.line(`package ${this.packageName}`);
77+
public emit(context: EmitContext): void {
78+
const { code } = context;
79+
code.openFile(this.file);
80+
this.emitHeader(code);
81+
this.emitImports(code);
82+
this.emitTypes(code);
83+
code.closeFile(this.file);
84+
85+
this.emitSubmodules(context);
86+
}
87+
88+
private emitHeader(code: CodeMaker) {
89+
code.line(`package ${this.moduleName}`);
12990
code.line();
91+
}
13092

131-
code.line('import (');
132-
code.indent();
93+
private emitImports(code: CodeMaker) {
94+
code.open('import (');
13395
code.line(`"${JSII_MODULE_NAME}"`);
134-
if (this.dependencies.size > 0) {
135-
this.dependencies.forEach((mod) => {
136-
if (mod.packageName !== this.packageName) {
137-
code.line(`"${mod.packageName}"`);
138-
}
139-
});
140-
}
141-
code.unindent();
142-
code.line(')');
96+
this.dependencyImports.forEach((modName) => {
97+
// If the module is the same as the current one being written, don't emit an import statement
98+
if (modName !== this.moduleName) {
99+
code.line(`"${modName}"`);
100+
}
101+
});
102+
code.close(')');
143103
code.line();
144-
145-
this.emitTypes(code);
146-
this.close(code);
147-
148-
this.emitSubmodules(code);
149104
}
150105

151-
public emitTypes(code: CodeMaker) {
152-
Object.values(this.types).forEach((type) => {
153-
type.emit(code);
106+
public emitSubmodules(context: EmitContext) {
107+
this.submodules.forEach((submodule) => {
108+
submodule.emit(context);
154109
});
155110
}
156111

157-
public emitSubmodules(code: CodeMaker) {
158-
this.submodules.forEach((submodule) => {
159-
submodule.emit(code);
112+
private emitTypes(code: CodeMaker) {
113+
this.types.forEach((type) => {
114+
type.emit(code);
160115
});
161116
}
162117
}
163118

164-
export class Submodule extends ModuleFile implements Module {
165-
private readonly assembly: JsiiSubmodule;
166-
public readonly packageName: string;
167-
public readonly moduleName: string;
168-
public readonly file: string;
169-
public readonly filePath: string;
119+
export class Submodule extends Module {
170120
public readonly parent: Module;
171-
public readonly root: RootModule;
172121

173-
public constructor(
174-
root: RootModule,
175-
parent: Module,
176-
submodule: JsiiSubmodule,
177-
) {
178-
const moduleName = submodule.name
179-
.replace('@', '')
180-
.replace(/[^a-z0-9]/gi, '');
181-
const packageName = moduleName;
122+
public constructor(root: Module, parent: Module, assembly: JsiiSubmodule) {
123+
const moduleName = goModuleName(assembly.name);
182124
const filePath = `${parent.filePath}/${moduleName}`;
183-
const file = `${filePath}.go`;
184-
super(file);
185-
186-
this.assembly = submodule;
187-
this.root = root;
188-
this.parent = parent;
189-
this.packageName = packageName;
190-
this.moduleName = moduleName;
191-
this.filePath = filePath;
192-
this.file = file;
193-
}
194-
195-
public get types(): ModuleTypes {
196-
return buildModuleTypes(this, this.assembly.types);
197-
}
198-
199-
public get submodules(): Submodule[] {
200-
return buildSubmodules(this.root, this, this.assembly.submodules);
201-
}
202-
203-
public hasSubmodules(): boolean {
204-
return Boolean(this.submodules.length);
205-
}
206125

207-
public get dependencies(): Set<Module> {
208-
return new Set(
209-
this.types
210-
.reduce(
211-
(accum: Module[], t: ModuleType) => [...accum, ...t.dependencies],
212-
[],
213-
)
214-
.filter((mod) => mod.packageName !== this.packageName),
215-
);
216-
}
217-
218-
public emit(code: CodeMaker): void {
219-
this.open(code);
220-
code.line(`package ${this.packageName}`);
221-
code.line();
222-
223-
code.line('import (');
224-
code.indent();
225-
code.line(`"${JSII_MODULE_NAME}"`);
226-
if (this.dependencies.size > 0) {
227-
this.dependencies.forEach((mod) => {
228-
if (mod.packageName !== this.packageName) {
229-
code.line(`"${mod.packageName}"`);
230-
}
231-
});
232-
}
233-
code.unindent();
234-
code.line(')');
235-
code.line();
236-
237-
this.emitTypes(code);
238-
this.close(code);
126+
super(assembly.types, assembly.submodules, moduleName, filePath, root);
239127

240-
this.emitSubmodules(code);
241-
}
242-
243-
public emitSubmodules(code: CodeMaker) {
244-
this.submodules.forEach((submodule) => {
245-
submodule.emit(code);
246-
});
247-
}
248-
249-
private emitTypes(code: CodeMaker): void {
250-
this.types.forEach((type) => {
251-
type.emit(code);
252-
});
128+
this.parent = parent;
253129
}
254130
}

packages/jsii-pacmak/lib/targets/golang/package-context.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)