Skip to content

Commit b9555f7

Browse files
4rthemalanpoulain
andauthored
fix(typescript): identifiers containing dashes (#315)
Co-authored-by: Alan Poulain <[email protected]>
1 parent 4a7571e commit b9555f7

File tree

5 files changed

+82
-13
lines changed

5 files changed

+82
-13
lines changed

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,20 @@
3737
"jest-light-runner": "^0.3.0",
3838
"lint-staged": "^13.0.0",
3939
"start-server-and-test": "^1.14.0",
40-
"tmp": "^0.2.1"
40+
"tmp": "^0.2.0"
4141
},
4242
"dependencies": {
4343
"@api-platform/api-doc-parser": "^0.15.0",
4444
"@babel/runtime": "^7.0.0",
4545
"chalk": "^5.0.0",
4646
"commander": "^9.4.0",
47-
"handlebars": "^4.0.12",
47+
"esutils": "^2.0.0",
48+
"handlebars": "^4.0.0",
4849
"handlebars-helpers": "^0.10.0",
4950
"isomorphic-fetch": "^3.0.0",
50-
"mkdirp": "^1.0.4",
51+
"mkdirp": "^1.0.0",
5152
"prettier": "^2.7.0",
52-
"sprintf-js": "^1.1.1"
53+
"sprintf-js": "^1.1.0"
5354
},
5455
"scripts": {
5556
"prepare": "husky install",

src/generators/TypescriptInterfaceGenerator.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
import handlebars from "handlebars";
2+
import { keyword } from "esutils";
13
import BaseGenerator from "./BaseGenerator.js";
24

35
export default class TypescriptInterfaceGenerator extends BaseGenerator {
46
constructor(params) {
57
super(params);
68

79
this.registerTemplates(`typescript/`, ["interface.ts"]);
10+
11+
handlebars.registerHelper("isIdentifier", (name) =>
12+
keyword.isIdentifierES5(name)
13+
);
814
}
915

1016
help(resource) {
@@ -18,14 +24,16 @@ export default class TypescriptInterfaceGenerator extends BaseGenerator {
1824
const dest = `${dir}/interfaces`;
1925
const { fields, imports } = this.parseFields(resource);
2026

27+
const normalizeTypeName = (name) => name.replace(/-/g, "_");
28+
2129
this.createDir(dest, false);
2230
this.createFile(
2331
"interface.ts",
2432
`${dest}/${resource.title.toLowerCase()}.ts`,
2533
{
2634
fields,
2735
imports,
28-
name: resource.title,
36+
name: normalizeTypeName(resource.title),
2937
}
3038
);
3139
}

src/generators/TypescriptInterfaceGenerator.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,61 @@ test("Generate a typescript interface with an explicit id field in the readableF
173173

174174
tmpobj.removeCallback();
175175
});
176+
177+
test("Generate a typescript interface with invalid JS identifiers for fields and title", () => {
178+
const generator = new TypescriptInterfaceGenerator({
179+
templateDirectory: `${dirname}/../../templates`,
180+
});
181+
const tmpobj = tmp.dirSync({ unsafeCleanup: true });
182+
183+
const resource = new Resource("abc", "http://example.com/foos", {
184+
id: "foo",
185+
title: "Foo-foo",
186+
readableFields: [
187+
new Field("bar-bar", {
188+
id: "http://schema.org/url",
189+
range: "http://www.w3.org/2001/XMLSchema#string",
190+
reference: null,
191+
required: true,
192+
description: "An URL",
193+
}),
194+
new Field("id", {
195+
id: "http://schema.org/url",
196+
range: "http://www.w3.org/2001/XMLSchema#string",
197+
reference: null,
198+
required: false,
199+
description: "Id",
200+
}),
201+
],
202+
writableFields: [
203+
new Field("foo-foo", {
204+
id: "http://schema.org/url",
205+
range: "http://www.w3.org/2001/XMLSchema#datetime",
206+
reference: null,
207+
required: true,
208+
description: "An URL",
209+
}),
210+
],
211+
});
212+
const api = new Api("http://example.com", {
213+
entrypoint: "http://example.com:8080",
214+
title: "My API",
215+
resources: [resource],
216+
});
217+
generator.generate(api, resource, tmpobj.name);
218+
219+
expect(fs.existsSync(tmpobj.name + "/interfaces/foo-foo.ts")).toBe(true);
220+
221+
const res = `export interface Foo_foo {
222+
"@id"?: string;
223+
"foo-foo": any;
224+
readonly "bar-bar": string;
225+
readonly id?: string;
226+
}
227+
`;
228+
expect(
229+
fs.readFileSync(tmpobj.name + "/interfaces/foo-foo.ts").toString()
230+
).toEqual(res);
231+
232+
tmpobj.removeCallback();
233+
});

templates/typescript/interface.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export interface {{{name}}} {
22
'@id'?: string;
3-
{{#each fields}}
4-
{{#if readonly}} readonly{{/if}} {{{name}}}{{#if notrequired}}?{{/if}}: {{{type}}};
5-
{{/each}}
3+
{{#each fields}}
4+
{{#if readonly}} readonly{{/if}} {{#unless (isIdentifier name)}}"{{/unless}}
5+
{{~ name ~}}
6+
{{#unless (isIdentifier name)}}"{{/unless}}{{#if notrequired}}?{{/if}}: {{{type}}};
7+
{{/each}}
68
}

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2809,7 +2809,7 @@ estraverse@^5.1.0, estraverse@^5.2.0:
28092809
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
28102810
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
28112811

2812-
esutils@^2.0.2:
2812+
esutils@^2.0.0, esutils@^2.0.2:
28132813
version "2.0.3"
28142814
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
28152815
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
@@ -3283,7 +3283,7 @@ handlebars-utils@^1.0.2, handlebars-utils@^1.0.4, handlebars-utils@^1.0.6:
32833283
kind-of "^6.0.0"
32843284
typeof-article "^0.1.1"
32853285

3286-
handlebars@^4.0.11, handlebars@^4.0.12:
3286+
handlebars@^4.0.0, handlebars@^4.0.11:
32873287
version "4.7.7"
32883288
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
32893289
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
@@ -4608,7 +4608,7 @@ mixin-deep@^1.2.0:
46084608
for-in "^1.0.2"
46094609
is-extendable "^1.0.1"
46104610

4611-
mkdirp@^1.0.4:
4611+
mkdirp@^1.0.0:
46124612
version "1.0.4"
46134613
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
46144614
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -5454,7 +5454,7 @@ [email protected]:
54545454
dependencies:
54555455
through "2"
54565456

5457-
sprintf-js@^1.1.1:
5457+
sprintf-js@^1.1.0:
54585458
version "1.1.2"
54595459
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
54605460
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
@@ -5683,7 +5683,7 @@ time-stamp@^1.0.1:
56835683
resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
56845684
integrity sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==
56855685

5686-
tmp@^0.2.1:
5686+
tmp@^0.2.0:
56875687
version "0.2.1"
56885688
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
56895689
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==

0 commit comments

Comments
 (0)