@ozanarslan/corpus-cli 0.0.1
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.txt +20 -0
- package/README.md +196 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +1448 -0
- package/dist/getConfig-lU3I2Ejy.mjs +324 -0
- package/dist/index.d.mts +1178 -0
- package/dist/index.mjs +595 -0
- package/package.json +48 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/constants.ts
|
|
8
|
+
const APP_NAME = "Corpus CLI";
|
|
9
|
+
const EXE_NAME = "corpus";
|
|
10
|
+
const CONFIG_FILE_NAME = "corpus.config.ts";
|
|
11
|
+
const GEN_FUNC = `generateApiClient`;
|
|
12
|
+
const NAME_FLAG_HELP = `<name> | [--name, -n] <name>`;
|
|
13
|
+
const LISTEN_PATTERN = /^[ \t]*(?:void|await)?\s*\w+\.listen\(.*?\);.*$/m;
|
|
14
|
+
const MODEL_PATTERN = /\w*Model\w*/;
|
|
15
|
+
const MODEL_TYPE_PATTERN = /^type\s+(\w+)\s*=\s*\w+\.InferModel<[^;]+>;?$/m;
|
|
16
|
+
const INTERFACE_MODEL_PATTERN = /(?:^|\s)interface\s+(\w*Model\w*)\s*\{/;
|
|
17
|
+
const PATTERNS = {
|
|
18
|
+
import: /^import\s.+;$/,
|
|
19
|
+
route: /(?:const\s+\w+\s*=\s*)?new\s+(?:[\w.]+)?Route\(/,
|
|
20
|
+
middleware: /(?:const\s+\w+\s*=\s*)?new\s+(?:[\w.]+)?Middleware\(/,
|
|
21
|
+
controller: /(?:const\s+\w+\s*=\s*)?new\s+(?:[\w.]+)?Controller\(/,
|
|
22
|
+
service: /(?:const\s+\w+\s*=\s*)?new\s+(?:[\w.]+)?Service\(/
|
|
23
|
+
};
|
|
24
|
+
const NEVER_SCHEMAS = /* @__PURE__ */ new Set([
|
|
25
|
+
"type(\\\"never\\\")",
|
|
26
|
+
"type(\"never\")",
|
|
27
|
+
"z.never()",
|
|
28
|
+
"y.mixed().oneOf([undefined] as const)",
|
|
29
|
+
"y.mixed().oneOf([undefined])",
|
|
30
|
+
"this.never",
|
|
31
|
+
"never",
|
|
32
|
+
"undefined",
|
|
33
|
+
"type(\\\"undefined\\\")",
|
|
34
|
+
"type(\"undefined\")",
|
|
35
|
+
"z.undefined()"
|
|
36
|
+
]);
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region ../utils/is.ts
|
|
39
|
+
const EMPTY = Symbol("empty");
|
|
40
|
+
function isPresent(input) {
|
|
41
|
+
return input !== void 0 && input !== null && input !== EMPTY;
|
|
42
|
+
}
|
|
43
|
+
function isAbsent(input) {
|
|
44
|
+
return !isPresent(input);
|
|
45
|
+
}
|
|
46
|
+
function isObject(input) {
|
|
47
|
+
if (isAbsent(input) || typeof input !== "object" || Array.isArray(input)) return false;
|
|
48
|
+
return Object.getPrototypeOf(input) === Object.prototype;
|
|
49
|
+
}
|
|
50
|
+
function isEmpty(input) {
|
|
51
|
+
if (isAbsent(input)) return true;
|
|
52
|
+
if (typeof input === "string") return input.trim() === "";
|
|
53
|
+
if (typeof input === "number") return input === 0;
|
|
54
|
+
if (isObject(input)) return Object.keys(input).length === 0;
|
|
55
|
+
if (Array.isArray(input)) return input.length === 0;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function isSomeArray(input) {
|
|
59
|
+
return isPresent(input) && Array.isArray(input) && input.length > 0;
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/internal/cache.ts
|
|
63
|
+
const map = /* @__PURE__ */ new Map();
|
|
64
|
+
const TWO_MIN = 12e4;
|
|
65
|
+
function cache(key, callback, ttlMs = TWO_MIN) {
|
|
66
|
+
return (...args) => {
|
|
67
|
+
const cacheKey = args.length ? `${key}:${JSON.stringify(args)}` : key;
|
|
68
|
+
const entry = map.get(cacheKey);
|
|
69
|
+
if (entry && Date.now() < entry.expiresAt) return entry.value;
|
|
70
|
+
const value = callback(...args);
|
|
71
|
+
map.set(cacheKey, {
|
|
72
|
+
value,
|
|
73
|
+
expiresAt: Date.now() + ttlMs
|
|
74
|
+
});
|
|
75
|
+
return value;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region ../utils/assert.ts
|
|
80
|
+
function assertBase(condition, msg) {
|
|
81
|
+
if (!condition) throw new Error(msg);
|
|
82
|
+
}
|
|
83
|
+
function assertPresent(value, msg) {
|
|
84
|
+
if (isAbsent(value)) throw new Error(msg);
|
|
85
|
+
}
|
|
86
|
+
const assert = Object.assign(assertBase, { present: assertPresent });
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/internal/converters.ts
|
|
89
|
+
function toPascalCase(key) {
|
|
90
|
+
return key.replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
91
|
+
}
|
|
92
|
+
function toCamelCase(key) {
|
|
93
|
+
const parts = key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean);
|
|
94
|
+
if (parts.length === 0) return key;
|
|
95
|
+
const [first, ...rest] = parts;
|
|
96
|
+
return first.toLowerCase() + rest.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
97
|
+
}
|
|
98
|
+
function toKebabCase(key) {
|
|
99
|
+
return key.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
100
|
+
}
|
|
101
|
+
function quote(s) {
|
|
102
|
+
return `"${s}"`;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/internal/resolveCwdPath.ts
|
|
106
|
+
function resolveCwdPath(...segments) {
|
|
107
|
+
const joined = segments.map((segment) => typeof segment === "number" ? segment.toString() : segment).filter((segment) => !isEmpty(segment)).flatMap((segment) => segment.split("/")).map((segment) => segment.replace(/^\/+|\/+$/g, "")).filter((segment) => segment.length > 0).join("/");
|
|
108
|
+
return path.resolve(process.cwd(), joined);
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/internal/StringBuilder.ts
|
|
112
|
+
var StringBuilder = class {
|
|
113
|
+
complete = "";
|
|
114
|
+
lineCount = 0;
|
|
115
|
+
get currentLine() {
|
|
116
|
+
return this.lineCount;
|
|
117
|
+
}
|
|
118
|
+
inline(s) {
|
|
119
|
+
this.complete += s;
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
line(input) {
|
|
123
|
+
return typeof input === "number" ? (s) => this.push(" ".repeat(input) + s) : this.push(input);
|
|
124
|
+
}
|
|
125
|
+
get tab() {
|
|
126
|
+
this.push(" ");
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
push(s) {
|
|
130
|
+
if (this.complete.length === 0) this.complete += s;
|
|
131
|
+
else {
|
|
132
|
+
this.complete += "\n" + s;
|
|
133
|
+
this.lineCount++;
|
|
134
|
+
}
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
prepend(s) {
|
|
138
|
+
this.complete = s + "\n" + this.complete;
|
|
139
|
+
this.lineCount++;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
clear() {
|
|
143
|
+
this.complete = "";
|
|
144
|
+
this.lineCount = 0;
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
replaceAll(find, change) {
|
|
148
|
+
this.complete = this.complete.replaceAll(find, change);
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
replace(find, change) {
|
|
152
|
+
this.complete = this.complete.replace(find, change);
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
replaceByIndex(find, occurrence, change) {
|
|
156
|
+
let i = -1;
|
|
157
|
+
let from = 0;
|
|
158
|
+
for (let n = 0; n <= occurrence; n++) {
|
|
159
|
+
i = this.complete.indexOf(find, from);
|
|
160
|
+
if (i === -1) return this;
|
|
161
|
+
from = i + find.length;
|
|
162
|
+
}
|
|
163
|
+
this.complete = this.complete.slice(0, i) + change + this.complete.slice(i + find.length);
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
trim() {
|
|
167
|
+
this.complete = this.complete.trim();
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
slice(start, end) {
|
|
171
|
+
this.complete = this.complete.slice(start, end);
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
get length() {
|
|
175
|
+
return this.complete.length;
|
|
176
|
+
}
|
|
177
|
+
get isEmpty() {
|
|
178
|
+
return this.complete.length === 0;
|
|
179
|
+
}
|
|
180
|
+
toString() {
|
|
181
|
+
return this.complete;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region ../utils/logger.ts
|
|
186
|
+
const col = {
|
|
187
|
+
reset: "\x1B[0m",
|
|
188
|
+
green: "\x1B[32m",
|
|
189
|
+
red: "\x1B[31m",
|
|
190
|
+
cyan: "\x1B[36m",
|
|
191
|
+
yellow: "\x1B[33m",
|
|
192
|
+
gray: "\x1B[90m",
|
|
193
|
+
bold: "\x1B[1m",
|
|
194
|
+
magenta: "\x1B[35m",
|
|
195
|
+
blue: "\x1B[34m"
|
|
196
|
+
};
|
|
197
|
+
function strColor(color, str) {
|
|
198
|
+
return col[color] + str + col.reset;
|
|
199
|
+
}
|
|
200
|
+
function makeLogger() {
|
|
201
|
+
const logger = {};
|
|
202
|
+
logger.log = (...a) => console.log(...a);
|
|
203
|
+
logger.bold = (...a) => console.log(col.bold, ...a, col.reset);
|
|
204
|
+
logger.info = (...a) => console.log(strColor("cyan", "i"), ...a);
|
|
205
|
+
logger.success = (...a) => console.log(strColor("green", "✓"), ...a);
|
|
206
|
+
logger.error = (...a) => console.error(strColor("red", "✗"), ...a);
|
|
207
|
+
logger.debug = (...a) => console.log(strColor("gray", "·"), ...a);
|
|
208
|
+
logger.warn = (...a) => console.warn(strColor("yellow", "⚠"), ...a);
|
|
209
|
+
logger.step = (...a) => console.log(strColor("magenta", ">"), ...a);
|
|
210
|
+
return logger;
|
|
211
|
+
}
|
|
212
|
+
function makeNoopLogger() {
|
|
213
|
+
return {
|
|
214
|
+
bold() {},
|
|
215
|
+
log() {},
|
|
216
|
+
info() {},
|
|
217
|
+
success() {},
|
|
218
|
+
debug() {},
|
|
219
|
+
warn() {},
|
|
220
|
+
step() {},
|
|
221
|
+
error() {}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
let active = makeLogger();
|
|
225
|
+
const logger = new Proxy({}, { get(_target, prop) {
|
|
226
|
+
return active[prop];
|
|
227
|
+
} });
|
|
228
|
+
function setLoggerNoop() {
|
|
229
|
+
active = makeNoopLogger();
|
|
230
|
+
}
|
|
231
|
+
function logFatal(...args) {
|
|
232
|
+
if (process.env.NODE_ENV === "test") throw new Error(JSON.stringify(args));
|
|
233
|
+
else {
|
|
234
|
+
logger.error(...args);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/Config/getConfig.ts
|
|
240
|
+
function getDefaultConfig() {
|
|
241
|
+
return {
|
|
242
|
+
silent: false,
|
|
243
|
+
main: "./src/main.ts",
|
|
244
|
+
pkgPath: "@ozanarslan/corpus",
|
|
245
|
+
casing: "pascal",
|
|
246
|
+
validationLibrary: null,
|
|
247
|
+
output: "./src/corpus.gen.ts",
|
|
248
|
+
apiClient: {
|
|
249
|
+
disabled: false,
|
|
250
|
+
exportAs: "CorpusApi",
|
|
251
|
+
useStaticClass: false
|
|
252
|
+
},
|
|
253
|
+
ignoreGlobalPrefix: false,
|
|
254
|
+
defaultMethods: {
|
|
255
|
+
get: {
|
|
256
|
+
propertyKey: "get",
|
|
257
|
+
address: "GET /"
|
|
258
|
+
},
|
|
259
|
+
getByParams: {
|
|
260
|
+
propertyKey: "getByParams",
|
|
261
|
+
address: "GET /:id"
|
|
262
|
+
},
|
|
263
|
+
create: {
|
|
264
|
+
propertyKey: "create",
|
|
265
|
+
address: "POST /"
|
|
266
|
+
},
|
|
267
|
+
update: {
|
|
268
|
+
propertyKey: "update",
|
|
269
|
+
address: "PUT /:id"
|
|
270
|
+
},
|
|
271
|
+
remove: {
|
|
272
|
+
propertyKey: "remove",
|
|
273
|
+
address: "DELETE /:id"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
folderStructure: {
|
|
277
|
+
model: "{resource}/{resource}-model.ts",
|
|
278
|
+
service: "{resource}/{resource}-service.ts",
|
|
279
|
+
controller: "{resource}/{resource}-controller.ts",
|
|
280
|
+
route: "{resource}/{resource}-route.ts"
|
|
281
|
+
},
|
|
282
|
+
exportModelsNamespace: true,
|
|
283
|
+
exportArgsNamespace: true
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function getFileConfig() {
|
|
287
|
+
const extensions = [".ts", ".js"];
|
|
288
|
+
const base = resolveCwdPath(CONFIG_FILE_NAME.replace(".ts", ""));
|
|
289
|
+
const configPath = extensions.map((ext) => base + ext).find(fs.existsSync);
|
|
290
|
+
return configPath ? __require(configPath).default : null;
|
|
291
|
+
}
|
|
292
|
+
const getConfig = cache("getConfig", () => {
|
|
293
|
+
function configFileExists() {
|
|
294
|
+
const filePath = path.resolve(process.cwd(), CONFIG_FILE_NAME);
|
|
295
|
+
return fs.existsSync(filePath);
|
|
296
|
+
}
|
|
297
|
+
const fileConfig = getFileConfig();
|
|
298
|
+
const defaultConfig = getDefaultConfig();
|
|
299
|
+
const config = fileConfig ?? defaultConfig;
|
|
300
|
+
function writeConfigFile(config) {
|
|
301
|
+
const b = new StringBuilder();
|
|
302
|
+
b.line(`import { defineConfig } from "@ozanarslan/corpus-cli/config";`);
|
|
303
|
+
b.line(``);
|
|
304
|
+
b.line(`export default defineConfig({`);
|
|
305
|
+
writeConfigEntries(b, config, 1);
|
|
306
|
+
b.line(`});`);
|
|
307
|
+
const content = b.toString();
|
|
308
|
+
const fpath = path.resolve(process.cwd(), CONFIG_FILE_NAME);
|
|
309
|
+
fs.mkdirSync(path.dirname(fpath), { recursive: true });
|
|
310
|
+
fs.writeFileSync(fpath, content);
|
|
311
|
+
logger.info(`Config written to ${CONFIG_FILE_NAME}`);
|
|
312
|
+
}
|
|
313
|
+
function writeConfigEntries(b, obj, indent) {
|
|
314
|
+
for (const [key, val] of Object.entries(obj)) if (isObject(val)) {
|
|
315
|
+
b.line(indent)(`${key}: {`);
|
|
316
|
+
writeConfigEntries(b, val, indent + 1);
|
|
317
|
+
b.line(indent)(`},`);
|
|
318
|
+
} else b.line(indent)(`${key}: ${typeof val === "string" ? quote(val) : val},`);
|
|
319
|
+
}
|
|
320
|
+
if (!configFileExists()) writeConfigFile(config);
|
|
321
|
+
return config;
|
|
322
|
+
});
|
|
323
|
+
//#endregion
|
|
324
|
+
export { LISTEN_PATTERN as C, NEVER_SCHEMAS as D, NAME_FLAG_HELP as E, PATTERNS as O, INTERFACE_MODEL_PATTERN as S, MODEL_TYPE_PATTERN as T, isPresent as _, setLoggerNoop as a, EXE_NAME as b, quote as c, toPascalCase as d, assert as f, isObject as g, isEmpty as h, logger as i, toCamelCase as l, isAbsent as m, getDefaultConfig as n, StringBuilder as o, cache as p, logFatal as r, resolveCwdPath as s, getConfig as t, toKebabCase as u, isSomeArray as v, MODEL_PATTERN as w, GEN_FUNC as x, APP_NAME as y };
|