@decohere/create 0.0.1-dev.17 → 0.0.1-dev.19
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/commonjs/src/cli.js +30 -5
- package/commonjs/src/domain/prompt.js +55 -0
- package/commonjs/src/models/compose.model.js +82 -0
- package/commonjs/src/models/config-yaml.model.js +34 -0
- package/commonjs/src/models/const.js +29 -0
- package/commonjs/src/models/container-image.model.js +88 -0
- package/commonjs/src/models/dev-container.model.js +73 -0
- package/commonjs/src/models/env-file.model.js +33 -0
- package/commonjs/src/models/gitignore.model.js +32 -0
- package/commonjs/src/models/launch-json.model.js +52 -0
- package/commonjs/src/models/package-json.model.js +64 -0
- package/commonjs/src/models/project.model.js +126 -0
- package/commonjs/src/models/source-file.js +6 -0
- package/commonjs/src/models/tsconfig.model.js +34 -0
- package/commonjs/src/models/vscode-settings.model.js +31 -0
- package/commonjs/src/runner.js +56 -0
- package/commonjs/src/services/scaffold.service.js +62 -0
- package/commonjs/src/version.js +32 -0
- package/commonjs/src/webapi/create-api.js +169 -0
- package/commonjs/src/webapi/features/auth.feature.js +166 -0
- package/commonjs/src/webapi/features/auth0-cli.js +151 -0
- package/commonjs/src/webapi/features/database.feature.js +151 -0
- package/commonjs/src/webapi/features/finalize.feature.js +51 -0
- package/commonjs/src/webapi/features/postman.feature.js +309 -0
- package/commonjs/src/webapi/models/api-package-json.model.js +57 -0
- package/commonjs/src/webapi/models/auth-config.model.js +23 -0
- package/commonjs/src/webapi/models/controller-source-file.model.js +180 -0
- package/commonjs/src/webapi/models/main-source-file.model.js +132 -0
- package/commonjs/src/webapi/models/sample-files.model.js +60 -0
- package/es6/src/cli.js +30 -5
- package/es6/src/domain/prompt.js +37 -0
- package/es6/src/models/compose.model.js +77 -0
- package/es6/src/models/config-yaml.model.js +30 -0
- package/es6/src/models/const.js +19 -0
- package/es6/src/models/container-image.model.js +84 -0
- package/es6/src/models/dev-container.model.js +68 -0
- package/es6/src/models/env-file.model.js +29 -0
- package/es6/src/models/gitignore.model.js +22 -0
- package/es6/src/models/launch-json.model.js +42 -0
- package/es6/src/models/package-json.model.js +60 -0
- package/es6/src/models/project.model.js +111 -0
- package/es6/src/models/source-file.js +3 -0
- package/es6/src/models/tsconfig.model.js +24 -0
- package/es6/src/models/vscode-settings.model.js +21 -0
- package/es6/src/runner.js +55 -0
- package/es6/src/services/scaffold.service.js +52 -0
- package/es6/src/version.js +22 -0
- package/es6/src/webapi/create-api.js +151 -0
- package/es6/src/webapi/features/auth.feature.js +115 -0
- package/es6/src/webapi/features/auth0-cli.js +116 -0
- package/es6/src/webapi/features/database.feature.js +141 -0
- package/es6/src/webapi/features/finalize.feature.js +41 -0
- package/es6/src/webapi/features/postman.feature.js +258 -0
- package/es6/src/webapi/models/api-package-json.model.js +52 -0
- package/es6/src/webapi/models/auth-config.model.js +19 -0
- package/es6/src/webapi/models/controller-source-file.model.js +171 -0
- package/es6/src/webapi/models/main-source-file.model.js +128 -0
- package/es6/src/webapi/models/sample-files.model.js +42 -0
- package/package.json +2 -2
- package/types/src/domain/prompt.d.ts +2 -0
- package/types/src/models/compose.model.d.ts +32 -0
- package/types/src/models/config-yaml.model.d.ts +16 -0
- package/types/src/models/const.d.ts +17 -0
- package/types/src/models/container-image.model.d.ts +15 -0
- package/types/src/models/dev-container.model.d.ts +21 -0
- package/types/src/models/env-file.model.d.ts +14 -0
- package/types/src/models/gitignore.model.d.ts +6 -0
- package/types/src/models/launch-json.model.d.ts +5 -0
- package/types/src/models/package-json.model.d.ts +18 -0
- package/types/src/models/project.model.d.ts +55 -0
- package/types/src/models/source-file.d.ts +11 -0
- package/types/src/models/tsconfig.model.d.ts +5 -0
- package/types/src/models/vscode-settings.model.d.ts +7 -0
- package/types/src/runner.d.ts +13 -0
- package/types/src/services/scaffold.service.d.ts +22 -0
- package/types/src/version.d.ts +2 -0
- package/types/src/webapi/create-api.d.ts +7 -0
- package/types/src/webapi/features/auth.feature.d.ts +7 -0
- package/types/src/webapi/features/auth0-cli.d.ts +22 -0
- package/types/src/webapi/features/database.feature.d.ts +5 -0
- package/types/src/webapi/features/finalize.feature.d.ts +2 -0
- package/types/src/webapi/features/postman.feature.d.ts +7 -0
- package/types/src/webapi/models/api-package-json.model.d.ts +17 -0
- package/types/src/webapi/models/auth-config.model.d.ts +18 -0
- package/types/src/webapi/models/controller-source-file.model.d.ts +42 -0
- package/types/src/webapi/models/main-source-file.model.d.ts +36 -0
- package/types/src/webapi/models/sample-files.model.d.ts +7 -0
- package/commonjs/src/scaffold.js +0 -89
- package/commonjs/src/templates.js +0 -306
- package/es6/src/scaffold.js +0 -79
- package/es6/src/templates.js +0 -246
- package/types/src/scaffold.d.ts +0 -6
- package/types/src/templates.d.ts +0 -20
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { WELL_KNOWN_FILES } from "../../models/const.js";
|
|
2
|
+
/** Tracks named imports from a single module path, split into values and types. */ class ImportGroup {
|
|
3
|
+
_values = [];
|
|
4
|
+
_types = [];
|
|
5
|
+
add(name, typeOnly = false) {
|
|
6
|
+
if (typeOnly) {
|
|
7
|
+
// Value import already present — value wins, skip
|
|
8
|
+
if (!this._values.includes(name) && !this._types.includes(name)) {
|
|
9
|
+
this._types.push(name);
|
|
10
|
+
}
|
|
11
|
+
} else {
|
|
12
|
+
// Promote: remove from types if it was previously type-only
|
|
13
|
+
const typeIdx = this._types.indexOf(name);
|
|
14
|
+
if (typeIdx !== -1) this._types.splice(typeIdx, 1);
|
|
15
|
+
if (!this._values.includes(name)) this._values.push(name);
|
|
16
|
+
}
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
render(from) {
|
|
20
|
+
const values = [
|
|
21
|
+
...this._values
|
|
22
|
+
].sort();
|
|
23
|
+
const types = [
|
|
24
|
+
...this._types
|
|
25
|
+
].sort().map((n)=>`type ${n}`);
|
|
26
|
+
return `import { ${[
|
|
27
|
+
...values,
|
|
28
|
+
...types
|
|
29
|
+
].join(", ")} } from "${from}";`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A controller method. Features call `addDecorator()` to prepend decorators
|
|
34
|
+
* before the HTTP verb decorator (e.g. `@AllowAnonymous` before `@Get()`).
|
|
35
|
+
*/ export class ControllerMethod {
|
|
36
|
+
name;
|
|
37
|
+
_httpDecorator;
|
|
38
|
+
_params;
|
|
39
|
+
_isAsync;
|
|
40
|
+
_body;
|
|
41
|
+
_extraDecorators = [];
|
|
42
|
+
constructor(name, _httpDecorator, _params, _isAsync, _body){
|
|
43
|
+
this.name = name;
|
|
44
|
+
this._httpDecorator = _httpDecorator;
|
|
45
|
+
this._params = _params;
|
|
46
|
+
this._isAsync = _isAsync;
|
|
47
|
+
this._body = _body;
|
|
48
|
+
}
|
|
49
|
+
addDecorator(decorator) {
|
|
50
|
+
this._extraDecorators.push(decorator);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
render() {
|
|
54
|
+
const lines = [];
|
|
55
|
+
for (const d of this._extraDecorators){
|
|
56
|
+
lines.push(`\t${d}`);
|
|
57
|
+
}
|
|
58
|
+
lines.push(`\t${this._httpDecorator}`);
|
|
59
|
+
const asyncKw = this._isAsync ? "async " : "";
|
|
60
|
+
lines.push(`\tpublic ${asyncKw}${this.name}(${this._params}) {`);
|
|
61
|
+
for (const line of this._body){
|
|
62
|
+
lines.push(`\t\t${line}`);
|
|
63
|
+
}
|
|
64
|
+
lines.push("\t}");
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Model for `projects/api/src/controllers/hello.controller.ts`.
|
|
70
|
+
*
|
|
71
|
+
* Pre-initialised with all routes and their HTTP decorators. Features mutate
|
|
72
|
+
* the model via `getMethod(name).addDecorator(...)`, `addDecorator(...)` (class
|
|
73
|
+
* level), `addCortexImport(...)`, `addImport(...)`, and `addConstructorParam(...)`.
|
|
74
|
+
*/ export class ControllerSourceFile {
|
|
75
|
+
key = WELL_KNOWN_FILES.CONTROLLER_TS;
|
|
76
|
+
_cortexImports = new ImportGroup().add("Controller").add("Delete").add("Field").add("Get").add("Param").add("Post").add("Put").add("Query");
|
|
77
|
+
_extraImportGroups = new Map();
|
|
78
|
+
_classDecorators = [];
|
|
79
|
+
_ctorParams = [
|
|
80
|
+
"private readonly sample: SampleService"
|
|
81
|
+
];
|
|
82
|
+
_methods = new Map([
|
|
83
|
+
[
|
|
84
|
+
"getAll",
|
|
85
|
+
new ControllerMethod("getAll", "@Get()", '@Query("filter") filter: string', true, [
|
|
86
|
+
"const greeting = await this.sample.getGreeting();",
|
|
87
|
+
"return { filter, message: greeting };"
|
|
88
|
+
])
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
"getOne",
|
|
92
|
+
new ControllerMethod("getOne", '@Get("/:id")', '@Param("id") id: string', false, // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
|
|
93
|
+
[
|
|
94
|
+
"return { id, message: `Hello ${id}!` };"
|
|
95
|
+
])
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
"create",
|
|
99
|
+
new ControllerMethod("create", '@Post("/")', "body: HelloBody", false, [
|
|
100
|
+
"return { message: body.message };"
|
|
101
|
+
])
|
|
102
|
+
],
|
|
103
|
+
[
|
|
104
|
+
"update",
|
|
105
|
+
new ControllerMethod("update", '@Put("/:id")', '@Param("id") id: string, body: HelloBody', false, [
|
|
106
|
+
"return { id, message: body.message };"
|
|
107
|
+
])
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
"remove",
|
|
111
|
+
new ControllerMethod("remove", '@Delete("/:id")', '@Param("id") id: string', false, [
|
|
112
|
+
"return { id, deleted: true };"
|
|
113
|
+
])
|
|
114
|
+
]
|
|
115
|
+
]);
|
|
116
|
+
/** Retrieve a method by name to mutate its decorators. */ getMethod(name) {
|
|
117
|
+
const m = this._methods.get(name);
|
|
118
|
+
if (m == null) throw new Error(`No method '${name}' on ControllerSourceFile`);
|
|
119
|
+
return m;
|
|
120
|
+
}
|
|
121
|
+
/** Add a class-level decorator (e.g. `@Authorize`). */ addDecorator(decorator) {
|
|
122
|
+
this._classDecorators.push(decorator);
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/** Add a named import from `@decohere/cortex`. */ addCortexImport(name, typeOnly = false) {
|
|
126
|
+
this._cortexImports.add(name, typeOnly);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
/** Add a named import from any other module. */ addImport(name, from, typeOnly = false) {
|
|
130
|
+
const group = this._extraImportGroups.get(from) ?? new ImportGroup();
|
|
131
|
+
group.add(name, typeOnly);
|
|
132
|
+
this._extraImportGroups.set(from, group);
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
/** Add a constructor parameter (e.g. an injected dependency). */ addConstructorParam(param) {
|
|
136
|
+
this._ctorParams.push(param);
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
files() {
|
|
140
|
+
const lines = [
|
|
141
|
+
this._cortexImports.render("@decohere/cortex"),
|
|
142
|
+
'import { SampleService } from "../sample.service.js";'
|
|
143
|
+
];
|
|
144
|
+
for (const [from, group] of this._extraImportGroups){
|
|
145
|
+
lines.push(group.render(from));
|
|
146
|
+
}
|
|
147
|
+
lines.push("", "class HelloBody {", '\t@Field("body", "message")', "\tpublic message!: string;", "}", "");
|
|
148
|
+
for (const d of this._classDecorators){
|
|
149
|
+
lines.push(d);
|
|
150
|
+
}
|
|
151
|
+
lines.push('@Controller({ prefix: "/hello" })', "export class HelloController {", "");
|
|
152
|
+
lines.push("\tpublic constructor(");
|
|
153
|
+
for (const p of this._ctorParams){
|
|
154
|
+
lines.push(`\t\t${p},`);
|
|
155
|
+
}
|
|
156
|
+
lines.push("\t) {}");
|
|
157
|
+
lines.push("");
|
|
158
|
+
for (const method of this._methods.values()){
|
|
159
|
+
lines.push(...method.render(), "");
|
|
160
|
+
}
|
|
161
|
+
lines.push("}", "");
|
|
162
|
+
return [
|
|
163
|
+
{
|
|
164
|
+
filePath: "src/controllers/hello.controller.ts",
|
|
165
|
+
content: lines.join("\n")
|
|
166
|
+
}
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL21vZGVscy9jb250cm9sbGVyLXNvdXJjZS1maWxlLm1vZGVsLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFdFTExfS05PV05fRklMRVMgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL2NvbnN0LmpzXCI7XG5pbXBvcnQgdHlwZSB7IEtleWVkTW9kZWwsIFNvdXJjZUZpbGUgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3NvdXJjZS1maWxlLmpzXCI7XG5cbi8qKiBUcmFja3MgbmFtZWQgaW1wb3J0cyBmcm9tIGEgc2luZ2xlIG1vZHVsZSBwYXRoLCBzcGxpdCBpbnRvIHZhbHVlcyBhbmQgdHlwZXMuICovXG5jbGFzcyBJbXBvcnRHcm91cCB7XG5cdHByaXZhdGUgcmVhZG9ubHkgX3ZhbHVlczogc3RyaW5nW10gPSBbXTtcblx0cHJpdmF0ZSByZWFkb25seSBfdHlwZXM6IHN0cmluZ1tdID0gW107XG5cblx0cHVibGljIGFkZChuYW1lOiBzdHJpbmcsIHR5cGVPbmx5ID0gZmFsc2UpOiB0aGlzIHtcblx0XHRpZiAodHlwZU9ubHkpIHtcblx0XHRcdC8vIFZhbHVlIGltcG9ydCBhbHJlYWR5IHByZXNlbnQg4oCUIHZhbHVlIHdpbnMsIHNraXBcblx0XHRcdGlmICghdGhpcy5fdmFsdWVzLmluY2x1ZGVzKG5hbWUpICYmICF0aGlzLl90eXBlcy5pbmNsdWRlcyhuYW1lKSkge1xuXHRcdFx0XHR0aGlzLl90eXBlcy5wdXNoKG5hbWUpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBQcm9tb3RlOiByZW1vdmUgZnJvbSB0eXBlcyBpZiBpdCB3YXMgcHJldmlvdXNseSB0eXBlLW9ubHlcblx0XHRcdGNvbnN0IHR5cGVJZHggPSB0aGlzLl90eXBlcy5pbmRleE9mKG5hbWUpO1xuXHRcdFx0aWYgKHR5cGVJZHggIT09IC0xKSB0aGlzLl90eXBlcy5zcGxpY2UodHlwZUlkeCwgMSk7XG5cdFx0XHRpZiAoIXRoaXMuX3ZhbHVlcy5pbmNsdWRlcyhuYW1lKSkgdGhpcy5fdmFsdWVzLnB1c2gobmFtZSk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIHJlbmRlcihmcm9tOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRcdGNvbnN0IHZhbHVlcyA9IFsuLi50aGlzLl92YWx1ZXNdLnNvcnQoKTtcblx0XHRjb25zdCB0eXBlcyA9IFsuLi50aGlzLl90eXBlc10uc29ydCgpLm1hcCgobikgPT4gYHR5cGUgJHtufWApO1xuXHRcdHJldHVybiBgaW1wb3J0IHsgJHtbLi4udmFsdWVzLCAuLi50eXBlc10uam9pbihcIiwgXCIpfSB9IGZyb20gXCIke2Zyb219XCI7YDtcblx0fVxufVxuXG4vKipcbiAqIEEgY29udHJvbGxlciBtZXRob2QuIEZlYXR1cmVzIGNhbGwgYGFkZERlY29yYXRvcigpYCB0byBwcmVwZW5kIGRlY29yYXRvcnNcbiAqIGJlZm9yZSB0aGUgSFRUUCB2ZXJiIGRlY29yYXRvciAoZS5nLiBgQEFsbG93QW5vbnltb3VzYCBiZWZvcmUgYEBHZXQoKWApLlxuICovXG5leHBvcnQgY2xhc3MgQ29udHJvbGxlck1ldGhvZCB7XG5cdHByaXZhdGUgcmVhZG9ubHkgX2V4dHJhRGVjb3JhdG9yczogc3RyaW5nW10gPSBbXTtcblxuXHRwdWJsaWMgY29uc3RydWN0b3IoXG5cdFx0cHVibGljIHJlYWRvbmx5IG5hbWU6IHN0cmluZyxcblx0XHRwcml2YXRlIHJlYWRvbmx5IF9odHRwRGVjb3JhdG9yOiBzdHJpbmcsXG5cdFx0cHJpdmF0ZSByZWFkb25seSBfcGFyYW1zOiBzdHJpbmcsXG5cdFx0cHJpdmF0ZSByZWFkb25seSBfaXNBc3luYzogYm9vbGVhbixcblx0XHRwcml2YXRlIHJlYWRvbmx5IF9ib2R5OiBzdHJpbmdbXSxcblx0KSB7fVxuXG5cdHB1YmxpYyBhZGREZWNvcmF0b3IoZGVjb3JhdG9yOiBzdHJpbmcpOiB0aGlzIHtcblx0XHR0aGlzLl9leHRyYURlY29yYXRvcnMucHVzaChkZWNvcmF0b3IpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIHJlbmRlcigpOiBzdHJpbmdbXSB7XG5cdFx0Y29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cdFx0Zm9yIChjb25zdCBkIG9mIHRoaXMuX2V4dHJhRGVjb3JhdG9ycykge1xuXHRcdFx0bGluZXMucHVzaChgXFx0JHtkfWApO1xuXHRcdH1cblx0XHRsaW5lcy5wdXNoKGBcXHQke3RoaXMuX2h0dHBEZWNvcmF0b3J9YCk7XG5cdFx0Y29uc3QgYXN5bmNLdyA9IHRoaXMuX2lzQXN5bmMgPyBcImFzeW5jIFwiIDogXCJcIjtcblx0XHRsaW5lcy5wdXNoKGBcXHRwdWJsaWMgJHthc3luY0t3fSR7dGhpcy5uYW1lfSgke3RoaXMuX3BhcmFtc30pIHtgKTtcblx0XHRmb3IgKGNvbnN0IGxpbmUgb2YgdGhpcy5fYm9keSkge1xuXHRcdFx0bGluZXMucHVzaChgXFx0XFx0JHtsaW5lfWApO1xuXHRcdH1cblx0XHRsaW5lcy5wdXNoKFwiXFx0fVwiKTtcblx0XHRyZXR1cm4gbGluZXM7XG5cdH1cbn1cblxuLyoqXG4gKiBNb2RlbCBmb3IgYHByb2plY3RzL2FwaS9zcmMvY29udHJvbGxlcnMvaGVsbG8uY29udHJvbGxlci50c2AuXG4gKlxuICogUHJlLWluaXRpYWxpc2VkIHdpdGggYWxsIHJvdXRlcyBhbmQgdGhlaXIgSFRUUCBkZWNvcmF0b3JzLiBGZWF0dXJlcyBtdXRhdGVcbiAqIHRoZSBtb2RlbCB2aWEgYGdldE1ldGhvZChuYW1lKS5hZGREZWNvcmF0b3IoLi4uKWAsIGBhZGREZWNvcmF0b3IoLi4uKWAgKGNsYXNzXG4gKiBsZXZlbCksIGBhZGRDb3J0ZXhJbXBvcnQoLi4uKWAsIGBhZGRJbXBvcnQoLi4uKWAsIGFuZCBgYWRkQ29uc3RydWN0b3JQYXJhbSguLi4pYC5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbnRyb2xsZXJTb3VyY2VGaWxlIGltcGxlbWVudHMgS2V5ZWRNb2RlbCB7XG5cdHB1YmxpYyByZWFkb25seSBrZXkgPSBXRUxMX0tOT1dOX0ZJTEVTLkNPTlRST0xMRVJfVFM7XG5cblx0cHJpdmF0ZSByZWFkb25seSBfY29ydGV4SW1wb3J0cyA9IG5ldyBJbXBvcnRHcm91cCgpXG5cdFx0LmFkZChcIkNvbnRyb2xsZXJcIilcblx0XHQuYWRkKFwiRGVsZXRlXCIpXG5cdFx0LmFkZChcIkZpZWxkXCIpXG5cdFx0LmFkZChcIkdldFwiKVxuXHRcdC5hZGQoXCJQYXJhbVwiKVxuXHRcdC5hZGQoXCJQb3N0XCIpXG5cdFx0LmFkZChcIlB1dFwiKVxuXHRcdC5hZGQoXCJRdWVyeVwiKTtcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9leHRyYUltcG9ydEdyb3VwcyA9IG5ldyBNYXA8c3RyaW5nLCBJbXBvcnRHcm91cD4oKTtcblx0cHJpdmF0ZSByZWFkb25seSBfY2xhc3NEZWNvcmF0b3JzOiBzdHJpbmdbXSA9IFtdO1xuXHRwcml2YXRlIHJlYWRvbmx5IF9jdG9yUGFyYW1zOiBzdHJpbmdbXSA9IFtcInByaXZhdGUgcmVhZG9ubHkgc2FtcGxlOiBTYW1wbGVTZXJ2aWNlXCJdO1xuXG5cdHByaXZhdGUgcmVhZG9ubHkgX21ldGhvZHMgPSBuZXcgTWFwPHN0cmluZywgQ29udHJvbGxlck1ldGhvZD4oW1xuXHRcdFtcblx0XHRcdFwiZ2V0QWxsXCIsXG5cdFx0XHRuZXcgQ29udHJvbGxlck1ldGhvZChcImdldEFsbFwiLCBcIkBHZXQoKVwiLCAnQFF1ZXJ5KFwiZmlsdGVyXCIpIGZpbHRlcjogc3RyaW5nJywgdHJ1ZSwgW1xuXHRcdFx0XHRcImNvbnN0IGdyZWV0aW5nID0gYXdhaXQgdGhpcy5zYW1wbGUuZ2V0R3JlZXRpbmcoKTtcIixcblx0XHRcdFx0XCJyZXR1cm4geyBmaWx0ZXIsIG1lc3NhZ2U6IGdyZWV0aW5nIH07XCIsXG5cdFx0XHRdKSxcblx0XHRdLFxuXHRcdFtcblx0XHRcdFwiZ2V0T25lXCIsXG5cdFx0XHRuZXcgQ29udHJvbGxlck1ldGhvZChcblx0XHRcdFx0XCJnZXRPbmVcIixcblx0XHRcdFx0J0BHZXQoXCIvOmlkXCIpJyxcblx0XHRcdFx0J0BQYXJhbShcImlkXCIpIGlkOiBzdHJpbmcnLFxuXHRcdFx0XHRmYWxzZSxcblx0XHRcdFx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub1RlbXBsYXRlQ3VybHlJblN0cmluZzogdGVtcGxhdGUgbGl0ZXJhbCBpbiBnZW5lcmF0ZWQgY29kZVxuXHRcdFx0XHRbXCJyZXR1cm4geyBpZCwgbWVzc2FnZTogYEhlbGxvICR7aWR9IWAgfTtcIl0sXG5cdFx0XHQpLFxuXHRcdF0sXG5cdFx0W1xuXHRcdFx0XCJjcmVhdGVcIixcblx0XHRcdG5ldyBDb250cm9sbGVyTWV0aG9kKFwiY3JlYXRlXCIsICdAUG9zdChcIi9cIiknLCBcImJvZHk6IEhlbGxvQm9keVwiLCBmYWxzZSwgW1xuXHRcdFx0XHRcInJldHVybiB7IG1lc3NhZ2U6IGJvZHkubWVzc2FnZSB9O1wiLFxuXHRcdFx0XSksXG5cdFx0XSxcblx0XHRbXG5cdFx0XHRcInVwZGF0ZVwiLFxuXHRcdFx0bmV3IENvbnRyb2xsZXJNZXRob2QoXG5cdFx0XHRcdFwidXBkYXRlXCIsXG5cdFx0XHRcdCdAUHV0KFwiLzppZFwiKScsXG5cdFx0XHRcdCdAUGFyYW0oXCJpZFwiKSBpZDogc3RyaW5nLCBib2R5OiBIZWxsb0JvZHknLFxuXHRcdFx0XHRmYWxzZSxcblx0XHRcdFx0W1wicmV0dXJuIHsgaWQsIG1lc3NhZ2U6IGJvZHkubWVzc2FnZSB9O1wiXSxcblx0XHRcdCksXG5cdFx0XSxcblx0XHRbXG5cdFx0XHRcInJlbW92ZVwiLFxuXHRcdFx0bmV3IENvbnRyb2xsZXJNZXRob2QoXCJyZW1vdmVcIiwgJ0BEZWxldGUoXCIvOmlkXCIpJywgJ0BQYXJhbShcImlkXCIpIGlkOiBzdHJpbmcnLCBmYWxzZSwgW1xuXHRcdFx0XHRcInJldHVybiB7IGlkLCBkZWxldGVkOiB0cnVlIH07XCIsXG5cdFx0XHRdKSxcblx0XHRdLFxuXHRdKTtcblxuXHQvKiogUmV0cmlldmUgYSBtZXRob2QgYnkgbmFtZSB0byBtdXRhdGUgaXRzIGRlY29yYXRvcnMuICovXG5cdHB1YmxpYyBnZXRNZXRob2QobmFtZTogc3RyaW5nKTogQ29udHJvbGxlck1ldGhvZCB7XG5cdFx0Y29uc3QgbSA9IHRoaXMuX21ldGhvZHMuZ2V0KG5hbWUpO1xuXHRcdGlmIChtID09IG51bGwpIHRocm93IG5ldyBFcnJvcihgTm8gbWV0aG9kICcke25hbWV9JyBvbiBDb250cm9sbGVyU291cmNlRmlsZWApO1xuXHRcdHJldHVybiBtO1xuXHR9XG5cblx0LyoqIEFkZCBhIGNsYXNzLWxldmVsIGRlY29yYXRvciAoZS5nLiBgQEF1dGhvcml6ZWApLiAqL1xuXHRwdWJsaWMgYWRkRGVjb3JhdG9yKGRlY29yYXRvcjogc3RyaW5nKTogdGhpcyB7XG5cdFx0dGhpcy5fY2xhc3NEZWNvcmF0b3JzLnB1c2goZGVjb3JhdG9yKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKiBBZGQgYSBuYW1lZCBpbXBvcnQgZnJvbSBgQGRlY29oZXJlL2NvcnRleGAuICovXG5cdHB1YmxpYyBhZGRDb3J0ZXhJbXBvcnQobmFtZTogc3RyaW5nLCB0eXBlT25seSA9IGZhbHNlKTogdGhpcyB7XG5cdFx0dGhpcy5fY29ydGV4SW1wb3J0cy5hZGQobmFtZSwgdHlwZU9ubHkpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqIEFkZCBhIG5hbWVkIGltcG9ydCBmcm9tIGFueSBvdGhlciBtb2R1bGUuICovXG5cdHB1YmxpYyBhZGRJbXBvcnQobmFtZTogc3RyaW5nLCBmcm9tOiBzdHJpbmcsIHR5cGVPbmx5ID0gZmFsc2UpOiB0aGlzIHtcblx0XHRjb25zdCBncm91cCA9IHRoaXMuX2V4dHJhSW1wb3J0R3JvdXBzLmdldChmcm9tKSA/PyBuZXcgSW1wb3J0R3JvdXAoKTtcblx0XHRncm91cC5hZGQobmFtZSwgdHlwZU9ubHkpO1xuXHRcdHRoaXMuX2V4dHJhSW1wb3J0R3JvdXBzLnNldChmcm9tLCBncm91cCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKiogQWRkIGEgY29uc3RydWN0b3IgcGFyYW1ldGVyIChlLmcuIGFuIGluamVjdGVkIGRlcGVuZGVuY3kpLiAqL1xuXHRwdWJsaWMgYWRkQ29uc3RydWN0b3JQYXJhbShwYXJhbTogc3RyaW5nKTogdGhpcyB7XG5cdFx0dGhpcy5fY3RvclBhcmFtcy5wdXNoKHBhcmFtKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHB1YmxpYyBmaWxlcygpOiBTb3VyY2VGaWxlW10ge1xuXHRcdGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtcblx0XHRcdHRoaXMuX2NvcnRleEltcG9ydHMucmVuZGVyKFwiQGRlY29oZXJlL2NvcnRleFwiKSxcblx0XHRcdCdpbXBvcnQgeyBTYW1wbGVTZXJ2aWNlIH0gZnJvbSBcIi4uL3NhbXBsZS5zZXJ2aWNlLmpzXCI7Jyxcblx0XHRdO1xuXG5cdFx0Zm9yIChjb25zdCBbZnJvbSwgZ3JvdXBdIG9mIHRoaXMuX2V4dHJhSW1wb3J0R3JvdXBzKSB7XG5cdFx0XHRsaW5lcy5wdXNoKGdyb3VwLnJlbmRlcihmcm9tKSk7XG5cdFx0fVxuXG5cdFx0bGluZXMucHVzaChcblx0XHRcdFwiXCIsXG5cdFx0XHRcImNsYXNzIEhlbGxvQm9keSB7XCIsXG5cdFx0XHQnXFx0QEZpZWxkKFwiYm9keVwiLCBcIm1lc3NhZ2VcIiknLFxuXHRcdFx0XCJcXHRwdWJsaWMgbWVzc2FnZSE6IHN0cmluZztcIixcblx0XHRcdFwifVwiLFxuXHRcdFx0XCJcIixcblx0XHQpO1xuXG5cdFx0Zm9yIChjb25zdCBkIG9mIHRoaXMuX2NsYXNzRGVjb3JhdG9ycykge1xuXHRcdFx0bGluZXMucHVzaChkKTtcblx0XHR9XG5cdFx0bGluZXMucHVzaCgnQENvbnRyb2xsZXIoeyBwcmVmaXg6IFwiL2hlbGxvXCIgfSknLCBcImV4cG9ydCBjbGFzcyBIZWxsb0NvbnRyb2xsZXIge1wiLCBcIlwiKTtcblxuXHRcdGxpbmVzLnB1c2goXCJcXHRwdWJsaWMgY29uc3RydWN0b3IoXCIpO1xuXHRcdGZvciAoY29uc3QgcCBvZiB0aGlzLl9jdG9yUGFyYW1zKSB7XG5cdFx0XHRsaW5lcy5wdXNoKGBcXHRcXHQke3B9LGApO1xuXHRcdH1cblx0XHRsaW5lcy5wdXNoKFwiXFx0KSB7fVwiKTtcblx0XHRsaW5lcy5wdXNoKFwiXCIpO1xuXG5cdFx0Zm9yIChjb25zdCBtZXRob2Qgb2YgdGhpcy5fbWV0aG9kcy52YWx1ZXMoKSkge1xuXHRcdFx0bGluZXMucHVzaCguLi5tZXRob2QucmVuZGVyKCksIFwiXCIpO1xuXHRcdH1cblxuXHRcdGxpbmVzLnB1c2goXCJ9XCIsIFwiXCIpO1xuXG5cdFx0cmV0dXJuIFtcblx0XHRcdHtcblx0XHRcdFx0ZmlsZVBhdGg6IFwic3JjL2NvbnRyb2xsZXJzL2hlbGxvLmNvbnRyb2xsZXIudHNcIixcblx0XHRcdFx0Y29udGVudDogbGluZXMuam9pbihcIlxcblwiKSxcblx0XHRcdH0sXG5cdFx0XTtcblx0fVxufVxuIl0sIm5hbWVzIjpbIldFTExfS05PV05fRklMRVMiLCJJbXBvcnRHcm91cCIsIl92YWx1ZXMiLCJfdHlwZXMiLCJhZGQiLCJuYW1lIiwidHlwZU9ubHkiLCJpbmNsdWRlcyIsInB1c2giLCJ0eXBlSWR4IiwiaW5kZXhPZiIsInNwbGljZSIsInJlbmRlciIsImZyb20iLCJ2YWx1ZXMiLCJzb3J0IiwidHlwZXMiLCJtYXAiLCJuIiwiam9pbiIsIkNvbnRyb2xsZXJNZXRob2QiLCJfZXh0cmFEZWNvcmF0b3JzIiwiX2h0dHBEZWNvcmF0b3IiLCJfcGFyYW1zIiwiX2lzQXN5bmMiLCJfYm9keSIsImFkZERlY29yYXRvciIsImRlY29yYXRvciIsImxpbmVzIiwiZCIsImFzeW5jS3ciLCJsaW5lIiwiQ29udHJvbGxlclNvdXJjZUZpbGUiLCJrZXkiLCJDT05UUk9MTEVSX1RTIiwiX2NvcnRleEltcG9ydHMiLCJfZXh0cmFJbXBvcnRHcm91cHMiLCJNYXAiLCJfY2xhc3NEZWNvcmF0b3JzIiwiX2N0b3JQYXJhbXMiLCJfbWV0aG9kcyIsImdldE1ldGhvZCIsIm0iLCJnZXQiLCJFcnJvciIsImFkZENvcnRleEltcG9ydCIsImFkZEltcG9ydCIsImdyb3VwIiwic2V0IiwiYWRkQ29uc3RydWN0b3JQYXJhbSIsInBhcmFtIiwiZmlsZXMiLCJwIiwibWV0aG9kIiwiZmlsZVBhdGgiLCJjb250ZW50Il0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxnQkFBZ0IsUUFBUSx3QkFBd0I7QUFHekQsaUZBQWlGLEdBQ2pGLE1BQU1DO0lBQ1lDLFVBQW9CLEVBQUUsQ0FBQztJQUN2QkMsU0FBbUIsRUFBRSxDQUFDO0lBRWhDQyxJQUFJQyxJQUFZLEVBQUVDLFdBQVcsS0FBSyxFQUFRO1FBQ2hELElBQUlBLFVBQVU7WUFDYixrREFBa0Q7WUFDbEQsSUFBSSxDQUFDLElBQUksQ0FBQ0osT0FBTyxDQUFDSyxRQUFRLENBQUNGLFNBQVMsQ0FBQyxJQUFJLENBQUNGLE1BQU0sQ0FBQ0ksUUFBUSxDQUFDRixPQUFPO2dCQUNoRSxJQUFJLENBQUNGLE1BQU0sQ0FBQ0ssSUFBSSxDQUFDSDtZQUNsQjtRQUNELE9BQU87WUFDTiw0REFBNEQ7WUFDNUQsTUFBTUksVUFBVSxJQUFJLENBQUNOLE1BQU0sQ0FBQ08sT0FBTyxDQUFDTDtZQUNwQyxJQUFJSSxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUNOLE1BQU0sQ0FBQ1EsTUFBTSxDQUFDRixTQUFTO1lBQ2hELElBQUksQ0FBQyxJQUFJLENBQUNQLE9BQU8sQ0FBQ0ssUUFBUSxDQUFDRixPQUFPLElBQUksQ0FBQ0gsT0FBTyxDQUFDTSxJQUFJLENBQUNIO1FBQ3JEO1FBQ0EsT0FBTyxJQUFJO0lBQ1o7SUFFT08sT0FBT0MsSUFBWSxFQUFVO1FBQ25DLE1BQU1DLFNBQVM7ZUFBSSxJQUFJLENBQUNaLE9BQU87U0FBQyxDQUFDYSxJQUFJO1FBQ3JDLE1BQU1DLFFBQVE7ZUFBSSxJQUFJLENBQUNiLE1BQU07U0FBQyxDQUFDWSxJQUFJLEdBQUdFLEdBQUcsQ0FBQyxDQUFDQyxJQUFNLENBQUMsS0FB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
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { WELL_KNOWN_FILES } from "../../models/const.js";
|
|
2
|
+
/** Tracks named imports from a single module path, split into values and types. */ class ImportGroup {
|
|
3
|
+
_values = [];
|
|
4
|
+
_types = [];
|
|
5
|
+
add(name, typeOnly = false) {
|
|
6
|
+
if (typeOnly) {
|
|
7
|
+
// Value import already present — value wins, skip
|
|
8
|
+
if (!this._values.includes(name) && !this._types.includes(name)) {
|
|
9
|
+
this._types.push(name);
|
|
10
|
+
}
|
|
11
|
+
} else {
|
|
12
|
+
// Promote: remove from types if it was previously type-only
|
|
13
|
+
const typeIdx = this._types.indexOf(name);
|
|
14
|
+
if (typeIdx !== -1) this._types.splice(typeIdx, 1);
|
|
15
|
+
if (!this._values.includes(name)) this._values.push(name);
|
|
16
|
+
}
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
render(from) {
|
|
20
|
+
const values = [
|
|
21
|
+
...this._values
|
|
22
|
+
].sort();
|
|
23
|
+
const types = [
|
|
24
|
+
...this._types
|
|
25
|
+
].sort().map((n)=>`type ${n}`);
|
|
26
|
+
return `import { ${[
|
|
27
|
+
...values,
|
|
28
|
+
...types
|
|
29
|
+
].join(", ")} } from "${from}";`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Model for `projects/api/src/main.ts`.
|
|
34
|
+
*
|
|
35
|
+
* Starts with the minimal HTTP + YAML config setup. Features mutate the model
|
|
36
|
+
* by calling addSideEffectImport / addImport / addBuilderCall / addEntity /
|
|
37
|
+
* addRepository. files() renders whatever has been accumulated.
|
|
38
|
+
*/ export class MainSourceFile {
|
|
39
|
+
appName;
|
|
40
|
+
key = WELL_KNOWN_FILES.MAIN_TS;
|
|
41
|
+
_sideEffectImports = [];
|
|
42
|
+
_extraImports = new Map();
|
|
43
|
+
_builderCalls = [];
|
|
44
|
+
_entities = [];
|
|
45
|
+
_repositories = [];
|
|
46
|
+
constructor(appName){
|
|
47
|
+
this.appName = appName;
|
|
48
|
+
}
|
|
49
|
+
/** Adds a bare side-effect import, e.g. `@decohere/cortex/auth`. */ addSideEffectImport(path) {
|
|
50
|
+
if (!this._sideEffectImports.includes(path)) this._sideEffectImports.push(path);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/** Adds a named import, e.g. `import { Foo } from "bar"`. */ addImport(name, from, typeOnly = false) {
|
|
54
|
+
const group = this._extraImports.get(from) ?? new ImportGroup();
|
|
55
|
+
group.add(name, typeOnly);
|
|
56
|
+
this._extraImports.set(from, group);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Adds a builder call inserted after `.withConfiguration()` and before
|
|
61
|
+
* `.withServices()`. Pass the call without leading dot, e.g. `.withAuth()`.
|
|
62
|
+
*/ addBuilderCall(call) {
|
|
63
|
+
this._builderCalls.push(call);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/** Adds a TypeORM entity — import and entry in `withTypeOrm({ entities })`. */ addEntity(entity) {
|
|
67
|
+
this._entities.push(entity);
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
/** Adds a TypeORM repository — import and entry in `withTypeOrm({ repositories })`. */ addRepository(repo) {
|
|
71
|
+
this._repositories.push(repo);
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
files() {
|
|
75
|
+
const imports = [
|
|
76
|
+
'import "@decohere/scribe-pino";',
|
|
77
|
+
'import "@decohere/cortex/http";'
|
|
78
|
+
];
|
|
79
|
+
for (const path of this._sideEffectImports){
|
|
80
|
+
imports.push(`import "${path}";`);
|
|
81
|
+
}
|
|
82
|
+
imports.push('import "@decohere/protocol";', 'import { YamlDataSource } from "@decohere/protocol";', 'import { Builder } from "@decohere/cortex";', 'import { FastifyProvider } from "@decohere/cortex/providers";', 'import { scribe } from "@decohere/scribe";', 'import { SampleService } from "./services/sample.service.js";');
|
|
83
|
+
for (const e of this._entities){
|
|
84
|
+
imports.push(`import { ${e.className} } from "${e.importPath}";`);
|
|
85
|
+
}
|
|
86
|
+
for (const r of this._repositories){
|
|
87
|
+
imports.push(`import { ${r.className} } from "${r.importPath}";`);
|
|
88
|
+
}
|
|
89
|
+
for (const [from, group] of this._extraImports){
|
|
90
|
+
imports.push(group.render(from));
|
|
91
|
+
}
|
|
92
|
+
imports.push('import { HelloController } from "./controllers/hello.controller.js";');
|
|
93
|
+
const builderCalls = [
|
|
94
|
+
`\t.withHttpProvider(FastifyProvider)`,
|
|
95
|
+
`\t.withConfiguration(YamlDataSource)`,
|
|
96
|
+
...this._builderCalls.map((c)=>`\t${c}`),
|
|
97
|
+
`\t.withServices((cb) => { cb.registerSingleton(SampleService); })`
|
|
98
|
+
];
|
|
99
|
+
if (this._entities.length > 0) {
|
|
100
|
+
const entities = this._entities.map((e)=>e.className).join(", ");
|
|
101
|
+
const repos = this._repositories.map((r)=>r.className).join(", ");
|
|
102
|
+
builderCalls.push(`\t.withTypeOrm({ entities: [${entities}], repositories: [${repos}] })`);
|
|
103
|
+
}
|
|
104
|
+
builderCalls.push(`\t.withControllers(HelloController)`);
|
|
105
|
+
const content = [
|
|
106
|
+
...imports,
|
|
107
|
+
"",
|
|
108
|
+
"scribe.extend.withPinoPretty();",
|
|
109
|
+
"",
|
|
110
|
+
`const app = await Builder.create({ applicationName: "${this.appName}" })`,
|
|
111
|
+
...builderCalls,
|
|
112
|
+
`\t.build();`,
|
|
113
|
+
"",
|
|
114
|
+
"await app.start({ port: 3000 });",
|
|
115
|
+
"",
|
|
116
|
+
"export default app;",
|
|
117
|
+
""
|
|
118
|
+
].join("\n");
|
|
119
|
+
return [
|
|
120
|
+
{
|
|
121
|
+
filePath: "src/main.ts",
|
|
122
|
+
content
|
|
123
|
+
}
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL21vZGVscy9tYWluLXNvdXJjZS1maWxlLm1vZGVsLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFdFTExfS05PV05fRklMRVMgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL2NvbnN0LmpzXCI7XG5pbXBvcnQgdHlwZSB7IEtleWVkTW9kZWwsIFNvdXJjZUZpbGUgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3NvdXJjZS1maWxlLmpzXCI7XG5cbmV4cG9ydCB0eXBlIFR5cGVPcm1JbXBvcnQgPSB7IGNsYXNzTmFtZTogc3RyaW5nOyBpbXBvcnRQYXRoOiBzdHJpbmcgfTtcblxuLyoqIFRyYWNrcyBuYW1lZCBpbXBvcnRzIGZyb20gYSBzaW5nbGUgbW9kdWxlIHBhdGgsIHNwbGl0IGludG8gdmFsdWVzIGFuZCB0eXBlcy4gKi9cbmNsYXNzIEltcG9ydEdyb3VwIHtcblx0cHJpdmF0ZSByZWFkb25seSBfdmFsdWVzOiBzdHJpbmdbXSA9IFtdO1xuXHRwcml2YXRlIHJlYWRvbmx5IF90eXBlczogc3RyaW5nW10gPSBbXTtcblxuXHRwdWJsaWMgYWRkKG5hbWU6IHN0cmluZywgdHlwZU9ubHkgPSBmYWxzZSk6IHRoaXMge1xuXHRcdGlmICh0eXBlT25seSkge1xuXHRcdFx0Ly8gVmFsdWUgaW1wb3J0IGFscmVhZHkgcHJlc2VudCDigJQgdmFsdWUgd2lucywgc2tpcFxuXHRcdFx0aWYgKCF0aGlzLl92YWx1ZXMuaW5jbHVkZXMobmFtZSkgJiYgIXRoaXMuX3R5cGVzLmluY2x1ZGVzKG5hbWUpKSB7XG5cdFx0XHRcdHRoaXMuX3R5cGVzLnB1c2gobmFtZSk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIFByb21vdGU6IHJlbW92ZSBmcm9tIHR5cGVzIGlmIGl0IHdhcyBwcmV2aW91c2x5IHR5cGUtb25seVxuXHRcdFx0Y29uc3QgdHlwZUlkeCA9IHRoaXMuX3R5cGVzLmluZGV4T2YobmFtZSk7XG5cdFx0XHRpZiAodHlwZUlkeCAhPT0gLTEpIHRoaXMuX3R5cGVzLnNwbGljZSh0eXBlSWR4LCAxKTtcblx0XHRcdGlmICghdGhpcy5fdmFsdWVzLmluY2x1ZGVzKG5hbWUpKSB0aGlzLl92YWx1ZXMucHVzaChuYW1lKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRwdWJsaWMgcmVuZGVyKGZyb206IHN0cmluZyk6IHN0cmluZyB7XG5cdFx0Y29uc3QgdmFsdWVzID0gWy4uLnRoaXMuX3ZhbHVlc10uc29ydCgpO1xuXHRcdGNvbnN0IHR5cGVzID0gWy4uLnRoaXMuX3R5cGVzXS5zb3J0KCkubWFwKChuKSA9PiBgdHlwZSAke259YCk7XG5cdFx0cmV0dXJuIGBpbXBvcnQgeyAke1suLi52YWx1ZXMsIC4uLnR5cGVzXS5qb2luKFwiLCBcIil9IH0gZnJvbSBcIiR7ZnJvbX1cIjtgO1xuXHR9XG59XG5cbi8qKlxuICogTW9kZWwgZm9yIGBwcm9qZWN0cy9hcGkvc3JjL21haW4udHNgLlxuICpcbiAqIFN0YXJ0cyB3aXRoIHRoZSBtaW5pbWFsIEhUVFAgKyBZQU1MIGNvbmZpZyBzZXR1cC4gRmVhdHVyZXMgbXV0YXRlIHRoZSBtb2RlbFxuICogYnkgY2FsbGluZyBhZGRTaWRlRWZmZWN0SW1wb3J0IC8gYWRkSW1wb3J0IC8gYWRkQnVpbGRlckNhbGwgLyBhZGRFbnRpdHkgL1xuICogYWRkUmVwb3NpdG9yeS4gZmlsZXMoKSByZW5kZXJzIHdoYXRldmVyIGhhcyBiZWVuIGFjY3VtdWxhdGVkLlxuICovXG5leHBvcnQgY2xhc3MgTWFpblNvdXJjZUZpbGUgaW1wbGVtZW50cyBLZXllZE1vZGVsIHtcblx0cHVibGljIHJlYWRvbmx5IGtleSA9IFdFTExfS05PV05fRklMRVMuTUFJTl9UUztcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9zaWRlRWZmZWN0SW1wb3J0czogc3RyaW5nW10gPSBbXTtcblx0cHJpdmF0ZSByZWFkb25seSBfZXh0cmFJbXBvcnRzID0gbmV3IE1hcDxzdHJpbmcsIEltcG9ydEdyb3VwPigpO1xuXHRwcml2YXRlIHJlYWRvbmx5IF9idWlsZGVyQ2FsbHM6IHN0cmluZ1tdID0gW107XG5cdHByaXZhdGUgcmVhZG9ubHkgX2VudGl0aWVzOiBUeXBlT3JtSW1wb3J0W10gPSBbXTtcblx0cHJpdmF0ZSByZWFkb25seSBfcmVwb3NpdG9yaWVzOiBUeXBlT3JtSW1wb3J0W10gPSBbXTtcblxuXHRwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBhcHBOYW1lOiBzdHJpbmcpIHt9XG5cblx0LyoqIEFkZHMgYSBiYXJlIHNpZGUtZWZmZWN0IGltcG9ydCwgZS5nLiBgQGRlY29oZXJlL2NvcnRleC9hdXRoYC4gKi9cblx0cHVibGljIGFkZFNpZGVFZmZlY3RJbXBvcnQocGF0aDogc3RyaW5nKTogdGhpcyB7XG5cdFx0aWYgKCF0aGlzLl9zaWRlRWZmZWN0SW1wb3J0cy5pbmNsdWRlcyhwYXRoKSkgdGhpcy5fc2lkZUVmZmVjdEltcG9ydHMucHVzaChwYXRoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKiBBZGRzIGEgbmFtZWQgaW1wb3J0LCBlLmcuIGBpbXBvcnQgeyBGb28gfSBmcm9tIFwiYmFyXCJgLiAqL1xuXHRwdWJsaWMgYWRkSW1wb3J0KG5hbWU6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0eXBlT25seSA9IGZhbHNlKTogdGhpcyB7XG5cdFx0Y29uc3QgZ3JvdXAgPSB0aGlzLl9leHRyYUltcG9ydHMuZ2V0KGZyb20pID8/IG5ldyBJbXBvcnRHcm91cCgpO1xuXHRcdGdyb3VwLmFkZChuYW1lLCB0eXBlT25seSk7XG5cdFx0dGhpcy5fZXh0cmFJbXBvcnRzLnNldChmcm9tLCBncm91cCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogQWRkcyBhIGJ1aWxkZXIgY2FsbCBpbnNlcnRlZCBhZnRlciBgLndpdGhDb25maWd1cmF0aW9uKClgIGFuZCBiZWZvcmVcblx0ICogYC53aXRoU2VydmljZXMoKWAuIFBhc3MgdGhlIGNhbGwgd2l0aG91dCBsZWFkaW5nIGRvdCwgZS5nLiBgLndpdGhBdXRoKClgLlxuXHQgKi9cblx0cHVibGljIGFkZEJ1aWxkZXJDYWxsKGNhbGw6IHN0cmluZyk6IHRoaXMge1xuXHRcdHRoaXMuX2J1aWxkZXJDYWxscy5wdXNoKGNhbGwpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqIEFkZHMgYSBUeXBlT1JNIGVudGl0eSDigJQgaW1wb3J0IGFuZCBlbnRyeSBpbiBgd2l0aFR5cGVPcm0oeyBlbnRpdGllcyB9KWAuICovXG5cdHB1YmxpYyBhZGRFbnRpdHkoZW50aXR5OiBUeXBlT3JtSW1wb3J0KTogdGhpcyB7XG5cdFx0dGhpcy5fZW50aXRpZXMucHVzaChlbnRpdHkpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqIEFkZHMgYSBUeXBlT1JNIHJlcG9zaXRvcnkg4oCUIGltcG9ydCBhbmQgZW50cnkgaW4gYHdpdGhUeXBlT3JtKHsgcmVwb3NpdG9yaWVzIH0pYC4gKi9cblx0cHVibGljIGFkZFJlcG9zaXRvcnkocmVwbzogVHlwZU9ybUltcG9ydCk6IHRoaXMge1xuXHRcdHRoaXMuX3JlcG9zaXRvcmllcy5wdXNoKHJlcG8pO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIGZpbGVzKCk6IFNvdXJjZUZpbGVbXSB7XG5cdFx0Y29uc3QgaW1wb3J0czogc3RyaW5nW10gPSBbXG5cdFx0XHQnaW1wb3J0IFwiQGRlY29oZXJlL3NjcmliZS1waW5vXCI7Jyxcblx0XHRcdCdpbXBvcnQgXCJAZGVjb2hlcmUvY29ydGV4L2h0dHBcIjsnLFxuXHRcdF07XG5cblx0XHRmb3IgKGNvbnN0IHBhdGggb2YgdGhpcy5fc2lkZUVmZmVjdEltcG9ydHMpIHtcblx0XHRcdGltcG9ydHMucHVzaChgaW1wb3J0IFwiJHtwYXRofVwiO2ApO1xuXHRcdH1cblxuXHRcdGltcG9ydHMucHVzaChcblx0XHRcdCdpbXBvcnQgXCJAZGVjb2hlcmUvcHJvdG9jb2xcIjsnLFxuXHRcdFx0J2ltcG9ydCB7IFlhbWxEYXRhU291cmNlIH0gZnJvbSBcIkBkZWNvaGVyZS9wcm90b2NvbFwiOycsXG5cdFx0XHQnaW1wb3J0IHsgQnVpbGRlciB9IGZyb20gXCJAZGVjb2hlcmUvY29ydGV4XCI7Jyxcblx0XHRcdCdpbXBvcnQgeyBGYXN0aWZ5UHJvdmlkZXIgfSBmcm9tIFwiQGRlY29oZXJlL2NvcnRleC9wcm92aWRlcnNcIjsnLFxuXHRcdFx0J2ltcG9ydCB7IHNjcmliZSB9IGZyb20gXCJAZGVjb2hlcmUvc2NyaWJlXCI7Jyxcblx0XHRcdCdpbXBvcnQgeyBTYW1wbGVTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvc2FtcGxlLnNlcnZpY2UuanNcIjsnLFxuXHRcdCk7XG5cblx0XHRmb3IgKGNvbnN0IGUgb2YgdGhpcy5fZW50aXRpZXMpIHtcblx0XHRcdGltcG9ydHMucHVzaChgaW1wb3J0IHsgJHtlLmNsYXNzTmFtZX0gfSBmcm9tIFwiJHtlLmltcG9ydFBhdGh9XCI7YCk7XG5cdFx0fVxuXG5cdFx0Zm9yIChjb25zdCByIG9mIHRoaXMuX3JlcG9zaXRvcmllcykge1xuXHRcdFx0aW1wb3J0cy5wdXNoKGBpbXBvcnQgeyAke3IuY2xhc3NOYW1lfSB9IGZyb20gXCIke3IuaW1wb3J0UGF0aH1cIjtgKTtcblx0XHR9XG5cblx0XHRmb3IgKGNvbnN0IFtmcm9tLCBncm91cF0gb2YgdGhpcy5fZXh0cmFJbXBvcnRzKSB7XG5cdFx0XHRpbXBvcnRzLnB1c2goZ3JvdXAucmVuZGVyKGZyb20pKTtcblx0XHR9XG5cblx0XHRpbXBvcnRzLnB1c2goJ2ltcG9ydCB7IEhlbGxvQ29udHJvbGxlciB9IGZyb20gXCIuL2NvbnRyb2xsZXJzL2hlbGxvLmNvbnRyb2xsZXIuanNcIjsnKTtcblxuXHRcdGNvbnN0IGJ1aWxkZXJDYWxsczogc3RyaW5nW10gPSBbXG5cdFx0XHRgXFx0LndpdGhIdHRwUHJvdmlkZXIoRmFzdGlmeVByb3ZpZGVyKWAsXG5cdFx0XHRgXFx0LndpdGhDb25maWd1cmF0aW9uKFlhbWxEYXRhU291cmNlKWAsXG5cdFx0XHQuLi50aGlzLl9idWlsZGVyQ2FsbHMubWFwKChjKSA9PiBgXFx0JHtjfWApLFxuXHRcdFx0YFxcdC53aXRoU2VydmljZXMoKGNiKSA9PiB7IGNiLnJlZ2lzdGVyU2luZ2xldG9uKFNhbXBsZVNlcnZpY2UpOyB9KWAsXG5cdFx0XTtcblxuXHRcdGlmICh0aGlzLl9lbnRpdGllcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRjb25zdCBlbnRpdGllcyA9IHRoaXMuX2VudGl0aWVzLm1hcCgoZSkgPT4gZS5jbGFzc05hbWUpLmpvaW4oXCIsIFwiKTtcblx0XHRcdGNvbnN0IHJlcG9zID0gdGhpcy5fcmVwb3NpdG9yaWVzLm1hcCgocikgPT4gci5jbGFzc05hbWUpLmpvaW4oXCIsIFwiKTtcblx0XHRcdGJ1aWxkZXJDYWxscy5wdXNoKFxuXHRcdFx0XHRgXFx0LndpdGhUeXBlT3JtKHsgZW50aXRpZXM6IFske2VudGl0aWVzfV0sIHJlcG9zaXRvcmllczogWyR7cmVwb3N9XSB9KWAsXG5cdFx0XHQpO1xuXHRcdH1cblxuXHRcdGJ1aWxkZXJDYWxscy5wdXNoKGBcXHQud2l0aENvbnRyb2xsZXJzKEhlbGxvQ29udHJvbGxlcilgKTtcblxuXHRcdGNvbnN0IGNvbnRlbnQgPSBbXG5cdFx0XHQuLi5pbXBvcnRzLFxuXHRcdFx0XCJcIixcblx0XHRcdFwic2NyaWJlLmV4dGVuZC53aXRoUGlub1ByZXR0eSgpO1wiLFxuXHRcdFx0XCJcIixcblx0XHRcdGBjb25zdCBhcHAgPSBhd2FpdCBCdWlsZGVyLmNyZWF0ZSh7IGFwcGxpY2F0aW9uTmFtZTogXCIke3RoaXMuYXBwTmFtZX1cIiB9KWAsXG5cdFx0XHQuLi5idWlsZGVyQ2FsbHMsXG5cdFx0XHRgXFx0LmJ1aWxkKCk7YCxcblx0XHRcdFwiXCIsXG5cdFx0XHRcImF3YWl0IGFwcC5zdGFydCh7IHBvcnQ6IDMwMDAgfSk7XCIsXG5cdFx0XHRcIlwiLFxuXHRcdFx0XCJleHBvcnQgZGVmYXVsdCBhcHA7XCIsXG5cdFx0XHRcIlwiLFxuXHRcdF0uam9pbihcIlxcblwiKTtcblxuXHRcdHJldHVybiBbXG5cdFx0XHR7XG5cdFx0XHRcdGZpbGVQYXRoOiBcInNyYy9tYWluLnRzXCIsXG5cdFx0XHRcdGNvbnRlbnQsXG5cdFx0XHR9LFxuXHRcdF07XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJXRUxMX0tOT1dOX0ZJTEVTIiwiSW1wb3J0R3JvdXAiLCJfdmFsdWVzIiwiX3R5cGVzIiwiYWRkIiwibmFtZSIsInR5cGVPbmx5IiwiaW5jbHVkZXMiLCJwdXNoIiwidHlwZUlkeCIsImluZGV4T2YiLCJzcGxpY2UiLCJyZW5kZXIiLCJmcm9tIiwidmFsdWVzIiwic29ydCIsInR5cGVzIiwibWFwIiwibiIsImpvaW4iLCJNYWluU291cmNlRmlsZSIsImtleSIsIk1BSU5fVFMiLCJfc2lkZUVmZmVjdEltcG9ydHMiLCJfZXh0cmFJbXBvcnRzIiwiTWFwIiwiX2J1aWxkZXJDYWxscyIsIl9lbnRpdGllcyIsIl9yZXBvc2l0b3JpZXMiLCJhcHBOYW1lIiwiYWRkU2lkZUVmZmVjdEltcG9ydCIsInBhdGgiLCJhZGRJbXBvcnQiLCJncm91cCIsImdldCIsInNldCIsImFkZEJ1aWxkZXJDYWxsIiwiY2FsbCIsImFkZEVudGl0eSIsImVudGl0eSIsImFkZFJlcG9zaXRvcnkiLCJyZXBvIiwiZmlsZXMiLCJpbXBvcnRzIiwiZSIsImNsYXNzTmFtZSIsImltcG9ydFBhdGgiLCJyIiwiYnVpbGRlckNhbGxzIiwiYyIsImxlbmd0aCIsImVudGl0aWVzIiwicmVwb3MiLCJjb250ZW50IiwiZmlsZVBhdGgiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLGdCQUFnQixRQUFRLHdCQUF3QjtBQUt6RCxpRkFBaUYsR0FDakYsTUFBTUM7SUFDWUMsVUFBb0IsRUFBRSxDQUFDO0lBQ3ZCQyxTQUFtQixFQUFFLENBQUM7SUFFaENDLElBQUlDLElBQVksRUFBRUMsV0FBVyxLQUFLLEVBQVE7UUFDaEQsSUFBSUEsVUFBVTtZQUNi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
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const SAMPLE_CONFIG_CONTENT = `export class SampleConfig {\n\tpublic greeting: string = "";\n}\n`;
|
|
2
|
+
const SAMPLE_SERVICE_CONTENT = [
|
|
3
|
+
`import { inject, injectable } from "@decohere/crucible/decorators";`,
|
|
4
|
+
`import { ConfigurationServiceToken } from "@decohere/nexus/configuration";`,
|
|
5
|
+
`import type { IConfigurationService } from "@decohere/nexus/configuration";`,
|
|
6
|
+
`import { SampleConfig } from "../sample.config.js";`,
|
|
7
|
+
``,
|
|
8
|
+
`@injectable()`,
|
|
9
|
+
`export class SampleService {`,
|
|
10
|
+
`\tpublic constructor(`,
|
|
11
|
+
`\t\t@inject(ConfigurationServiceToken) private readonly config: IConfigurationService,`,
|
|
12
|
+
`\t) {}`,
|
|
13
|
+
``,
|
|
14
|
+
`\tpublic async getGreeting(): Promise<string> {`,
|
|
15
|
+
`\t\tconst config = await this.config.get(SampleConfig);`,
|
|
16
|
+
`\t\treturn config.greeting;`,
|
|
17
|
+
`\t}`,
|
|
18
|
+
`}`,
|
|
19
|
+
``
|
|
20
|
+
].join("\n");
|
|
21
|
+
export class SampleConfigModel {
|
|
22
|
+
files() {
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
filePath: "src/sample.config.ts",
|
|
26
|
+
content: SAMPLE_CONFIG_CONTENT
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class SampleServiceModel {
|
|
32
|
+
files() {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
filePath: "src/services/sample.service.ts",
|
|
36
|
+
content: SAMPLE_SERVICE_CONTENT
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL21vZGVscy9zYW1wbGUtZmlsZXMubW9kZWwudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBTb3VyY2VGaWxlLCBTb3VyY2VGaWxlUHJvdmlkZXIgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3NvdXJjZS1maWxlLmpzXCI7XG5cbmNvbnN0IFNBTVBMRV9DT05GSUdfQ09OVEVOVCA9IGBleHBvcnQgY2xhc3MgU2FtcGxlQ29uZmlnIHtcXG5cXHRwdWJsaWMgZ3JlZXRpbmc6IHN0cmluZyA9IFwiXCI7XFxufVxcbmA7XG5cbmNvbnN0IFNBTVBMRV9TRVJWSUNFX0NPTlRFTlQgPSBbXG5cdGBpbXBvcnQgeyBpbmplY3QsIGluamVjdGFibGUgfSBmcm9tIFwiQGRlY29oZXJlL2NydWNpYmxlL2RlY29yYXRvcnNcIjtgLFxuXHRgaW1wb3J0IHsgQ29uZmlndXJhdGlvblNlcnZpY2VUb2tlbiB9IGZyb20gXCJAZGVjb2hlcmUvbmV4dXMvY29uZmlndXJhdGlvblwiO2AsXG5cdGBpbXBvcnQgdHlwZSB7IElDb25maWd1cmF0aW9uU2VydmljZSB9IGZyb20gXCJAZGVjb2hlcmUvbmV4dXMvY29uZmlndXJhdGlvblwiO2AsXG5cdGBpbXBvcnQgeyBTYW1wbGVDb25maWcgfSBmcm9tIFwiLi4vc2FtcGxlLmNvbmZpZy5qc1wiO2AsXG5cdGBgLFxuXHRgQGluamVjdGFibGUoKWAsXG5cdGBleHBvcnQgY2xhc3MgU2FtcGxlU2VydmljZSB7YCxcblx0YFxcdHB1YmxpYyBjb25zdHJ1Y3RvcihgLFxuXHRgXFx0XFx0QGluamVjdChDb25maWd1cmF0aW9uU2VydmljZVRva2VuKSBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZzogSUNvbmZpZ3VyYXRpb25TZXJ2aWNlLGAsXG5cdGBcXHQpIHt9YCxcblx0YGAsXG5cdGBcXHRwdWJsaWMgYXN5bmMgZ2V0R3JlZXRpbmcoKTogUHJvbWlzZTxzdHJpbmc+IHtgLFxuXHRgXFx0XFx0Y29uc3QgY29uZmlnID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0KFNhbXBsZUNvbmZpZyk7YCxcblx0YFxcdFxcdHJldHVybiBjb25maWcuZ3JlZXRpbmc7YCxcblx0YFxcdH1gLFxuXHRgfWAsXG5cdGBgLFxuXS5qb2luKFwiXFxuXCIpO1xuXG5leHBvcnQgY2xhc3MgU2FtcGxlQ29uZmlnTW9kZWwgaW1wbGVtZW50cyBTb3VyY2VGaWxlUHJvdmlkZXIge1xuXHRwdWJsaWMgZmlsZXMoKTogU291cmNlRmlsZVtdIHtcblx0XHRyZXR1cm4gW1xuXHRcdFx0e1xuXHRcdFx0XHRmaWxlUGF0aDogXCJzcmMvc2FtcGxlLmNvbmZpZy50c1wiLFxuXHRcdFx0XHRjb250ZW50OiBTQU1QTEVfQ09ORklHX0NPTlRFTlQsXG5cdFx0XHR9LFxuXHRcdF07XG5cdH1cbn1cblxuZXhwb3J0IGNsYXNzIFNhbXBsZVNlcnZpY2VNb2RlbCBpbXBsZW1lbnRzIFNvdXJjZUZpbGVQcm92aWRlciB7XG5cdHB1YmxpYyBmaWxlcygpOiBTb3VyY2VGaWxlW10ge1xuXHRcdHJldHVybiBbXG5cdFx0XHR7XG5cdFx0XHRcdGZpbGVQYXRoOiBcInNyYy9zZXJ2aWNlcy9zYW1wbGUuc2VydmljZS50c1wiLFxuXHRcdFx0XHRjb250ZW50OiBTQU1QTEVfU0VSVklDRV9DT05URU5ULFxuXHRcdFx0fSxcblx0XHRdO1xuXHR9XG59XG4iXSwibmFtZXMiOlsiU0FNUExFX0NPTkZJR19DT05URU5UIiwiU0FNUExFX1NFUlZJQ0VfQ09OVEVOVCIsImpvaW4iLCJTYW1wbGVDb25maWdNb2RlbCIsImZpbGVzIiwiZmlsZVBhdGgiLCJjb250ZW50IiwiU2FtcGxlU2VydmljZU1vZGVsIl0sIm1hcHBpbmdzIjoiQUFFQSxNQUFNQSx3QkFBd0IsQ0FBQyxpRUFBaUUsQ0FBQztBQUVqRyxNQUFNQyx5QkFBeUI7SUFDOUIsQ0FBQyxtRUFBbUUsQ0FBQztJQUNyRSxDQUFDLDBFQUEwRSxDQUFDO0lBQzVFLENBQUMsMkVBQTJFLENBQUM7SUFDN0UsQ0FBQyxtREFBbUQsQ0FBQztJQUNyRCxFQUFFO0lBQ0YsQ0FBQyxhQUFhLENBQUM7SUFDZixDQUFDLDRCQUE0QixDQUFDO0lBQzlCLENBQUMscUJBQXFCLENBQUM7SUFDdkIsQ0FBQyxzRkFBc0YsQ0FBQztJQUN4RixDQUFDLE1BQU0sQ0FBQztJQUNSLEVBQUU7SUFDRixDQUFDLCtDQUErQyxDQUFDO0lBQ2pELENBQUMsdURBQXVELENBQUM7SUFDekQsQ0FBQywyQkFBMkIsQ0FBQztJQUM3QixDQUFDLEdBQUcsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0gsRUFBRTtDQUNGLENBQUNDLElBQUksQ0FBQztBQUVQLE9BQU8sTUFBTUM7SUFDTEMsUUFBc0I7UUFDNUIsT0FBTztZQUNOO2dCQUNDQyxVQUFVO2dCQUNWQyxTQUFTTjtZQUNWO1NBQ0E7SUFDRjtBQUNEO0FBRUEsT0FBTyxNQUFNTztJQUNMSCxRQUFzQjtRQUM1QixPQUFPO1lBQ047Z0JBQ0NDLFVBQVU7Z0JBQ1ZDLFNBQVNMO1lBQ1Y7U0FDQTtJQUNGO0FBQ0QifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decohere/create",
|
|
3
|
-
"version": "0.0.1-dev.
|
|
3
|
+
"version": "0.0.1-dev.19",
|
|
4
4
|
"description": "Scaffold a new Decohere project — build with Forge, serve with Flux",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"decohere",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@decohere/nexus": "0.0.1-dev.
|
|
24
|
+
"@decohere/nexus": "0.0.1-dev.19",
|
|
25
25
|
"commander": "^13.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { KeyedModel } from "./source-file.js";
|
|
2
|
+
export interface ComposeService {
|
|
3
|
+
build?: string;
|
|
4
|
+
image?: string;
|
|
5
|
+
env_file?: string[];
|
|
6
|
+
environment?: Record<string, string>;
|
|
7
|
+
ports?: string[];
|
|
8
|
+
volumes?: string[];
|
|
9
|
+
command?: string;
|
|
10
|
+
restart?: string;
|
|
11
|
+
depends_on?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Live builder for `docker-compose.yml`.
|
|
15
|
+
*
|
|
16
|
+
* Features call `addService` / `addVolume` in their `configure` phases.
|
|
17
|
+
* The devcontainer `render` phase calls `render()` and writes the file.
|
|
18
|
+
*/
|
|
19
|
+
export declare class DockerCompose implements KeyedModel {
|
|
20
|
+
readonly key: string;
|
|
21
|
+
private readonly _services;
|
|
22
|
+
private readonly _volumes;
|
|
23
|
+
addService(name: string, config: ComposeService): this;
|
|
24
|
+
files(): {
|
|
25
|
+
filePath: string;
|
|
26
|
+
content: string;
|
|
27
|
+
}[];
|
|
28
|
+
addVolume(name: string): this;
|
|
29
|
+
/** Append an env_file path to an existing service. */
|
|
30
|
+
addEnvFile(serviceName: string, filePath: string): this;
|
|
31
|
+
getContent(): string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builder for a YAML config file (e.g. config/config.yaml or config/config.dev.yaml).
|
|
4
|
+
*
|
|
5
|
+
* Starts with a base section passed to the constructor. Features call
|
|
6
|
+
* `addSection(yaml)` during their scaffold phase to append their own block.
|
|
7
|
+
* `files()` joins all sections with a blank line separator.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ConfigYaml implements KeyedModel {
|
|
10
|
+
readonly key: string;
|
|
11
|
+
private readonly filePath;
|
|
12
|
+
private readonly _sections;
|
|
13
|
+
constructor(key: string, filePath: string, baseContent: string);
|
|
14
|
+
addSection(yaml: string): this;
|
|
15
|
+
files(): SourceFile[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const WELL_KNOWN_FILES: {
|
|
2
|
+
VSCODE_SETTINGS: string;
|
|
3
|
+
LAUNCH_JSON: string;
|
|
4
|
+
DOCKER_COMPOSE: string;
|
|
5
|
+
DEVCONTAINER_JSON: string;
|
|
6
|
+
DOCKERFILE: string;
|
|
7
|
+
PACKAGE_JSON: string;
|
|
8
|
+
API_PACKAGE_JSON: string;
|
|
9
|
+
TSCONFIG: string;
|
|
10
|
+
MAIN_TS: string;
|
|
11
|
+
CONTROLLER_TS: string;
|
|
12
|
+
CONFIG_YAML: string;
|
|
13
|
+
CONFIG_DEV_YAML: string;
|
|
14
|
+
GITIGNORE: string;
|
|
15
|
+
AUTH_CONFIG: string;
|
|
16
|
+
ENV_FILE: string;
|
|
17
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builder for `.devcontainer/Dockerfile`.
|
|
4
|
+
*
|
|
5
|
+
* Features call `addRunStep(cmd)` during their scaffold phase to append
|
|
6
|
+
* additional `RUN` instructions before the final `USER` instruction.
|
|
7
|
+
* `files()` assembles the complete Dockerfile content at render time.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DockerfileModel implements KeyedModel {
|
|
10
|
+
readonly key: string;
|
|
11
|
+
private readonly _runSteps;
|
|
12
|
+
/** Append a RUN instruction (pass the command, not the RUN keyword). */
|
|
13
|
+
addRunStep(cmd: string): this;
|
|
14
|
+
files(): SourceFile[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Model for `.devcontainer/devcontainer.json`.
|
|
4
|
+
*
|
|
5
|
+
* Features call builder methods (`addExtension`, `forwardPort`, etc.) during
|
|
6
|
+
* their configure phase. `MonoRepoScaffold` calls `files()` at render time.
|
|
7
|
+
*/
|
|
8
|
+
export declare class DevContainer implements KeyedModel {
|
|
9
|
+
readonly key: string;
|
|
10
|
+
private readonly _extensions;
|
|
11
|
+
private readonly _ports;
|
|
12
|
+
private readonly _mounts;
|
|
13
|
+
private _postStartCommand?;
|
|
14
|
+
private _useCompose;
|
|
15
|
+
constructor();
|
|
16
|
+
addExtension(...ids: string[]): this;
|
|
17
|
+
forwardPort(...ports: number[]): this;
|
|
18
|
+
setPostStartCommand(cmd: string): this;
|
|
19
|
+
useCompose(): this;
|
|
20
|
+
files(): SourceFile[];
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Accumulates key=value pairs and renders them as a `.env` file.
|
|
4
|
+
*
|
|
5
|
+
* Register once in the workspace; features call `addEntry` during their
|
|
6
|
+
* scaffold phase to contribute environment variables. The final file is
|
|
7
|
+
* written at render time when `workspace.scaffold()` is called.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EnvFile implements KeyedModel {
|
|
10
|
+
readonly key: string;
|
|
11
|
+
private readonly _entries;
|
|
12
|
+
addEntry(key: string, value: string): this;
|
|
13
|
+
files(): SourceFile[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builder for the root `package.json`.
|
|
4
|
+
*
|
|
5
|
+
* Starts with the core API dependencies. Features call `addDependency` /
|
|
6
|
+
* `addDevDependency` during their scaffold phase to inject their own deps
|
|
7
|
+
* before `files()` is called at render time.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PackageJson implements KeyedModel {
|
|
10
|
+
private readonly name;
|
|
11
|
+
readonly key: string;
|
|
12
|
+
private readonly _dependencies;
|
|
13
|
+
private readonly _devDependencies;
|
|
14
|
+
constructor(name: string);
|
|
15
|
+
addDependency(name: string, version: string): this;
|
|
16
|
+
addDevDependency(name: string, version: string): this;
|
|
17
|
+
files(): SourceFile[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile, SourceFileProvider } from "./source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* A sub-unit of the monorepo (e.g. `projects/api`).
|
|
4
|
+
*
|
|
5
|
+
* Models and files registered here produce paths relative to `dir`. The parent
|
|
6
|
+
* `MonoRepoScaffold` calls `files()` and prepends `dir/` to every path, so
|
|
7
|
+
* models remain unaware of where they live in the repo.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ProjectScaffold {
|
|
10
|
+
readonly dir: string;
|
|
11
|
+
private readonly _models;
|
|
12
|
+
private readonly _files;
|
|
13
|
+
constructor(dir: string);
|
|
14
|
+
addModel<T extends KeyedModel>(model: T): T;
|
|
15
|
+
addFile(provider: SourceFileProvider): this;
|
|
16
|
+
getModel<T extends SourceFileProvider>(key: string): T | undefined;
|
|
17
|
+
getModels<T extends SourceFileProvider>(ctor: new (...args: never[]) => T): T[];
|
|
18
|
+
/** Returns all files with `dir/` prepended to each path. */
|
|
19
|
+
files(): SourceFile[];
|
|
20
|
+
}
|
|
21
|
+
export declare abstract class WorkspaceScaffold {
|
|
22
|
+
readonly files: SourceFile[];
|
|
23
|
+
targetDir: string;
|
|
24
|
+
/** Derived from the basename of targetDir. */
|
|
25
|
+
get name(): string;
|
|
26
|
+
/** Add an ad-hoc file provider whose output is included at render time. */
|
|
27
|
+
addFile(provider: SourceFileProvider): this;
|
|
28
|
+
abstract addModel<T extends KeyedModel>(model: T): T;
|
|
29
|
+
abstract getModel<T extends SourceFileProvider>(key: string): T | undefined;
|
|
30
|
+
abstract getModels<T extends SourceFileProvider>(ctor: new (...args: never[]) => T): T[];
|
|
31
|
+
abstract getProject(dir: string): ProjectScaffold | undefined;
|
|
32
|
+
abstract scaffold(): Promise<void> | void;
|
|
33
|
+
}
|
|
34
|
+
export declare class MonoRepoScaffold extends WorkspaceScaffold {
|
|
35
|
+
private readonly _models;
|
|
36
|
+
private readonly _projects;
|
|
37
|
+
/** Register a named project. */
|
|
38
|
+
addProject(project: ProjectScaffold): ProjectScaffold;
|
|
39
|
+
/** Retrieve a previously-registered project by its directory path. */
|
|
40
|
+
getProject(dir: string): ProjectScaffold | undefined;
|
|
41
|
+
/** Register a named model at workspace level. */
|
|
42
|
+
addModel<T extends KeyedModel>(model: T): T;
|
|
43
|
+
/**
|
|
44
|
+
* Retrieve a model by key. Searches workspace models first, then all
|
|
45
|
+
* registered projects in order.
|
|
46
|
+
*/
|
|
47
|
+
getModel<T extends SourceFileProvider>(key: string): T | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Retrieve all models of a given type. Searches workspace models and all
|
|
50
|
+
* projects, so features can discover controllers across multiple projects.
|
|
51
|
+
*/
|
|
52
|
+
getModels<T extends SourceFileProvider>(ctor: new (...args: never[]) => T): T[];
|
|
53
|
+
/** Render all models and projects into files, then write everything to disk. */
|
|
54
|
+
scaffold(): Promise<void>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SourceFileProvider {
|
|
2
|
+
files(): SourceFile[];
|
|
3
|
+
}
|
|
4
|
+
/** A SourceFileProvider that knows its own registration key. */
|
|
5
|
+
export interface KeyedModel extends SourceFileProvider {
|
|
6
|
+
readonly key: string;
|
|
7
|
+
}
|
|
8
|
+
export type SourceFile = {
|
|
9
|
+
filePath: string;
|
|
10
|
+
content: string;
|
|
11
|
+
};
|