Skip to content

Commit c56dcff

Browse files
authored
Merge pull request #1642 from pmcelhaney/copilot/change-objects-to-maps
Convert internal plain objects to Maps
2 parents 414c82e + 499d66b commit c56dcff

File tree

4 files changed

+66
-62
lines changed

4 files changed

+66
-62
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"counterfact": patch
3+
---
4+
5+
Refactor internal plain objects to Maps where appropriate:
6+
- `Directory.directories` and `Directory.files` in `module-tree.ts` are now `Map<string, Directory>` and `Map<string, File>`
7+
- `ParameterTypes` inner types in `dispatcher.ts` are now `Map<string, string>`
8+
- `castParameters` in `registry.ts` now accepts `Map<string, string>` for parameter types

src/server/dispatcher.ts

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,12 @@ function parseCookies(cookieHeader: string): Record<string, string> {
4747
}
4848

4949
interface ParameterTypes {
50-
body: {
51-
[key: string]: string;
52-
};
53-
cookie: {
54-
[key: string]: string;
55-
};
56-
formData: {
57-
[key: string]: string;
58-
};
59-
header: {
60-
[key: string]: string;
61-
};
62-
path: {
63-
[key: string]: string;
64-
};
65-
query: {
66-
[key: string]: string;
67-
};
50+
body: Map<string, string>;
51+
cookie: Map<string, string>;
52+
formData: Map<string, string>;
53+
header: Map<string, string>;
54+
path: Map<string, string>;
55+
query: Map<string, string>;
6856
}
6957

7058
export interface OpenApiDocument {
@@ -124,12 +112,12 @@ export class Dispatcher {
124112
parameters: OpenApiParameters[] | undefined,
125113
): ParameterTypes {
126114
const types: ParameterTypes = {
127-
body: {},
128-
cookie: {},
129-
formData: {},
130-
header: {},
131-
path: {},
132-
query: {},
115+
body: new Map(),
116+
cookie: new Map(),
117+
formData: new Map(),
118+
header: new Map(),
119+
path: new Map(),
120+
query: new Map(),
133121
};
134122

135123
if (!parameters) {
@@ -140,8 +128,10 @@ export class Dispatcher {
140128
const type = parameter?.type;
141129

142130
if (type !== undefined) {
143-
types[parameter.in][parameter.name] =
144-
type === "integer" ? "number" : type;
131+
types[parameter.in].set(
132+
parameter.name,
133+
type === "integer" ? "number" : type,
134+
);
145135
}
146136
}
147137

src/server/module-tree.ts

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ interface File {
1313
}
1414

1515
interface Directory {
16-
directories: { [key: string]: Directory };
17-
files: { [key: string]: File };
16+
directories: Map<string, Directory>;
17+
files: Map<string, File>;
1818
isWildcard: boolean;
1919
name: string;
2020
rawName: string;
@@ -34,8 +34,8 @@ function isDirectory(test: Directory | undefined): test is Directory {
3434

3535
export class ModuleTree {
3636
public readonly root: Directory = {
37-
directories: {},
38-
files: {},
37+
directories: new Map(),
38+
files: new Map(),
3939
isWildcard: false,
4040
name: "",
4141
rawName: "",
@@ -52,20 +52,25 @@ export class ModuleTree {
5252
return directory;
5353
}
5454

55-
const isNewDirectory =
56-
directory.directories[segment.toLowerCase()] === undefined;
55+
const isNewDirectory = !directory.directories.has(segment.toLowerCase());
5756

58-
const nextDirectory = (directory.directories[segment.toLowerCase()] ??= {
59-
directories: {},
60-
files: {},
61-
isWildcard: segment.startsWith("{"),
62-
name: segment.replace(/^\{(?<name>.*)\}$/u, "$<name>"),
63-
rawName: segment,
64-
});
57+
if (isNewDirectory) {
58+
directory.directories.set(segment.toLowerCase(), {
59+
directories: new Map(),
60+
files: new Map(),
61+
isWildcard: segment.startsWith("{"),
62+
name: segment.replace(/^\{(?<name>.*)\}$/u, "$<name>"),
63+
rawName: segment,
64+
});
65+
}
66+
67+
const nextDirectory = directory.directories.get(
68+
segment.toLowerCase(),
69+
) as Directory;
6570

6671
if (isNewDirectory && segment.startsWith("{")) {
67-
const ambiguousWildcardDirectories = Object.values(
68-
directory.directories,
72+
const ambiguousWildcardDirectories = Array.from(
73+
directory.directories.values(),
6974
).filter((subdirectory) => subdirectory.isWildcard);
7075

7176
if (ambiguousWildcardDirectories.length > 1) {
@@ -97,16 +102,16 @@ export class ModuleTree {
97102
);
98103
}
99104

100-
targetDirectory.files[filename] = {
105+
targetDirectory.files.set(filename, {
101106
isWildcard: filename.startsWith("{"),
102107
module,
103108
name: filename.replace(/^\{(?<name>.*)\}$/u, "$<name>"),
104109
rawName: filename,
105-
};
110+
});
106111

107112
if (filename.startsWith("{")) {
108-
const ambiguousWildcardFiles = Object.values(
109-
targetDirectory.files,
113+
const ambiguousWildcardFiles = Array.from(
114+
targetDirectory.files.values(),
110115
).filter((file) => file.isWildcard);
111116

112117
if (ambiguousWildcardFiles.length > 1) {
@@ -136,13 +141,13 @@ export class ModuleTree {
136141
}
137142

138143
if (remainingSegments.length === 0) {
139-
delete directory.files[segment.toLowerCase()];
144+
directory.files.delete(segment.toLowerCase());
140145

141146
return;
142147
}
143148

144149
this.removeModuleFromDirectory(
145-
directory.directories[segment.toLowerCase()],
150+
directory.directories.get(segment.toLowerCase()),
146151
remainingSegments,
147152
);
148153
}
@@ -165,16 +170,17 @@ export class ModuleTree {
165170
method: string,
166171
): Match | undefined {
167172
function normalizedSegment(segment: string, directory: Directory) {
168-
for (const file in directory.files) {
173+
for (const file of directory.files.keys()) {
169174
if (file.toLowerCase() === segment.toLowerCase()) {
170175
return file;
171176
}
172177
}
173178
return "";
174179
}
175180

176-
const exactMatchFile =
177-
directory.files[normalizedSegment(segment, directory)];
181+
const exactMatchFile = directory.files.get(
182+
normalizedSegment(segment, directory),
183+
);
178184

179185
// If the URL segment literally matches a file key (e.g., requesting "/{x}"
180186
// as a literal URL value), exactMatchFile may be a wildcard file. In that
@@ -187,7 +193,7 @@ export class ModuleTree {
187193
};
188194
}
189195

190-
const wildcardFiles = Object.values(directory.files).filter(
196+
const wildcardFiles = Array.from(directory.files.values()).filter(
191197
(file) => file.isWildcard && this.fileModuleDefined(file, method),
192198
);
193199

@@ -265,7 +271,7 @@ export class ModuleTree {
265271
);
266272
}
267273

268-
const exactMatch = directory.directories[segment.toLowerCase()];
274+
const exactMatch = directory.directories.get(segment.toLowerCase());
269275

270276
if (isDirectory(exactMatch)) {
271277
return this.matchWithinDirectory(
@@ -277,9 +283,9 @@ export class ModuleTree {
277283
);
278284
}
279285

280-
const wildcardDirectories = Object.values(directory.directories).filter(
281-
(subdirectory) => subdirectory.isWildcard,
282-
);
286+
const wildcardDirectories = Array.from(
287+
directory.directories.values(),
288+
).filter((subdirectory) => subdirectory.isWildcard);
283289

284290
const wildcardMatches: Match[] = [];
285291

@@ -323,11 +329,11 @@ export class ModuleTree {
323329
const routes: Route[] = [];
324330

325331
function traverse(directory: Directory, path: string) {
326-
Object.values(directory.directories).forEach((subdirectory) => {
332+
directory.directories.forEach((subdirectory) => {
327333
traverse(subdirectory, `${path}/${subdirectory.rawName}`);
328334
});
329335

330-
Object.values(directory.files).forEach((file) => {
336+
directory.files.forEach((file) => {
331337
const methods: [string, string][] = Object.entries(file.module).map(
332338
([method, implementation]) => [method, String(implementation)],
333339
);

src/server/registry.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ function castParameter(value: string | number | boolean, type: string) {
114114

115115
function castParameters(
116116
parameters: { [key: string]: string | number | boolean } = {},
117-
parameterTypes: { [key: string]: string } = {},
117+
parameterTypes: Map<string, string> = new Map(),
118118
) {
119119
const copy: { [key: string]: boolean | number | string } = {};
120120

121121
Object.entries(parameters).forEach(([key, value]) => {
122-
copy[key] = castParameter(value, parameterTypes?.[key] ?? "string");
122+
copy[key] = castParameter(value, parameterTypes.get(key) ?? "string");
123123
});
124124

125125
return copy;
@@ -184,9 +184,9 @@ export class Registry {
184184
httpRequestMethod: HttpMethods,
185185
url: string,
186186
parameterTypes: {
187-
header?: { [key: string]: string };
188-
path?: { [key: string]: string };
189-
query?: { [key: string]: string };
187+
header?: Map<string, string>;
188+
path?: Map<string, string>;
189+
query?: Map<string, string>;
190190
} = {},
191191
) {
192192
const handler = this.handler(url, httpRequestMethod);

0 commit comments

Comments
 (0)