Skip to content

Commit da8dfb8

Browse files
committed
feat: new argument to use a custom external generator
1 parent 709e28f commit da8dfb8

File tree

2 files changed

+133
-115
lines changed

2 files changed

+133
-115
lines changed

src/generators.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fs from "fs";
12
import NextGenerator from "./generators/NextGenerator";
23
import NuxtGenerator from "./generators/NuxtGenerator";
34
import ReactGenerator from "./generators/ReactGenerator";
@@ -12,7 +13,12 @@ function wrap(cl) {
1213
new cl({ hydraPrefix, templateDirectory });
1314
}
1415

15-
export default function generators(generator = "react") {
16+
export default async function generators(generator = "react") {
17+
if (fs.existsSync(generator)) {
18+
const gen = await import(generator);
19+
return wrap(gen.default);
20+
}
21+
1622
switch (generator) {
1723
case "next":
1824
return wrap(NextGenerator);

src/index.js

Lines changed: 126 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -8,129 +8,141 @@ import parseOpenApi3Documentation from "@api-platform/api-doc-parser/lib/openapi
88
import { version } from "../package.json";
99
import generators from "./generators";
1010

11-
program
12-
.version(version)
13-
.description(
14-
"Generate apps built with Next, Nuxt, Quasar, React, React Native, Vue or Vuetify for any API documented using Hydra or OpenAPI"
15-
)
16-
.usage("entrypoint outputDirectory")
17-
.option(
18-
"-r, --resource [resourceName]",
19-
"Generate CRUD for the given resource"
20-
)
21-
.option(
22-
"-p, --hydra-prefix [hydraPrefix]",
23-
"The hydra prefix used by the API",
24-
"hydra:"
25-
)
26-
.option("--username [username]", "Username for basic auth (Hydra only)")
27-
.option("--password [password]", "Password for basic auth (Hydra only)")
28-
.option("--bearer [bearer]", "Token for bearer auth (Hydra only)")
29-
.option(
30-
"-g, --generator [generator]",
31-
'The generator to use, one of "next", "nuxt", "quasar", "react", "react-native", "typescript", "vue", "vuetify"',
32-
"next"
33-
)
34-
.option(
35-
"-t, --template-directory [templateDirectory]",
36-
"The templates directory base to use. Final directory will be ${templateDirectory}/${generator}",
37-
`${__dirname}/../templates/`
38-
)
39-
.option(
40-
"-f, --format [hydra|openapi3|openapi2]",
41-
'"hydra", "openapi3" or "openapi2"',
42-
"hydra"
43-
)
44-
.option(
45-
"-s, --server-path [serverPath]",
46-
"Path to express server file to allow route dynamic addition (Next.js generator only)"
47-
)
48-
.parse(process.argv);
11+
async function main() {
12+
program
13+
.version(version)
14+
.description(
15+
"Generate apps built with Next, Nuxt, Quasar, React, React Native, Vue or Vuetify for any API documented using Hydra or OpenAPI"
16+
)
17+
.usage("entrypoint outputDirectory")
18+
.option(
19+
"-r, --resource [resourceName]",
20+
"Generate CRUD for the given resource"
21+
)
22+
.option(
23+
"-p, --hydra-prefix [hydraPrefix]",
24+
"The hydra prefix used by the API",
25+
"hydra:"
26+
)
27+
.option("--username [username]", "Username for basic auth (Hydra only)")
28+
.option("--password [password]", "Password for basic auth (Hydra only)")
29+
.option("--bearer [bearer]", "Token for bearer auth (Hydra only)")
30+
.option(
31+
"-g, --generator [generator]",
32+
'The generator to use, one of "next", "nuxt", "quasar", "react", "react-native", "typescript", "vue", "vuetify"',
33+
"next"
34+
)
35+
.option(
36+
"--custom-generator [customGenerator]",
37+
"A node module to use as a custom generator."
38+
)
39+
.option(
40+
"-t, --template-directory [templateDirectory]",
41+
"The templates directory base to use. Final directory will be ${templateDirectory}/${generator}",
42+
`${__dirname}/../templates/`
43+
)
44+
.option(
45+
"-f, --format [hydra|openapi3|openapi2]",
46+
'"hydra", "openapi3" or "openapi2"',
47+
"hydra"
48+
)
49+
.option(
50+
"-s, --server-path [serverPath]",
51+
"Path to express server file to allow route dynamic addition (Next.js generator only)"
52+
)
53+
.parse(process.argv);
4954

50-
if (
51-
2 !== program.args.length &&
52-
(!process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT ||
53-
!process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT)
54-
) {
55-
program.help();
56-
}
55+
if (
56+
2 !== program.args.length &&
57+
(!process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT ||
58+
!process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT)
59+
) {
60+
program.help();
61+
}
5762

58-
const options = program.opts();
63+
const options = program.opts();
5964

60-
const entrypoint =
61-
program.args[0] || process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT;
62-
const outputDirectory =
63-
program.args[1] || process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT;
65+
const entrypoint =
66+
program.args[0] || process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT;
67+
const outputDirectory =
68+
program.args[1] || process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT;
6469

65-
const entrypointWithSlash = entrypoint.endsWith("/")
66-
? entrypoint
67-
: entrypoint + "/";
70+
const entrypointWithSlash = entrypoint.endsWith("/")
71+
? entrypoint
72+
: entrypoint + "/";
6873

69-
const generator = generators(options.generator)({
70-
hydraPrefix: options.hydraPrefix,
71-
templateDirectory: options.templateDirectory,
72-
});
73-
const resourceToGenerate = options.resource
74-
? options.resource.toLowerCase()
75-
: null;
76-
const serverPath = options.serverPath ? options.serverPath.toLowerCase() : null;
74+
const generator = (
75+
await generators(options.customGenerator ?? options.generator)
76+
)({
77+
hydraPrefix: options.hydraPrefix,
78+
templateDirectory: options.templateDirectory,
79+
});
80+
const resourceToGenerate = options.resource
81+
? options.resource.toLowerCase()
82+
: null;
83+
const serverPath = options.serverPath
84+
? options.serverPath.toLowerCase()
85+
: null;
7786

78-
const parser = (entrypointWithSlash) => {
79-
const options = {};
80-
if (options.username && options.password) {
81-
const encoded = Buffer.from(
82-
`${options.username}:${options.password}`
83-
).toString("base64");
84-
options.headers = new Headers();
85-
options.headers.set("Authorization", `Basic ${encoded}`);
86-
}
87-
if (options.bearer) {
88-
options.headers = new Headers();
89-
options.headers.set("Authorization", `Bearer ${options.bearer}`);
90-
}
91-
switch (options.format) {
92-
case "swagger": // deprecated
93-
case "openapi2":
94-
return parseSwaggerDocumentation(entrypointWithSlash);
95-
case "openapi3":
96-
return parseOpenApi3Documentation(entrypointWithSlash);
97-
default:
98-
return parseHydraDocumentation(entrypointWithSlash, options);
99-
}
100-
};
87+
const parser = (entrypointWithSlash) => {
88+
const options = {};
89+
if (options.username && options.password) {
90+
const encoded = Buffer.from(
91+
`${options.username}:${options.password}`
92+
).toString("base64");
93+
options.headers = new Headers();
94+
options.headers.set("Authorization", `Basic ${encoded}`);
95+
}
96+
if (options.bearer) {
97+
options.headers = new Headers();
98+
options.headers.set("Authorization", `Bearer ${options.bearer}`);
99+
}
100+
switch (options.format) {
101+
case "swagger": // deprecated
102+
case "openapi2":
103+
return parseSwaggerDocumentation(entrypointWithSlash);
104+
case "openapi3":
105+
return parseOpenApi3Documentation(entrypointWithSlash);
106+
default:
107+
return parseHydraDocumentation(entrypointWithSlash, options);
108+
}
109+
};
101110

102-
// check generator dependencies
103-
generator.checkDependencies(outputDirectory, serverPath);
111+
// check generator dependencies
112+
generator.checkDependencies(outputDirectory, serverPath);
104113

105-
parser(entrypointWithSlash)
106-
.then((ret) => {
107-
ret.api.resources
108-
.filter(({ deprecated }) => !deprecated)
109-
.filter((resource) => {
110-
const nameLc = resource.name.toLowerCase();
111-
const titleLc = resource.title.toLowerCase();
114+
parser(entrypointWithSlash)
115+
.then((ret) => {
116+
ret.api.resources
117+
.filter(({ deprecated }) => !deprecated)
118+
.filter((resource) => {
119+
const nameLc = resource.name.toLowerCase();
120+
const titleLc = resource.title.toLowerCase();
112121

113-
return (
114-
null === resourceToGenerate ||
115-
nameLc === resourceToGenerate ||
116-
titleLc === resourceToGenerate
117-
);
118-
})
119-
.map((resource) => {
120-
const filterDeprecated = (list) =>
121-
list.filter(({ deprecated }) => !deprecated);
122+
return (
123+
null === resourceToGenerate ||
124+
nameLc === resourceToGenerate ||
125+
titleLc === resourceToGenerate
126+
);
127+
})
128+
.map((resource) => {
129+
const filterDeprecated = (list) =>
130+
list.filter(({ deprecated }) => !deprecated);
122131

123-
resource.fields = filterDeprecated(resource.fields);
124-
resource.readableFields = filterDeprecated(resource.readableFields);
125-
resource.writableFields = filterDeprecated(resource.writableFields);
132+
resource.fields = filterDeprecated(resource.fields);
133+
resource.readableFields = filterDeprecated(resource.readableFields);
134+
resource.writableFields = filterDeprecated(resource.writableFields);
126135

127-
generator.generate(ret.api, resource, outputDirectory, serverPath);
136+
generator.generate(ret.api, resource, outputDirectory, serverPath);
128137

129-
return resource;
130-
})
131-
// display helps after all resources have been generated to check relation dependency for example
132-
.forEach((resource) => generator.help(resource, outputDirectory));
133-
})
134-
.catch((e) => {
135-
console.log(e);
136-
});
138+
return resource;
139+
})
140+
// display helps after all resources have been generated to check relation dependency for example
141+
.forEach((resource) => generator.help(resource, outputDirectory));
142+
})
143+
.catch((e) => {
144+
console.log(e);
145+
});
146+
}
147+
148+
main();

0 commit comments

Comments
 (0)