@anu8151/adonisjs-blueprint 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +131 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +7 -0
- package/build/index.d.ts +16 -0
- package/build/index.js +9 -0
- package/build/init-TjAcOVVP.js +64 -0
- package/build/main-1fZp_M_R.js +8 -0
- package/build/parser-DJB5DEck.js +5832 -0
- package/build/src/commands/build.d.ts +14 -0
- package/build/src/commands/build.js +177 -0
- package/build/src/commands/erase.d.ts +6 -0
- package/build/src/commands/erase.js +23 -0
- package/build/src/commands/init.d.ts +6 -0
- package/build/src/commands/main.d.ts +1 -0
- package/build/src/commands/main.js +10 -0
- package/build/src/commands/stubs.d.ts +6 -0
- package/build/src/commands/stubs.js +16 -0
- package/build/src/commands/trace.d.ts +6 -0
- package/build/src/commands/trace.js +60 -0
- package/build/src/generators/base_generator.d.ts +12 -0
- package/build/src/generators/base_generator.js +31 -0
- package/build/src/generators/channel_generator.d.ts +4 -0
- package/build/src/generators/channel_generator.js +25 -0
- package/build/src/generators/class_generator.d.ts +4 -0
- package/build/src/generators/class_generator.js +11 -0
- package/build/src/generators/controller_generator.d.ts +5 -0
- package/build/src/generators/controller_generator.js +355 -0
- package/build/src/generators/enum_generator.d.ts +4 -0
- package/build/src/generators/enum_generator.js +17 -0
- package/build/src/generators/event_generator.d.ts +4 -0
- package/build/src/generators/event_generator.js +10 -0
- package/build/src/generators/factory_generator.d.ts +4 -0
- package/build/src/generators/factory_generator.js +50 -0
- package/build/src/generators/job_generator.d.ts +4 -0
- package/build/src/generators/job_generator.js +10 -0
- package/build/src/generators/mail_generator.d.ts +4 -0
- package/build/src/generators/mail_generator.js +10 -0
- package/build/src/generators/middleware_generator.d.ts +4 -0
- package/build/src/generators/middleware_generator.js +10 -0
- package/build/src/generators/migration_generator.d.ts +5 -0
- package/build/src/generators/migration_generator.js +46 -0
- package/build/src/generators/model_generator.d.ts +4 -0
- package/build/src/generators/model_generator.js +57 -0
- package/build/src/generators/notification_generator.d.ts +4 -0
- package/build/src/generators/notification_generator.js +10 -0
- package/build/src/generators/openapi_generator.d.ts +8 -0
- package/build/src/generators/openapi_generator.js +200 -0
- package/build/src/generators/policy_generator.d.ts +4 -0
- package/build/src/generators/policy_generator.js +29 -0
- package/build/src/generators/route_generator.d.ts +4 -0
- package/build/src/generators/route_generator.js +34 -0
- package/build/src/generators/seeder_generator.d.ts +4 -0
- package/build/src/generators/seeder_generator.js +16 -0
- package/build/src/generators/service_generator.d.ts +4 -0
- package/build/src/generators/service_generator.js +14 -0
- package/build/src/generators/test_generator.d.ts +5 -0
- package/build/src/generators/test_generator.js +38 -0
- package/build/src/generators/validator_generator.d.ts +4 -0
- package/build/src/generators/validator_generator.js +70 -0
- package/build/src/generators/view_generator.d.ts +4 -0
- package/build/src/generators/view_generator.js +23 -0
- package/build/src/parser.d.ts +7 -0
- package/build/src/parser.js +2 -0
- package/build/src/statements/index.d.ts +1 -0
- package/build/src/statements_registry.d.ts +47 -0
- package/build/src/types.d.ts +50 -0
- package/build/statements_registry-DzyxAiKP.js +19 -0
- package/build/stubs/config.stub +32 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/make/controller/main.stub +47 -0
- package/build/stubs/make/enum/main.stub +10 -0
- package/build/stubs/make/event/main.stub +12 -0
- package/build/stubs/make/factory/main.stub +25 -0
- package/build/stubs/make/job/main.stub +12 -0
- package/build/stubs/make/mail/main.stub +23 -0
- package/build/stubs/make/middleware/main.stub +16 -0
- package/build/stubs/make/migration/main.stub +25 -0
- package/build/stubs/make/model/main.stub +19 -0
- package/build/stubs/make/notification/main.stub +28 -0
- package/build/stubs/make/policy/main.stub +17 -0
- package/build/stubs/make/seeder/main.stub +21 -0
- package/build/stubs/make/service/main.stub +8 -0
- package/build/stubs/make/test/controller.stub +23 -0
- package/build/stubs/make/validator/main.stub +22 -0
- package/build/stubs/make/view/edge.stub +65 -0
- package/build/stubs/make/view/react.stub +57 -0
- package/build/stubs/make/view/svelte.stub +67 -0
- package/build/stubs/make/view/vue.stub +74 -0
- package/package.json +151 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import { writeFileSync } from "node:fs";
|
|
3
|
+
import string from "@adonisjs/core/helpers/string";
|
|
4
|
+
//#region src/generators/openapi_generator.ts
|
|
5
|
+
var OpenAPIGenerator = class extends BaseGenerator {
|
|
6
|
+
async generate(_name, blueprint) {
|
|
7
|
+
if (!blueprint.controllers) return;
|
|
8
|
+
const openapi = {
|
|
9
|
+
openapi: "3.0.0",
|
|
10
|
+
info: {
|
|
11
|
+
title: blueprint.settings?.api ? "AdonisJS API Documentation" : "AdonisJS Application API",
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
},
|
|
14
|
+
paths: {},
|
|
15
|
+
components: {
|
|
16
|
+
schemas: {},
|
|
17
|
+
securitySchemes: { bearerAuth: {
|
|
18
|
+
type: "http",
|
|
19
|
+
scheme: "bearer",
|
|
20
|
+
bearerFormat: "JWT"
|
|
21
|
+
} }
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
if (blueprint.models) for (const [modelName, modelDef] of Object.entries(blueprint.models)) {
|
|
25
|
+
const schema = {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {},
|
|
28
|
+
required: []
|
|
29
|
+
};
|
|
30
|
+
if (modelDef.attributes) for (const [attrName, attrType] of Object.entries(modelDef.attributes)) {
|
|
31
|
+
const typeStr = typeof attrType === "string" ? attrType : attrType.type || "string";
|
|
32
|
+
schema.properties[attrName] = { type: this.mapToOpenAPIType(typeStr) };
|
|
33
|
+
if (typeof attrType === "string" && !attrType.includes("optional") && !attrType.includes("nullable")) schema.required.push(attrName);
|
|
34
|
+
}
|
|
35
|
+
if (schema.required.length === 0) delete schema.required;
|
|
36
|
+
openapi.components.schemas[modelName] = schema;
|
|
37
|
+
}
|
|
38
|
+
for (const [controllerName, controllerDef] of Object.entries(blueprint.controllers)) {
|
|
39
|
+
const resourceName = string.snakeCase(controllerName);
|
|
40
|
+
const normalizedDefinition = this.normalizeDefinition(controllerDef, blueprint.settings?.api, controllerName);
|
|
41
|
+
const modelName = string.pascalCase(string.singular(controllerName));
|
|
42
|
+
for (const [actionName, actionDef] of Object.entries(normalizedDefinition)) {
|
|
43
|
+
if (actionName === "resource" || actionName === "middleware" || actionName === "stub") continue;
|
|
44
|
+
const { path, method } = this.inferRoute(resourceName, actionName);
|
|
45
|
+
if (!path || !method) continue;
|
|
46
|
+
if (!openapi.paths[path]) openapi.paths[path] = {};
|
|
47
|
+
const operation = {
|
|
48
|
+
tags: [controllerName],
|
|
49
|
+
summary: `${actionName} action for ${controllerName}`,
|
|
50
|
+
responses: { "200": { description: "Successful response" } }
|
|
51
|
+
};
|
|
52
|
+
if (path.includes("{id}")) operation.parameters = [{
|
|
53
|
+
name: "id",
|
|
54
|
+
in: "path",
|
|
55
|
+
required: true,
|
|
56
|
+
schema: { type: "string" }
|
|
57
|
+
}];
|
|
58
|
+
if (actionDef.auth) operation.security = [{ bearerAuth: [] }];
|
|
59
|
+
if (actionDef.validate) {
|
|
60
|
+
const validateFields = actionDef.validate === "all" ? Object.keys(blueprint.models?.[modelName]?.attributes || {}) : actionDef.validate.split(",").map((f) => f.trim());
|
|
61
|
+
operation.requestBody = { content: { "application/json": { schema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {}
|
|
64
|
+
} } } };
|
|
65
|
+
for (const field of validateFields) {
|
|
66
|
+
const attrType = blueprint.models?.[modelName]?.attributes?.[field];
|
|
67
|
+
const typeStr = typeof attrType === "string" ? attrType : attrType?.type || "string";
|
|
68
|
+
operation.requestBody.content["application/json"].schema.properties[field] = { type: this.mapToOpenAPIType(typeStr) };
|
|
69
|
+
}
|
|
70
|
+
} else if (actionName === "store" || actionName === "update") operation.requestBody = { content: { "application/json": { schema: { $ref: `#/components/schemas/${modelName}` } } } };
|
|
71
|
+
if (actionDef.query === "all" || actionDef.query?.startsWith("paginate")) {
|
|
72
|
+
operation.responses["200"].content = { "application/json": { schema: {
|
|
73
|
+
type: "array",
|
|
74
|
+
items: { $ref: `#/components/schemas/${modelName}` }
|
|
75
|
+
} } };
|
|
76
|
+
if (actionDef.query.startsWith("paginate")) {
|
|
77
|
+
if (!operation.parameters) operation.parameters = [];
|
|
78
|
+
operation.parameters.push({
|
|
79
|
+
name: "page",
|
|
80
|
+
in: "query",
|
|
81
|
+
schema: {
|
|
82
|
+
type: "integer",
|
|
83
|
+
default: 1
|
|
84
|
+
}
|
|
85
|
+
}, {
|
|
86
|
+
name: "limit",
|
|
87
|
+
in: "query",
|
|
88
|
+
schema: {
|
|
89
|
+
type: "integer",
|
|
90
|
+
default: 20
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} else if (actionDef.query === "find") operation.responses["200"].content = { "application/json": { schema: { $ref: `#/components/schemas/${modelName}` } } };
|
|
95
|
+
openapi.paths[path][method] = operation;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const outputPath = this.app.makePath("openapi.json");
|
|
99
|
+
writeFileSync(outputPath, JSON.stringify(openapi, null, 2));
|
|
100
|
+
this.logger.action(`create ${outputPath}`).succeeded();
|
|
101
|
+
if (this.manifest) this.manifest.push(outputPath);
|
|
102
|
+
}
|
|
103
|
+
mapToOpenAPIType(type) {
|
|
104
|
+
switch (type.split(":")[0]) {
|
|
105
|
+
case "integer":
|
|
106
|
+
case "number": return "number";
|
|
107
|
+
case "boolean": return "boolean";
|
|
108
|
+
case "datetime":
|
|
109
|
+
case "timestamp":
|
|
110
|
+
case "date": return "string";
|
|
111
|
+
default: return "string";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
normalizeDefinition(definition, isApi, controllerName) {
|
|
115
|
+
if (definition.resource) {
|
|
116
|
+
const pluralName = string.plural(string.camelCase(controllerName || ""));
|
|
117
|
+
return isApi ? {
|
|
118
|
+
index: {
|
|
119
|
+
query: "all",
|
|
120
|
+
render: "json"
|
|
121
|
+
},
|
|
122
|
+
store: {
|
|
123
|
+
validate: "all",
|
|
124
|
+
save: true,
|
|
125
|
+
render: "json"
|
|
126
|
+
},
|
|
127
|
+
show: {
|
|
128
|
+
query: "find",
|
|
129
|
+
render: "json"
|
|
130
|
+
},
|
|
131
|
+
update: {
|
|
132
|
+
validate: "all",
|
|
133
|
+
save: true,
|
|
134
|
+
render: "json"
|
|
135
|
+
},
|
|
136
|
+
destroy: {
|
|
137
|
+
delete: true,
|
|
138
|
+
render: "json"
|
|
139
|
+
}
|
|
140
|
+
} : {
|
|
141
|
+
index: { render: `${pluralName}/index` },
|
|
142
|
+
create: { render: `${pluralName}/create` },
|
|
143
|
+
store: {
|
|
144
|
+
validate: "all",
|
|
145
|
+
save: true,
|
|
146
|
+
redirect: `${pluralName}.index`
|
|
147
|
+
},
|
|
148
|
+
show: { render: `${pluralName}/show` },
|
|
149
|
+
edit: { render: `${pluralName}/edit` },
|
|
150
|
+
update: {
|
|
151
|
+
validate: "all",
|
|
152
|
+
save: true,
|
|
153
|
+
redirect: `${pluralName}.index`
|
|
154
|
+
},
|
|
155
|
+
destroy: {
|
|
156
|
+
delete: true,
|
|
157
|
+
redirect: `${pluralName}.index`
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return definition;
|
|
162
|
+
}
|
|
163
|
+
inferRoute(resourceName, actionName) {
|
|
164
|
+
return {
|
|
165
|
+
index: {
|
|
166
|
+
path: `/${resourceName}`,
|
|
167
|
+
method: "get"
|
|
168
|
+
},
|
|
169
|
+
create: {
|
|
170
|
+
path: `/${resourceName}/create`,
|
|
171
|
+
method: "get"
|
|
172
|
+
},
|
|
173
|
+
store: {
|
|
174
|
+
path: `/${resourceName}`,
|
|
175
|
+
method: "post"
|
|
176
|
+
},
|
|
177
|
+
show: {
|
|
178
|
+
path: `/${resourceName}/{id}`,
|
|
179
|
+
method: "get"
|
|
180
|
+
},
|
|
181
|
+
edit: {
|
|
182
|
+
path: `/${resourceName}/{id}/edit`,
|
|
183
|
+
method: "get"
|
|
184
|
+
},
|
|
185
|
+
update: {
|
|
186
|
+
path: `/${resourceName}/{id}`,
|
|
187
|
+
method: "put"
|
|
188
|
+
},
|
|
189
|
+
destroy: {
|
|
190
|
+
path: `/${resourceName}/{id}`,
|
|
191
|
+
method: "delete"
|
|
192
|
+
}
|
|
193
|
+
}[actionName] || {
|
|
194
|
+
path: `/${resourceName}/${string.snakeCase(actionName)}`,
|
|
195
|
+
method: "get"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
//#endregion
|
|
200
|
+
export { OpenAPIGenerator };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import string from "@adonisjs/core/helpers/string";
|
|
3
|
+
//#region src/generators/policy_generator.ts
|
|
4
|
+
var PolicyGenerator = class extends BaseGenerator {
|
|
5
|
+
async generate(name, definition) {
|
|
6
|
+
const entity = this.app.generators.createEntity(name);
|
|
7
|
+
const actions = [];
|
|
8
|
+
for (const [actionName, actionDef] of Object.entries(definition)) {
|
|
9
|
+
if (typeof actionDef !== "object") continue;
|
|
10
|
+
let policyAction = actionName;
|
|
11
|
+
if (actionName === "index") policyAction = "viewAny";
|
|
12
|
+
if (actionName === "show") policyAction = "view";
|
|
13
|
+
if (actionName === "store") policyAction = "create";
|
|
14
|
+
if (actionName === "update") policyAction = "update";
|
|
15
|
+
if (actionName === "destroy") policyAction = "delete";
|
|
16
|
+
actions.push({
|
|
17
|
+
name: policyAction,
|
|
18
|
+
modelName: entity.className,
|
|
19
|
+
variableName: string.camelCase(entity.className)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
await this.generateStub("make/policy/main.stub", {
|
|
23
|
+
entity,
|
|
24
|
+
actions
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
export { PolicyGenerator };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
//#region src/generators/route_generator.ts
|
|
4
|
+
var RouteGenerator = class extends BaseGenerator {
|
|
5
|
+
async generate(name, definition, isApi = false) {
|
|
6
|
+
const nameParts = name.split(/[\/.]/);
|
|
7
|
+
const baseName = nameParts.pop();
|
|
8
|
+
const parents = nameParts.map((p) => p.toLowerCase() + "s");
|
|
9
|
+
const entity = this.app.generators.createEntity(baseName);
|
|
10
|
+
const routesPath = this.app.makePath("start/routes.ts");
|
|
11
|
+
if (!existsSync(routesPath)) {
|
|
12
|
+
this.logger.warning(`File ${routesPath} not found. Skipping route registration.`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const resourceName = entity.name.toLowerCase() + "s";
|
|
16
|
+
const fullResourcePath = [...parents, resourceName].join(".");
|
|
17
|
+
const controllerPath = [...nameParts.map((p) => p.toLowerCase()), entity.name.toLowerCase()].join("/");
|
|
18
|
+
let content = readFileSync(routesPath, "utf8");
|
|
19
|
+
if (content.includes(`router.resource('${fullResourcePath}'`)) return;
|
|
20
|
+
let routeLine = `router.resource('${fullResourcePath}', '#controllers/${controllerPath}_controller')`;
|
|
21
|
+
if (isApi) routeLine += ".apiOnly()";
|
|
22
|
+
if (definition.middleware && definition.middleware.length > 0) {
|
|
23
|
+
const mw = definition.middleware.map((m) => `middleware.${m}()`).join(", ");
|
|
24
|
+
routeLine += `.use('*', [${mw}])`;
|
|
25
|
+
}
|
|
26
|
+
if (nameParts.length > 0) {
|
|
27
|
+
const prefix = nameParts.map((p) => p.toLowerCase()).join("/");
|
|
28
|
+
writeFileSync(routesPath, content + `\nrouter.group(() => {\n ${routeLine}\n}).prefix('${prefix}')`);
|
|
29
|
+
} else writeFileSync(routesPath, content + `\n${routeLine}`);
|
|
30
|
+
this.logger.success(`Registered resource routes for ${fullResourcePath}`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { RouteGenerator };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
//#region src/generators/seeder_generator.ts
|
|
3
|
+
var SeederGenerator = class extends BaseGenerator {
|
|
4
|
+
async generate(name, definition) {
|
|
5
|
+
const entity = this.app.generators.createEntity(name);
|
|
6
|
+
const count = definition.seed || 10;
|
|
7
|
+
const data = definition.data || null;
|
|
8
|
+
await this.generateStub("make/seeder/main.stub", {
|
|
9
|
+
entity,
|
|
10
|
+
count,
|
|
11
|
+
data
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { SeederGenerator };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import string from "@adonisjs/core/helpers/string";
|
|
3
|
+
//#region src/generators/service_generator.ts
|
|
4
|
+
var ServiceGenerator = class extends BaseGenerator {
|
|
5
|
+
async generate(name) {
|
|
6
|
+
const nameParts = name.split(/[\/.]/);
|
|
7
|
+
const baseName = nameParts.pop();
|
|
8
|
+
const entity = this.app.generators.createEntity(baseName);
|
|
9
|
+
if (nameParts.length > 0) entity.path = nameParts.map((p) => string.snakeCase(p)).join("/");
|
|
10
|
+
await this.generateStub("make/service/main.stub", { entity });
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ServiceGenerator };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import string from "@adonisjs/core/helpers/string";
|
|
3
|
+
//#region src/generators/test_generator.ts
|
|
4
|
+
var TestGenerator = class extends BaseGenerator {
|
|
5
|
+
async generate(name, definition, blueprint) {
|
|
6
|
+
const entity = this.app.generators.createEntity(name);
|
|
7
|
+
const actions = [];
|
|
8
|
+
const pluralName = string.plural(string.snakeCase(entity.name));
|
|
9
|
+
for (const [actionName, actionDef] of Object.entries(definition)) {
|
|
10
|
+
if (typeof actionDef !== "object") continue;
|
|
11
|
+
let method = "get";
|
|
12
|
+
let url = `/${pluralName}`;
|
|
13
|
+
const typedDef = actionDef;
|
|
14
|
+
if (actionName === "store") method = "post";
|
|
15
|
+
else if (actionName === "show" || actionName === "edit") url = `/${pluralName}/1`;
|
|
16
|
+
else if (actionName === "update") {
|
|
17
|
+
method = "put";
|
|
18
|
+
url = `/${pluralName}/1`;
|
|
19
|
+
} else if (actionName === "destroy") {
|
|
20
|
+
method = "delete";
|
|
21
|
+
url = `/${pluralName}/1`;
|
|
22
|
+
} else if (actionName === "create") url = `/${pluralName}/create`;
|
|
23
|
+
actions.push({
|
|
24
|
+
name: actionName,
|
|
25
|
+
method,
|
|
26
|
+
url,
|
|
27
|
+
auth: !!typedDef.auth
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
await this.generateStub("make/test/controller.stub", {
|
|
31
|
+
entity,
|
|
32
|
+
actions,
|
|
33
|
+
hasAuth: actions.some((a) => a.auth) || !!blueprint.auth
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { TestGenerator };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
import string from "@adonisjs/core/helpers/string";
|
|
3
|
+
//#region src/generators/validator_generator.ts
|
|
4
|
+
var ValidatorGenerator = class extends BaseGenerator {
|
|
5
|
+
async generate(name, definition) {
|
|
6
|
+
const entity = this.app.generators.createEntity(name);
|
|
7
|
+
const attributes = [];
|
|
8
|
+
if (definition.attributes) for (const [attrName, attrType] of Object.entries(definition.attributes)) {
|
|
9
|
+
let vineChain = "vine.string()";
|
|
10
|
+
const parts = (typeof attrType === "string" ? attrType : attrType.type || "string").split(":");
|
|
11
|
+
const baseType = parts[0];
|
|
12
|
+
if (baseType === "number" || baseType === "integer") vineChain = "vine.number()";
|
|
13
|
+
else if (baseType === "boolean") vineChain = "vine.boolean()";
|
|
14
|
+
else if (baseType === "email") vineChain = "vine.string().email()";
|
|
15
|
+
else if (baseType === "url") vineChain = "vine.string().url()";
|
|
16
|
+
else if (baseType === "ip") vineChain = "vine.string().ip()";
|
|
17
|
+
else if (baseType === "uuid") vineChain = "vine.string().uuid()";
|
|
18
|
+
else if (baseType === "mobile") vineChain = "vine.string().mobile()";
|
|
19
|
+
else if (baseType === "postalCode") vineChain = "vine.string().postalCode()";
|
|
20
|
+
else if (baseType === "creditCard") vineChain = "vine.string().creditCard()";
|
|
21
|
+
else if (baseType === "macAddress") vineChain = "vine.string().macAddress()";
|
|
22
|
+
for (let i = 1; i < parts.length; i++) {
|
|
23
|
+
const modifier = parts[i];
|
|
24
|
+
if (modifier === "unique") {
|
|
25
|
+
const tableName = string.plural(string.snakeCase(entity.name));
|
|
26
|
+
const scope = parts.find((p) => p.startsWith("scope:"));
|
|
27
|
+
if (scope) {
|
|
28
|
+
const scopeColumn = scope.replace("scope:", "");
|
|
29
|
+
vineChain += `.unique(async (db, value, field) => {
|
|
30
|
+
const query = db.from('${tableName}').where('${attrName}', value)
|
|
31
|
+
if (field.meta.id) query.whereNot('id', field.meta.id)
|
|
32
|
+
const scopeValue = field.meta['${scopeColumn}'] || field.data['${scopeColumn}']
|
|
33
|
+
if (scopeValue) query.where('${scopeColumn}', scopeValue)
|
|
34
|
+
return !await query.first()
|
|
35
|
+
})`;
|
|
36
|
+
} else vineChain += `.unique(async (db, value, field) => {
|
|
37
|
+
const query = db.from('${tableName}').where('${attrName}', value)
|
|
38
|
+
if (field.meta.id) query.whereNot('id', field.meta.id)
|
|
39
|
+
return !await query.first()
|
|
40
|
+
})`;
|
|
41
|
+
} else if (modifier === "min" && parts[i + 1]) {
|
|
42
|
+
vineChain += baseType === "number" ? `.min(${parts[i + 1]})` : `.minLength(${parts[i + 1]})`;
|
|
43
|
+
i++;
|
|
44
|
+
} else if (modifier === "max" && parts[i + 1]) {
|
|
45
|
+
vineChain += baseType === "number" ? `.max(${parts[i + 1]})` : `.maxLength(${parts[i + 1]})`;
|
|
46
|
+
i++;
|
|
47
|
+
} else if (modifier === "optional" || modifier === "nullable") vineChain += ".optional()";
|
|
48
|
+
else if (modifier === "confirmed") vineChain += ".confirmed()";
|
|
49
|
+
else if (modifier === "regex" && parts[i + 1]) {
|
|
50
|
+
vineChain += `.regex(new RegExp('${parts[i + 1]}'))`;
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
attributes.push({
|
|
55
|
+
name: attrName,
|
|
56
|
+
vineType: vineChain.replace("vine.", "")
|
|
57
|
+
});
|
|
58
|
+
if (parts.includes("confirmed")) attributes.push({
|
|
59
|
+
name: `${attrName}_confirmation`,
|
|
60
|
+
vineType: vineChain.replace("vine.", "").replace(".confirmed()", "")
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
await this.generateStub("make/validator/main.stub", {
|
|
64
|
+
entity,
|
|
65
|
+
attributes
|
|
66
|
+
}, definition.stub);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { ValidatorGenerator };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseGenerator } from "./base_generator.js";
|
|
2
|
+
//#region src/generators/view_generator.ts
|
|
3
|
+
var ViewGenerator = class extends BaseGenerator {
|
|
4
|
+
async generate(name, useInertia = false, adapter = "react", definition) {
|
|
5
|
+
const entity = this.app.generators.createEntity(name);
|
|
6
|
+
let stubPath = "make/view/edge.stub";
|
|
7
|
+
if (useInertia) stubPath = `make/view/${adapter}.stub`;
|
|
8
|
+
const attributes = definition?.attributes ? Object.entries(definition.attributes).map(([attrName, attrType]) => ({
|
|
9
|
+
name: attrName,
|
|
10
|
+
type: typeof attrType === "string" ? attrType : attrType.type
|
|
11
|
+
})) : [];
|
|
12
|
+
const action = name.split("/").pop() || "show";
|
|
13
|
+
const folder = name.split("/").slice(0, -1).join("/");
|
|
14
|
+
await this.generateStub(stubPath, {
|
|
15
|
+
entity,
|
|
16
|
+
attributes,
|
|
17
|
+
action,
|
|
18
|
+
folder
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ViewGenerator };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Entity } from './types.js';
|
|
2
|
+
import { type EventGenerator } from './generators/event_generator.js';
|
|
3
|
+
import { type MailGenerator } from './generators/mail_generator.js';
|
|
4
|
+
import { type JobGenerator } from './generators/job_generator.js';
|
|
5
|
+
import { type NotificationGenerator } from './generators/notification_generator.js';
|
|
6
|
+
import { type ServiceGenerator } from './generators/service_generator.js';
|
|
7
|
+
export interface StatementContext {
|
|
8
|
+
actionName: string;
|
|
9
|
+
actionDef: any;
|
|
10
|
+
entity: Entity;
|
|
11
|
+
isApi: boolean;
|
|
12
|
+
useInertia: boolean;
|
|
13
|
+
pluralName: string;
|
|
14
|
+
singularName: string;
|
|
15
|
+
generators: {
|
|
16
|
+
event: EventGenerator;
|
|
17
|
+
mail: MailGenerator;
|
|
18
|
+
job: JobGenerator;
|
|
19
|
+
notification: NotificationGenerator;
|
|
20
|
+
service: ServiceGenerator;
|
|
21
|
+
};
|
|
22
|
+
models?: any;
|
|
23
|
+
}
|
|
24
|
+
export interface StatementResult {
|
|
25
|
+
logicLines: string[];
|
|
26
|
+
imports?: {
|
|
27
|
+
models?: string[];
|
|
28
|
+
validators?: string[];
|
|
29
|
+
events?: string[];
|
|
30
|
+
policies?: string[];
|
|
31
|
+
mails?: string[];
|
|
32
|
+
jobs?: string[];
|
|
33
|
+
notifications?: string[];
|
|
34
|
+
services?: string[];
|
|
35
|
+
};
|
|
36
|
+
context?: string[];
|
|
37
|
+
}
|
|
38
|
+
export type StatementHandler = (value: any, context: StatementContext) => StatementResult | Promise<StatementResult>;
|
|
39
|
+
declare class StatementsRegistry {
|
|
40
|
+
private handlers;
|
|
41
|
+
register(name: string, handler: StatementHandler): void;
|
|
42
|
+
get(name: string): StatementHandler | undefined;
|
|
43
|
+
has(name: string): boolean;
|
|
44
|
+
all(): MapIterator<[string, StatementHandler]>;
|
|
45
|
+
}
|
|
46
|
+
export declare const statementsRegistry: StatementsRegistry;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface Entity {
|
|
2
|
+
name: string;
|
|
3
|
+
path: string;
|
|
4
|
+
className: string;
|
|
5
|
+
tableName?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ModelAttribute {
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
modifiers: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface ModelRelationship {
|
|
13
|
+
type: 'belongsTo' | 'hasMany' | 'belongsToMany' | 'hasOne';
|
|
14
|
+
model: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ModelDefinition {
|
|
17
|
+
name: string;
|
|
18
|
+
attributes: Record<string, string | {
|
|
19
|
+
type: string;
|
|
20
|
+
modifiers?: string[];
|
|
21
|
+
}>;
|
|
22
|
+
relationships?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
export interface ControllerAction {
|
|
25
|
+
query?: string;
|
|
26
|
+
render?: string;
|
|
27
|
+
validate?: string;
|
|
28
|
+
save?: string | boolean;
|
|
29
|
+
flash?: string;
|
|
30
|
+
redirect?: string;
|
|
31
|
+
delete?: string | boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface ControllerDefinition {
|
|
34
|
+
name: string;
|
|
35
|
+
middleware?: string[];
|
|
36
|
+
actions: Record<string, ControllerAction>;
|
|
37
|
+
}
|
|
38
|
+
export interface BlueprintSchema {
|
|
39
|
+
settings?: {
|
|
40
|
+
api?: boolean;
|
|
41
|
+
inertia?: {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
adapter: 'react' | 'vue' | 'svelte';
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
auth?: Record<string, any> | boolean;
|
|
47
|
+
models?: Record<string, any>;
|
|
48
|
+
controllers?: Record<string, any>;
|
|
49
|
+
channels?: Record<string, any>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/statements_registry.ts
|
|
2
|
+
var StatementsRegistry = class {
|
|
3
|
+
handlers = /* @__PURE__ */ new Map();
|
|
4
|
+
register(name, handler) {
|
|
5
|
+
this.handlers.set(name, handler);
|
|
6
|
+
}
|
|
7
|
+
get(name) {
|
|
8
|
+
return this.handlers.get(name);
|
|
9
|
+
}
|
|
10
|
+
has(name) {
|
|
11
|
+
return this.handlers.has(name);
|
|
12
|
+
}
|
|
13
|
+
all() {
|
|
14
|
+
return this.handlers.entries();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const statementsRegistry = new StatementsRegistry();
|
|
18
|
+
//#endregion
|
|
19
|
+
export { statementsRegistry as t };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({
|
|
3
|
+
to: app.configPath('blueprint.ts')
|
|
4
|
+
})
|
|
5
|
+
}}}
|
|
6
|
+
import { defineConfig } from '@anu8151/adonisjs-blueprint'
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
/**
|
|
10
|
+
* Default view framework to use
|
|
11
|
+
* Options: 'edge', 'inertia'
|
|
12
|
+
*/
|
|
13
|
+
viewer: 'edge',
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Default Inertia adapter
|
|
17
|
+
* Options: 'react', 'vue', 'svelte'
|
|
18
|
+
*/
|
|
19
|
+
inertia: {
|
|
20
|
+
adapter: 'react'
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Custom namespaces for generated files
|
|
25
|
+
*/
|
|
26
|
+
namespaces: {
|
|
27
|
+
models: 'app/models',
|
|
28
|
+
controllers: 'app/controllers',
|
|
29
|
+
validators: 'app/validators',
|
|
30
|
+
factories: 'database/factories',
|
|
31
|
+
}
|
|
32
|
+
})
|