fexapi 0.2.0 → 0.2.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/dist/cli/args.js +2 -2
- package/dist/cli/ui.d.ts +15 -0
- package/dist/cli/ui.d.ts.map +1 -1
- package/dist/cli/ui.js +84 -2
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +85 -19
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +45 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/cli/args.js
CHANGED
|
@@ -90,7 +90,7 @@ const parseServeOptions = (serveArgs) => {
|
|
|
90
90
|
if (positionalArgs.length > 0) {
|
|
91
91
|
return { error: `Unexpected argument(s): ${positionalArgs.join(", ")}` };
|
|
92
92
|
}
|
|
93
|
-
const host = hostValue ?? "
|
|
93
|
+
const host = hostValue ?? "localhost";
|
|
94
94
|
const port = portValue ? Number(portValue) : undefined;
|
|
95
95
|
if (port !== undefined &&
|
|
96
96
|
(!Number.isInteger(port) || port < 1 || port > 65535)) {
|
|
@@ -150,7 +150,7 @@ const parseDevOptions = (devArgs) => {
|
|
|
150
150
|
if (positionalArgs.length > 0) {
|
|
151
151
|
return { error: `Unexpected argument(s): ${positionalArgs.join(", ")}` };
|
|
152
152
|
}
|
|
153
|
-
const host = hostValue ?? "
|
|
153
|
+
const host = hostValue ?? "localhost";
|
|
154
154
|
const port = portValue ? Number(portValue) : undefined;
|
|
155
155
|
if (port !== undefined &&
|
|
156
156
|
(!Number.isInteger(port) || port < 1 || port > 65535)) {
|
package/dist/cli/ui.d.ts
CHANGED
|
@@ -2,12 +2,26 @@ export declare const ui: {
|
|
|
2
2
|
bold: (text: string) => string;
|
|
3
3
|
dim: (text: string) => string;
|
|
4
4
|
cyan: (text: string) => string;
|
|
5
|
+
magenta: (text: string) => string;
|
|
5
6
|
blue: (text: string) => string;
|
|
6
7
|
green: (text: string) => string;
|
|
7
8
|
yellow: (text: string) => string;
|
|
8
9
|
red: (text: string) => string;
|
|
9
10
|
gray: (text: string) => string;
|
|
10
11
|
};
|
|
12
|
+
type SpinnerController = {
|
|
13
|
+
update: (text: string) => void;
|
|
14
|
+
succeed: (text: string) => void;
|
|
15
|
+
fail: (text: string) => void;
|
|
16
|
+
stop: () => void;
|
|
17
|
+
};
|
|
18
|
+
export declare const startSpinner: (initialText: string) => SpinnerController;
|
|
19
|
+
export declare const nowMs: () => number;
|
|
20
|
+
export declare const formatDuration: (startMs: number) => string;
|
|
21
|
+
export declare const printSummaryCard: (title: string, rows: Array<{
|
|
22
|
+
label: string;
|
|
23
|
+
value: string;
|
|
24
|
+
}>) => void;
|
|
11
25
|
export declare const printBanner: () => void;
|
|
12
26
|
export declare const printSpacer: () => void;
|
|
13
27
|
export declare const logInfo: (message: string) => void;
|
|
@@ -16,4 +30,5 @@ export declare const logWarn: (message: string) => void;
|
|
|
16
30
|
export declare const logError: (message: string) => void;
|
|
17
31
|
export declare const logStep: (message: string) => void;
|
|
18
32
|
export declare const formatCommand: (command: string) => string;
|
|
33
|
+
export {};
|
|
19
34
|
//# sourceMappingURL=ui.d.ts.map
|
package/dist/cli/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,EAAE;iBACA,MAAM,KAAG,MAAM;gBAChB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;oBACZ,MAAM,KAAG,MAAM;iBAClB,MAAM,KAAG,MAAM;kBACd,MAAM,KAAG,MAAM;mBACd,MAAM,KAAG,MAAM;gBAClB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;CAC7B,CAAC;AAYF,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,KAAG,iBA0ClD,CAAC;AAEF,eAAO,MAAM,KAAK,QAAO,MAAoB,CAAC;AAE9C,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAQhD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,MAAM,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,KAC5C,IAyBF,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAO9B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,KAAG,IAE1C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,MAE/C,CAAC"}
|
package/dist/cli/ui.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatCommand = exports.logStep = exports.logError = exports.logWarn = exports.logSuccess = exports.logInfo = exports.printSpacer = exports.printBanner = exports.ui = void 0;
|
|
3
|
+
exports.formatCommand = exports.logStep = exports.logError = exports.logWarn = exports.logSuccess = exports.logInfo = exports.printSpacer = exports.printBanner = exports.printSummaryCard = exports.formatDuration = exports.nowMs = exports.startSpinner = exports.ui = void 0;
|
|
4
4
|
const shouldUseColor = () => {
|
|
5
5
|
return Boolean(process.stdout.isTTY);
|
|
6
6
|
};
|
|
7
7
|
const colorEnabled = shouldUseColor();
|
|
8
|
+
const interactive = Boolean(process.stdout.isTTY);
|
|
8
9
|
const paint = (code, text) => {
|
|
9
10
|
if (!colorEnabled) {
|
|
10
11
|
return text;
|
|
@@ -15,14 +16,95 @@ exports.ui = {
|
|
|
15
16
|
bold: (text) => paint("1", text),
|
|
16
17
|
dim: (text) => paint("2", text),
|
|
17
18
|
cyan: (text) => paint("36", text),
|
|
19
|
+
magenta: (text) => paint("35", text),
|
|
18
20
|
blue: (text) => paint("94", text),
|
|
19
21
|
green: (text) => paint("32", text),
|
|
20
22
|
yellow: (text) => paint("33", text),
|
|
21
23
|
red: (text) => paint("31", text),
|
|
22
24
|
gray: (text) => paint("90", text),
|
|
23
25
|
};
|
|
26
|
+
const SPINNER_FRAMES = ["-", "\\", "|", "/"];
|
|
27
|
+
const clearCurrentLine = () => {
|
|
28
|
+
if (!interactive) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
process.stdout.write("\r\u001b[2K");
|
|
32
|
+
};
|
|
33
|
+
const startSpinner = (initialText) => {
|
|
34
|
+
if (!interactive) {
|
|
35
|
+
(0, exports.logStep)(initialText);
|
|
36
|
+
return {
|
|
37
|
+
update: (text) => (0, exports.logStep)(text),
|
|
38
|
+
succeed: (text) => (0, exports.logSuccess)(text),
|
|
39
|
+
fail: (text) => (0, exports.logError)(text),
|
|
40
|
+
stop: () => undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
let text = initialText;
|
|
44
|
+
let frameIndex = 0;
|
|
45
|
+
const render = () => {
|
|
46
|
+
const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length] ?? "-";
|
|
47
|
+
frameIndex += 1;
|
|
48
|
+
process.stdout.write(`\r${exports.ui.cyan(frame)} ${exports.ui.bold(text)}`);
|
|
49
|
+
};
|
|
50
|
+
render();
|
|
51
|
+
const timer = setInterval(render, 80);
|
|
52
|
+
return {
|
|
53
|
+
update: (nextText) => {
|
|
54
|
+
text = nextText;
|
|
55
|
+
},
|
|
56
|
+
succeed: (finalText) => {
|
|
57
|
+
clearInterval(timer);
|
|
58
|
+
clearCurrentLine();
|
|
59
|
+
console.log(`${exports.ui.green("ok")} ${finalText}`);
|
|
60
|
+
},
|
|
61
|
+
fail: (finalText) => {
|
|
62
|
+
clearInterval(timer);
|
|
63
|
+
clearCurrentLine();
|
|
64
|
+
console.log(`${exports.ui.red("err")} ${finalText}`);
|
|
65
|
+
},
|
|
66
|
+
stop: () => {
|
|
67
|
+
clearInterval(timer);
|
|
68
|
+
clearCurrentLine();
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
exports.startSpinner = startSpinner;
|
|
73
|
+
const nowMs = () => Date.now();
|
|
74
|
+
exports.nowMs = nowMs;
|
|
75
|
+
const formatDuration = (startMs) => {
|
|
76
|
+
const elapsedMs = Date.now() - startMs;
|
|
77
|
+
if (elapsedMs < 1000) {
|
|
78
|
+
return `${elapsedMs}ms`;
|
|
79
|
+
}
|
|
80
|
+
return `${(elapsedMs / 1000).toFixed(2)}s`;
|
|
81
|
+
};
|
|
82
|
+
exports.formatDuration = formatDuration;
|
|
83
|
+
const printSummaryCard = (title, rows) => {
|
|
84
|
+
const contentRows = [{ label: "", value: title }, ...rows];
|
|
85
|
+
const maxLabel = Math.max(...contentRows.map((row) => row.label.length));
|
|
86
|
+
const maxValue = Math.max(...contentRows.map((row) => row.value.length));
|
|
87
|
+
const cardWidth = Math.max(40, maxLabel + maxValue + 7);
|
|
88
|
+
const border = `+${"-".repeat(cardWidth - 2)}+`;
|
|
89
|
+
console.log(exports.ui.gray(border));
|
|
90
|
+
const titleText = exports.ui.bold(exports.ui.cyan(title));
|
|
91
|
+
const titleLine = `| ${titleText}${" ".repeat(Math.max(0, cardWidth - 4 - title.length))} |`;
|
|
92
|
+
console.log(titleLine);
|
|
93
|
+
console.log(exports.ui.gray(`|${"-".repeat(cardWidth - 2)}|`));
|
|
94
|
+
for (const row of rows) {
|
|
95
|
+
const label = row.label.padEnd(maxLabel, " ");
|
|
96
|
+
const value = row.value;
|
|
97
|
+
const spaces = " ".repeat(Math.max(1, cardWidth - 4 - label.length - 3 - value.length));
|
|
98
|
+
console.log(`| ${exports.ui.dim(label)} : ${exports.ui.bold(value)}${spaces}|`);
|
|
99
|
+
}
|
|
100
|
+
console.log(exports.ui.gray(border));
|
|
101
|
+
};
|
|
102
|
+
exports.printSummaryCard = printSummaryCard;
|
|
24
103
|
const printBanner = () => {
|
|
25
|
-
console.log(exports.ui.bold(exports.ui.cyan("fexapi")) +
|
|
104
|
+
console.log(exports.ui.bold(exports.ui.cyan("fexapi")) +
|
|
105
|
+
exports.ui.gray(" ") +
|
|
106
|
+
exports.ui.magenta("mock") +
|
|
107
|
+
exports.ui.gray(" api toolkit"));
|
|
26
108
|
};
|
|
27
109
|
exports.printBanner = printBanner;
|
|
28
110
|
const printSpacer = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,kBAAkB,QAAO,MA8KrC,CAAC"}
|
|
@@ -7,7 +7,14 @@ const constants_1 = require("../constants");
|
|
|
7
7
|
const ui_1 = require("../cli/ui");
|
|
8
8
|
const paths_1 = require("../project/paths");
|
|
9
9
|
const schema_1 = require("../schema");
|
|
10
|
+
const createRouteSignature = (value) => {
|
|
11
|
+
return JSON.stringify({
|
|
12
|
+
port: value.port,
|
|
13
|
+
routes: value.routes,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
10
16
|
const generateFromSchema = () => {
|
|
17
|
+
const startedAtMs = (0, ui_1.nowMs)();
|
|
11
18
|
const projectRoot = (0, paths_1.resolveProjectRoot)();
|
|
12
19
|
if (!projectRoot) {
|
|
13
20
|
(0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
|
|
@@ -19,18 +26,40 @@ const generateFromSchema = () => {
|
|
|
19
26
|
const configPath = (0, node_path_1.join)(projectRoot, "fexapi.config.json");
|
|
20
27
|
if (!(0, node_fs_1.existsSync)(schemaPath)) {
|
|
21
28
|
(0, ui_1.logError)(`Schema file not found: ${schemaPath}`);
|
|
22
|
-
(0, ui_1.
|
|
29
|
+
(0, ui_1.logError)("Run `fexapi init` first.");
|
|
23
30
|
return 1;
|
|
24
31
|
}
|
|
32
|
+
const generationSpinner = (0, ui_1.startSpinner)("Reading schema");
|
|
25
33
|
const schemaText = (0, node_fs_1.readFileSync)(schemaPath, "utf-8");
|
|
34
|
+
generationSpinner.update("Parsing schema routes");
|
|
26
35
|
const parsed = (0, schema_1.parseFexapiSchema)(schemaText);
|
|
27
36
|
if (parsed.errors.length > 0 || !parsed.schema) {
|
|
37
|
+
generationSpinner.fail("Schema parsing failed");
|
|
28
38
|
(0, ui_1.logError)("Failed to generate API from schema.fexapi");
|
|
29
39
|
for (const error of parsed.errors) {
|
|
30
40
|
(0, ui_1.logError)(`- ${error}`);
|
|
31
41
|
}
|
|
32
42
|
return 1;
|
|
33
43
|
}
|
|
44
|
+
generationSpinner.update("Resolving cache state");
|
|
45
|
+
const previousGenerated = (0, node_fs_1.existsSync)(generatedPath)
|
|
46
|
+
? (() => {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse((0, node_fs_1.readFileSync)(generatedPath, "utf-8"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
})()
|
|
54
|
+
: undefined;
|
|
55
|
+
const nextSignature = createRouteSignature({
|
|
56
|
+
port: parsed.schema.port,
|
|
57
|
+
routes: parsed.schema.routes,
|
|
58
|
+
});
|
|
59
|
+
const previousSignature = previousGenerated
|
|
60
|
+
? createRouteSignature(previousGenerated)
|
|
61
|
+
: undefined;
|
|
62
|
+
const schemaChanged = nextSignature !== previousSignature;
|
|
34
63
|
const generated = {
|
|
35
64
|
schemaVersion: 1,
|
|
36
65
|
generatedAt: new Date().toISOString(),
|
|
@@ -38,25 +67,26 @@ const generateFromSchema = () => {
|
|
|
38
67
|
routes: parsed.schema.routes,
|
|
39
68
|
};
|
|
40
69
|
(0, node_fs_1.mkdirSync)(migrationsDirectoryPath, { recursive: true });
|
|
41
|
-
const existingMigrationFiles = (0, node_fs_1.readdirSync)(migrationsDirectoryPath, {
|
|
42
|
-
withFileTypes: true,
|
|
43
|
-
})
|
|
44
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
45
|
-
.map((entry) => (0, node_path_1.join)(migrationsDirectoryPath, entry.name));
|
|
46
|
-
for (const migrationFilePath of existingMigrationFiles) {
|
|
47
|
-
(0, node_fs_1.unlinkSync)(migrationFilePath);
|
|
48
|
-
}
|
|
49
|
-
const migrationId = new Date().toISOString().replace(/[.:]/g, "-");
|
|
50
70
|
const migrationPath = (0, node_path_1.join)(migrationsDirectoryPath, "schema.json");
|
|
51
71
|
const migration = {
|
|
52
|
-
migrationId,
|
|
72
|
+
migrationId: new Date().toISOString().replace(/[.:]/g, "-"),
|
|
53
73
|
sourceSchema: "fexapi/schema.fexapi",
|
|
54
74
|
createdAt: generated.generatedAt,
|
|
55
75
|
port: parsed.schema.port,
|
|
56
76
|
routes: parsed.schema.routes,
|
|
57
77
|
};
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
let generatedStatus = "cached";
|
|
79
|
+
let migrationStatus = "cached";
|
|
80
|
+
if (schemaChanged || !(0, node_fs_1.existsSync)(generatedPath)) {
|
|
81
|
+
generationSpinner.update("Writing generated API spec");
|
|
82
|
+
(0, node_fs_1.writeFileSync)(generatedPath, `${JSON.stringify(generated, null, 2)}\n`, "utf-8");
|
|
83
|
+
generatedStatus = "changed";
|
|
84
|
+
}
|
|
85
|
+
if (schemaChanged || !(0, node_fs_1.existsSync)(migrationPath)) {
|
|
86
|
+
generationSpinner.update("Updating migration snapshot");
|
|
87
|
+
(0, node_fs_1.writeFileSync)(migrationPath, `${JSON.stringify(migration, null, 2)}\n`, "utf-8");
|
|
88
|
+
migrationStatus = "changed";
|
|
89
|
+
}
|
|
60
90
|
let existingConfig = {};
|
|
61
91
|
if ((0, node_fs_1.existsSync)(configPath)) {
|
|
62
92
|
try {
|
|
@@ -70,14 +100,50 @@ const generateFromSchema = () => {
|
|
|
70
100
|
...existingConfig,
|
|
71
101
|
schemaPath: "fexapi/schema.fexapi",
|
|
72
102
|
generatedPath: constants_1.GENERATED_SPEC_RELATIVE_PATH,
|
|
73
|
-
lastGeneratedAt: new Date().toISOString(),
|
|
103
|
+
...(schemaChanged ? { lastGeneratedAt: new Date().toISOString() } : {}),
|
|
74
104
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
(0,
|
|
105
|
+
generationSpinner.update("Syncing project config");
|
|
106
|
+
const nextConfigText = `${JSON.stringify(updatedConfig, null, 2)}\n`;
|
|
107
|
+
const previousConfigText = (0, node_fs_1.existsSync)(configPath)
|
|
108
|
+
? (0, node_fs_1.readFileSync)(configPath, "utf-8")
|
|
109
|
+
: undefined;
|
|
110
|
+
let configStatus = "cached";
|
|
111
|
+
if (previousConfigText !== nextConfigText) {
|
|
112
|
+
(0, node_fs_1.writeFileSync)(configPath, nextConfigText, "utf-8");
|
|
113
|
+
configStatus = "changed";
|
|
114
|
+
}
|
|
115
|
+
generationSpinner.succeed(`Generate complete (${schemaChanged ? "changed" : "cached"})`);
|
|
78
116
|
(0, ui_1.printSpacer)();
|
|
79
|
-
(0, ui_1.
|
|
80
|
-
|
|
117
|
+
(0, ui_1.printSummaryCard)("Generate Summary", [
|
|
118
|
+
{
|
|
119
|
+
label: "routes",
|
|
120
|
+
value: ui_1.ui.cyan(String(parsed.schema.routes.length)),
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
label: "port",
|
|
124
|
+
value: ui_1.ui.cyan(String(parsed.schema.port)),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
label: "schema source",
|
|
128
|
+
value: "fexapi/schema.fexapi",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
label: "generated.api.json",
|
|
132
|
+
value: generatedStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
label: "migration",
|
|
136
|
+
value: migrationStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
label: "config",
|
|
140
|
+
value: configStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
label: "time",
|
|
144
|
+
value: ui_1.ui.bold((0, ui_1.formatDuration)(startedAtMs)),
|
|
145
|
+
},
|
|
146
|
+
]);
|
|
81
147
|
return 0;
|
|
82
148
|
};
|
|
83
149
|
exports.generateFromSchema = generateFromSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAuMA,eAAO,MAAM,iBAAiB,GAAU,YAErC;IACD,KAAK,EAAE,OAAO,CAAC;CAChB,KAAG,OAAO,CAAC,MAAM,CA0MjB,CAAC"}
|
package/dist/commands/init.js
CHANGED
|
@@ -9,7 +9,7 @@ const constants_1 = require("../constants");
|
|
|
9
9
|
const ui_1 = require("../cli/ui");
|
|
10
10
|
const detect_1 = require("../project/detect");
|
|
11
11
|
const paths_1 = require("../project/paths");
|
|
12
|
-
const DEFAULT_INIT_PORT =
|
|
12
|
+
const DEFAULT_INIT_PORT = 4000;
|
|
13
13
|
const parseYesNo = (value, defaultValue) => {
|
|
14
14
|
const normalized = value.trim().toLowerCase();
|
|
15
15
|
if (!normalized) {
|
|
@@ -141,6 +141,7 @@ const SAMPLE_POST_SCHEMA = [
|
|
|
141
141
|
" type: date",
|
|
142
142
|
].join("\n");
|
|
143
143
|
const initializeProject = async ({ force, }) => {
|
|
144
|
+
const initStartedAtMs = (0, ui_1.nowMs)();
|
|
144
145
|
const packageJsonPath = (0, paths_1.findClosestPackageJson)(process.cwd());
|
|
145
146
|
if (!packageJsonPath) {
|
|
146
147
|
(0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
|
|
@@ -156,6 +157,7 @@ const initializeProject = async ({ force, }) => {
|
|
|
156
157
|
const userSchemaPath = (0, node_path_1.join)(schemasDirectoryPath, "user.yaml");
|
|
157
158
|
const postSchemaPath = (0, node_path_1.join)(schemasDirectoryPath, "post.yaml");
|
|
158
159
|
const wizardAnswers = await askInitWizardQuestions();
|
|
160
|
+
const initSpinner = (0, ui_1.startSpinner)("Scaffolding fexapi project files");
|
|
159
161
|
(0, node_fs_1.mkdirSync)(fexapiDirectoryPath, { recursive: true });
|
|
160
162
|
const configExists = (0, node_fs_1.existsSync)(configPath);
|
|
161
163
|
const schemaExists = (0, node_fs_1.existsSync)(schemaPath);
|
|
@@ -171,13 +173,16 @@ const initializeProject = async ({ force, }) => {
|
|
|
171
173
|
createdAt: new Date().toISOString(),
|
|
172
174
|
};
|
|
173
175
|
if (!configExists || force) {
|
|
176
|
+
initSpinner.update("Writing fexapi.config.json");
|
|
174
177
|
(0, node_fs_1.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
|
|
175
178
|
}
|
|
176
179
|
if (!schemaExists || force) {
|
|
180
|
+
initSpinner.update("Writing fexapi/schema.fexapi");
|
|
177
181
|
(0, node_fs_1.writeFileSync)(schemaPath, `${(0, detect_1.getSchemaTemplate)(detectedProject.primaryFramework, wizardAnswers.port)}\n`, "utf-8");
|
|
178
182
|
}
|
|
179
183
|
const runtimeConfigExists = (0, node_fs_1.existsSync)(runtimeConfigPath);
|
|
180
184
|
if (!runtimeConfigExists || force) {
|
|
185
|
+
initSpinner.update("Writing fexapi.config.js");
|
|
181
186
|
(0, node_fs_1.writeFileSync)(runtimeConfigPath, `${getRuntimeConfigTemplate({
|
|
182
187
|
port: wizardAnswers.port,
|
|
183
188
|
cors: wizardAnswers.cors,
|
|
@@ -190,6 +195,7 @@ const initializeProject = async ({ force, }) => {
|
|
|
190
195
|
(0, node_fs_1.mkdirSync)(schemasDirectoryPath, { recursive: true });
|
|
191
196
|
const userSchemaExists = (0, node_fs_1.existsSync)(userSchemaPath);
|
|
192
197
|
if (!userSchemaExists || force) {
|
|
198
|
+
initSpinner.update("Writing sample user schema");
|
|
193
199
|
(0, node_fs_1.writeFileSync)(userSchemaPath, `${SAMPLE_USER_SCHEMA}\n`, "utf-8");
|
|
194
200
|
userSchemaStatus = userSchemaExists ? "overwritten" : "created";
|
|
195
201
|
}
|
|
@@ -198,6 +204,7 @@ const initializeProject = async ({ force, }) => {
|
|
|
198
204
|
}
|
|
199
205
|
const postSchemaExists = (0, node_fs_1.existsSync)(postSchemaPath);
|
|
200
206
|
if (!postSchemaExists || force) {
|
|
207
|
+
initSpinner.update("Writing sample post schema");
|
|
201
208
|
(0, node_fs_1.writeFileSync)(postSchemaPath, `${SAMPLE_POST_SCHEMA}\n`, "utf-8");
|
|
202
209
|
postSchemaStatus = postSchemaExists ? "overwritten" : "created";
|
|
203
210
|
}
|
|
@@ -205,6 +212,7 @@ const initializeProject = async ({ force, }) => {
|
|
|
205
212
|
postSchemaStatus = "exists";
|
|
206
213
|
}
|
|
207
214
|
}
|
|
215
|
+
initSpinner.succeed("Project scaffolding complete");
|
|
208
216
|
(0, ui_1.logSuccess)(`Initialized fexapi in ${projectRoot}`);
|
|
209
217
|
(0, ui_1.logInfo)(`Detected framework: ${detectedProject.primaryFramework}`);
|
|
210
218
|
(0, ui_1.logInfo)(`Detected frameworks: ${detectedProject.frameworks.join(", ")}`);
|
|
@@ -266,6 +274,42 @@ const initializeProject = async ({ force, }) => {
|
|
|
266
274
|
(0, ui_1.logWarn)("No known framework dependency found. Update fexapi.config.json and schema.fexapi if needed.");
|
|
267
275
|
}
|
|
268
276
|
(0, ui_1.printSpacer)();
|
|
277
|
+
const createdFiles = [
|
|
278
|
+
!configExists || force,
|
|
279
|
+
!schemaExists || force,
|
|
280
|
+
!runtimeConfigExists || force,
|
|
281
|
+
userSchemaStatus === "created" || userSchemaStatus === "overwritten",
|
|
282
|
+
postSchemaStatus === "created" || postSchemaStatus === "overwritten",
|
|
283
|
+
].filter(Boolean).length;
|
|
284
|
+
(0, ui_1.printSummaryCard)("Init Summary", [
|
|
285
|
+
{
|
|
286
|
+
label: "framework",
|
|
287
|
+
value: detectedProject.primaryFramework,
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
label: "port",
|
|
291
|
+
value: ui_1.ui.cyan(String(wizardAnswers.port)),
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
label: "cors",
|
|
295
|
+
value: wizardAnswers.cors ? ui_1.ui.green("enabled") : ui_1.ui.gray("disabled"),
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
label: "sample schemas",
|
|
299
|
+
value: wizardAnswers.generateSampleSchemas
|
|
300
|
+
? ui_1.ui.green("enabled")
|
|
301
|
+
: ui_1.ui.gray("disabled"),
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
label: "files changed",
|
|
305
|
+
value: ui_1.ui.bold(String(createdFiles)),
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
label: "time",
|
|
309
|
+
value: ui_1.ui.bold((0, ui_1.formatDuration)(initStartedAtMs)),
|
|
310
|
+
},
|
|
311
|
+
]);
|
|
312
|
+
(0, ui_1.printSpacer)();
|
|
269
313
|
(0, ui_1.logInfo)(`Next: ${(0, ui_1.formatCommand)("fexapi generate")} then ${(0, ui_1.formatCommand)("fexapi serve")}`);
|
|
270
314
|
return 0;
|
|
271
315
|
};
|
package/dist/server.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.startServer = void 0;
|
|
|
4
4
|
const faker_1 = require("@faker-js/faker");
|
|
5
5
|
const node_http_1 = require("node:http");
|
|
6
6
|
const ui_1 = require("./cli/ui");
|
|
7
|
-
const DEFAULT_HOST = "
|
|
7
|
+
const DEFAULT_HOST = "localhost";
|
|
8
8
|
const DEFAULT_PORT = 4000;
|
|
9
9
|
const sendJson = (response, statusCode, payload, options) => {
|
|
10
10
|
const send = () => {
|