Skip to content

Commit 5bf6820

Browse files
abluchetsoyuka
authored andcommitted
Add typescript interface generator
1 parent b27ef67 commit 5bf6820

File tree

7 files changed

+174
-13
lines changed

7 files changed

+174
-13
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"tmp": "^0.0.31"
3131
},
3232
"dependencies": {
33-
"api-doc-parser": "^0.1.1",
33+
"api-doc-parser": "^0.2",
3434
"babel-runtime": "^6.23.0",
3535
"chalk": "^2.1.0",
3636
"commander": "^2.9.0",

src/generators.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ReactCrudGenerator from './generators/ReactCrudGenerator';
2+
import TypescriptInterfaceGenerator from './generators/TypescriptInterfaceGenerator';
23

34
function wrap (cl) {
45
return (prefix) => new cl(prefix)
@@ -7,7 +8,9 @@ function wrap (cl) {
78
function generators (generator = 'react') {
89
switch (generator) {
910
case 'react':
10-
return wrap(ReactCrudGenerator)
11+
return wrap(ReactCrudGenerator);
12+
case 'typescript':
13+
return wrap(TypescriptInterfaceGenerator);
1114
}
1215
}
1316

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import mkdirp from 'mkdirp';
2+
import handlebars from 'handlebars';
3+
import fs from 'fs';
4+
5+
export default class TypescriptInterfaceGenerator {
6+
templates = {};
7+
8+
constructor() {
9+
const templatePath = `${__dirname}/../../templates/typescript`;
10+
this.template = handlebars.compile(fs.readFileSync(`${templatePath}/interface.ts`).toString())
11+
}
12+
13+
help() {
14+
}
15+
16+
generate(api, resource, dir) {
17+
const fields = this.parseFields(resource)
18+
const name = resource.title
19+
let dest = `${dir}/interfaces`
20+
21+
try {
22+
mkdirp.sync(dest);
23+
} catch(e) {
24+
// nothing
25+
}
26+
27+
dest += `/${name.toLowerCase()}.ts`;
28+
29+
fs.writeFileSync(dest, this.template({fields, name}));
30+
}
31+
32+
getType(field) {
33+
if (field.reference) {
34+
return field.reference.title;
35+
}
36+
37+
switch (field.range) {
38+
case 'http://www.w3.org/2001/XMLSchema#integer':
39+
case 'http://www.w3.org/2001/XMLSchema#decimal':
40+
return 'number';
41+
case 'http://www.w3.org/2001/XMLSchema#boolean':
42+
return 'bool';
43+
case 'http://www.w3.org/2001/XMLSchema#date':
44+
case 'http://www.w3.org/2001/XMLSchema#dateTime':
45+
case 'http://www.w3.org/2001/XMLSchema#time':
46+
return 'Date';
47+
case 'http://www.w3.org/2001/XMLSchema#string':
48+
return 'string';
49+
}
50+
51+
return 'any';
52+
}
53+
54+
getDescription(field) {
55+
return field.description ? field.description.replace(/"/g, "'") : ''
56+
}
57+
58+
parseFields(resource) {
59+
const fields = {}
60+
61+
for (let field of resource.writableFields) {
62+
fields[field.name] = {
63+
notrequired: !field.required,
64+
name: field.name,
65+
type: this.getType(field),
66+
description: this.getDescription(field),
67+
readonly: false
68+
}
69+
}
70+
71+
for (let field of resource.readableFields) {
72+
if (fields[field.name] !== undefined) {
73+
continue;
74+
}
75+
76+
fields[field.name] = {
77+
notrequired: !field.required,
78+
name: field.name,
79+
type: this.getType(field),
80+
description: this.getDescription(field),
81+
readonly: true
82+
}
83+
}
84+
85+
return Object.keys(fields).map((e) => fields[e]);
86+
}
87+
88+
// createFile(template, dest, context) {
89+
// }
90+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import Api from 'api-doc-parser/lib/Api';
2+
import Resource from 'api-doc-parser/lib/Resource';
3+
import Field from 'api-doc-parser/lib/Field';
4+
import fs from 'fs';
5+
import tmp from 'tmp';
6+
import TypescriptInterfaceGenerator from './TypescriptInterfaceGenerator';
7+
8+
9+
test('Generate a typescript interface', () => {
10+
const generator = new TypescriptInterfaceGenerator('hydra:');
11+
const tmpobj = tmp.dirSync({unsafeCleanup: true});
12+
13+
const resource = new Resource('abc', 'http://example.com/foos', {
14+
id: 'foo',
15+
title: 'Foo',
16+
readableFields: [new Field('bar', {
17+
id: 'http://schema.org/url',
18+
range: 'http://www.w3.org/2001/XMLSchema#string',
19+
reference: null,
20+
required: true,
21+
description: 'An URL'
22+
})],
23+
writableFields: [new Field('foo', {
24+
id: 'http://schema.org/url',
25+
range: 'http://www.w3.org/2001/XMLSchema#datetime',
26+
reference: null,
27+
required: true,
28+
description: 'An URL'
29+
}), new Field('foobar', {
30+
id: 'http://schema.org/url',
31+
range: undefined,
32+
reference: new Resource('foobar', 'http://example.com/FooBar', {title: 'FooBar'}),
33+
required: false
34+
})]
35+
});
36+
const api = new Api('http://example.com', {
37+
title: 'My API',
38+
resources: [resource]
39+
});
40+
generator.generate(api, resource, tmpobj.name);
41+
42+
expect(fs.existsSync(tmpobj.name+'/interfaces/foo.ts'), true);
43+
44+
const res = `interface Foo {
45+
'@id'?: string;
46+
id: string;
47+
foo: any;
48+
foobar?: FooBar;
49+
readonly bar: string;
50+
}
51+
`
52+
expect(fs.readFileSync(tmpobj.name+'/interfaces/foo.ts').toString()).toEqual(res)
53+
54+
tmpobj.removeCallback();
55+
});

src/index.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,23 @@ const generator = generators(program.generator)(program.hydraPrefix)
2323
const resourceToGenerate = program.resource ? program.resource.toLowerCase() : null;
2424

2525
parseHydraDocumentation(program.args[0]).then(api => {
26-
for (let resource of api.resources) {
27-
const nameLc = resource.name.toLowerCase();
28-
const titleLc = resource.title.toLowerCase();
29-
30-
if (null === resourceToGenerate || nameLc === resourceToGenerate || titleLc === resourceToGenerate) {
31-
generator.generate(api, resource, program.args[1]);
32-
generator.help(resource)
33-
}
26+
for (let resource of api.api.resources) {
27+
const nameLc = resource.name.toLowerCase();
28+
const titleLc = resource.title.toLowerCase();
29+
30+
if (null === resourceToGenerate || nameLc === resourceToGenerate || titleLc === resourceToGenerate) {
31+
generator.generate(api, resource, program.args[1]);
32+
generator.help(resource)
3433
}
34+
}
35+
36+
if ('entrypoint' in generator) {
3537
generator.entrypoint(program.args[0], program.args[1]);
38+
}
39+
40+
if ('utils' in generator) {
3641
generator.utils(program.args[1]);
42+
}
3743
}).catch((e) => {
3844
console.log(e);
3945
});

templates/typescript/interface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface {{ name }} {
2+
'@id'?: string;
3+
id: string;
4+
{{#each fields}}
5+
{{#if readonly}} readonly{{/if}} {{{ name }}}{{#if notrequired}}?{{/if}}: {{{ type }}};
6+
{{/each}}
7+
}

yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ anymatch@^1.3.0:
8484
arrify "^1.0.0"
8585
micromatch "^2.1.5"
8686

87-
api-doc-parser@^0.1.1:
88-
version "0.1.5"
89-
resolved "https://registry.yarnpkg.com/api-doc-parser/-/api-doc-parser-0.1.5.tgz#719b9af21ab599995549bca63a8f10514cf26aaa"
87+
api-doc-parser@^0.2:
88+
version "0.2.1"
89+
resolved "https://registry.yarnpkg.com/api-doc-parser/-/api-doc-parser-0.2.1.tgz#1fa6fd25ecf8d3a005be7de3095f0ecb9c15b4cc"
9090
dependencies:
9191
babel-runtime "^6.23.0"
9292
jsonld "^0.4.11"

0 commit comments

Comments
 (0)