Skip to content

Commit b744312

Browse files
committed
feat: new argument to use a custom external generator
actually add the command don't use a new argument
1 parent 709e28f commit b744312

File tree

3 files changed

+128
-115
lines changed

3 files changed

+128
-115
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"build": "babel src -d lib --ignore '*.test.js'",
5555
"watch": "babel --watch src -d lib --ignore '*.test.js'",
5656
"test-gen": "rm -rf ./tmp && yarn build && ./lib/index.js https://demo.api-platform.com ./tmp/react -g react && ./lib/index.js https://demo.api-platform.com ./tmp/react-native -g react-native && ./lib/index.js https://demo.api-platform.com ./tmp/vue -g vue",
57+
"test-gen-custom": "rm -rf ./tmp && yarn build && babel src/generators/ReactGenerator.js src/generators/BaseGenerator.js -d ./tmp/gens && cp -r ./templates/react ./templates/react-common ./templates/entrypoint.js ./tmp/gens && ./lib/index.js https://demo.api-platform.com ./tmp/react-custom -g \"$(pwd)/tmp/gens/ReactGenerator.js\" -t ./tmp/gens",
5758
"test-gen-swagger": "rm -rf ./tmp && yarn build && ./lib/index.js https://demo.api-platform.com/docs.json ./tmp/react -f swagger && ./lib/index.js https://demo.api-platform.com/docs.json ./tmp/react-native -g react-native -f swagger && ./lib/index.js https://demo.api-platform.com/docs.json ./tmp/vue -g vue -f swagger",
5859
"test-gen-env": "rm -rf ./tmp && yarn build && API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT=https://demo.api-platform.com API_PLATFORM_CLIENT_GENERATOR_OUTPUT=./tmp ./lib/index.js"
5960
},

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: 120 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -8,129 +8,135 @@ 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" or a path to a custom generator of your choice',
33+
"next"
34+
)
35+
.option(
36+
"-t, --template-directory [templateDirectory]",
37+
"The templates directory base to use. Final directory will be ${templateDirectory}/${generator}",
38+
`${__dirname}/../templates/`
39+
)
40+
.option(
41+
"-f, --format [hydra|openapi3|openapi2]",
42+
'"hydra", "openapi3" or "openapi2"',
43+
"hydra"
44+
)
45+
.option(
46+
"-s, --server-path [serverPath]",
47+
"Path to express server file to allow route dynamic addition (Next.js generator only)"
48+
)
49+
.parse(process.argv);
4950

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-
}
51+
if (
52+
2 !== program.args.length &&
53+
(!process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT ||
54+
!process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT)
55+
) {
56+
program.help();
57+
}
5758

58-
const options = program.opts();
59+
const options = program.opts();
5960

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;
61+
const entrypoint =
62+
program.args[0] || process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT;
63+
const outputDirectory =
64+
program.args[1] || process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT;
6465

65-
const entrypointWithSlash = entrypoint.endsWith("/")
66-
? entrypoint
67-
: entrypoint + "/";
66+
const entrypointWithSlash = entrypoint.endsWith("/")
67+
? entrypoint
68+
: entrypoint + "/";
6869

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;
70+
const generator = (await generators(options.generator))({
71+
hydraPrefix: options.hydraPrefix,
72+
templateDirectory: options.templateDirectory,
73+
});
74+
const resourceToGenerate = options.resource
75+
? options.resource.toLowerCase()
76+
: null;
77+
const serverPath = options.serverPath
78+
? options.serverPath.toLowerCase()
79+
: null;
7780

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

102-
// check generator dependencies
103-
generator.checkDependencies(outputDirectory, serverPath);
105+
// check generator dependencies
106+
generator.checkDependencies(outputDirectory, serverPath);
104107

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();
108+
parser(entrypointWithSlash)
109+
.then((ret) => {
110+
ret.api.resources
111+
.filter(({ deprecated }) => !deprecated)
112+
.filter((resource) => {
113+
const nameLc = resource.name.toLowerCase();
114+
const titleLc = resource.title.toLowerCase();
112115

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);
116+
return (
117+
null === resourceToGenerate ||
118+
nameLc === resourceToGenerate ||
119+
titleLc === resourceToGenerate
120+
);
121+
})
122+
.map((resource) => {
123+
const filterDeprecated = (list) =>
124+
list.filter(({ deprecated }) => !deprecated);
122125

123-
resource.fields = filterDeprecated(resource.fields);
124-
resource.readableFields = filterDeprecated(resource.readableFields);
125-
resource.writableFields = filterDeprecated(resource.writableFields);
126+
resource.fields = filterDeprecated(resource.fields);
127+
resource.readableFields = filterDeprecated(resource.readableFields);
128+
resource.writableFields = filterDeprecated(resource.writableFields);
126129

127-
generator.generate(ret.api, resource, outputDirectory, serverPath);
130+
generator.generate(ret.api, resource, outputDirectory, serverPath);
128131

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-
});
132+
return resource;
133+
})
134+
// display helps after all resources have been generated to check relation dependency for example
135+
.forEach((resource) => generator.help(resource, outputDirectory));
136+
})
137+
.catch((e) => {
138+
console.log(e);
139+
});
140+
}
141+
142+
main();

0 commit comments

Comments
 (0)