fexapi 0.2.1 → 0.2.2

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/ui.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare const ui: {
8
8
  yellow: (text: string) => string;
9
9
  red: (text: string) => string;
10
10
  gray: (text: string) => string;
11
+ white: (text: string) => string;
11
12
  };
12
13
  type SpinnerController = {
13
14
  update: (text: string) => void;
@@ -22,6 +23,7 @@ export declare const printSummaryCard: (title: string, rows: Array<{
22
23
  label: string;
23
24
  value: string;
24
25
  }>) => void;
26
+ export declare const printGroupHeader: (title: string) => void;
25
27
  export declare const printBanner: () => void;
26
28
  export declare const printSpacer: () => void;
27
29
  export declare const logInfo: (message: string) => void;
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAgBA,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;kBACd,MAAM,KAAG,MAAM;CAC9B,CAAC;AA4DF,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,IAqDF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,IAQhD,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,11 +1,12 @@
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.printSummaryCard = exports.formatDuration = exports.nowMs = exports.startSpinner = exports.ui = void 0;
3
+ exports.formatCommand = exports.logStep = exports.logError = exports.logWarn = exports.logSuccess = exports.logInfo = exports.printSpacer = exports.printBanner = exports.printGroupHeader = 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
8
  const interactive = Boolean(process.stdout.isTTY);
9
+ const DEFAULT_TERMINAL_WIDTH = 80;
9
10
  const paint = (code, text) => {
10
11
  if (!colorEnabled) {
11
12
  return text;
@@ -22,8 +23,43 @@ exports.ui = {
22
23
  yellow: (text) => paint("33", text),
23
24
  red: (text) => paint("31", text),
24
25
  gray: (text) => paint("90", text),
26
+ white: (text) => paint("97", text),
27
+ };
28
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
29
+ const ANSI_REGEX = /\u001b\[[0-9;]*m/g;
30
+ const stripAnsi = (text) => text.replace(ANSI_REGEX, "");
31
+ const visibleLength = (text) => stripAnsi(text).length;
32
+ const getTerminalWidth = () => {
33
+ const columns = process.stdout.columns;
34
+ if (!columns || Number.isNaN(columns)) {
35
+ return DEFAULT_TERMINAL_WIDTH;
36
+ }
37
+ return Math.max(40, columns);
38
+ };
39
+ const truncateText = (text, maxLength) => {
40
+ if (text.length <= maxLength) {
41
+ return text;
42
+ }
43
+ if (maxLength <= 1) {
44
+ return text.slice(0, maxLength);
45
+ }
46
+ return `${text.slice(0, maxLength - 1)}…`;
47
+ };
48
+ const styleCardValue = (value) => {
49
+ const normalized = value.trim().toLowerCase();
50
+ if (normalized === "changed" ||
51
+ normalized === "enabled" ||
52
+ normalized === "running") {
53
+ return exports.ui.green(exports.ui.bold(value));
54
+ }
55
+ if (normalized === "cached" || normalized === "disabled") {
56
+ return exports.ui.gray(value);
57
+ }
58
+ if (normalized === "stopped" || normalized === "failed") {
59
+ return exports.ui.red(exports.ui.bold(value));
60
+ }
61
+ return exports.ui.white(exports.ui.bold(value));
25
62
  };
26
- const SPINNER_FRAMES = ["-", "\\", "|", "/"];
27
63
  const clearCurrentLine = () => {
28
64
  if (!interactive) {
29
65
  return;
@@ -45,7 +81,7 @@ const startSpinner = (initialText) => {
45
81
  const render = () => {
46
82
  const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length] ?? "-";
47
83
  frameIndex += 1;
48
- process.stdout.write(`\r${exports.ui.cyan(frame)} ${exports.ui.bold(text)}`);
84
+ process.stdout.write(`\r${exports.ui.cyan(frame)} ${exports.ui.white(exports.ui.bold(text))}`);
49
85
  };
50
86
  render();
51
87
  const timer = setInterval(render, 80);
@@ -56,12 +92,12 @@ const startSpinner = (initialText) => {
56
92
  succeed: (finalText) => {
57
93
  clearInterval(timer);
58
94
  clearCurrentLine();
59
- console.log(`${exports.ui.green("ok")} ${finalText}`);
95
+ console.log(`${exports.ui.green("")} ${exports.ui.white(finalText)}`);
60
96
  },
61
97
  fail: (finalText) => {
62
98
  clearInterval(timer);
63
99
  clearCurrentLine();
64
- console.log(`${exports.ui.red("err")} ${finalText}`);
100
+ console.log(`${exports.ui.red("")} ${exports.ui.white(finalText)}`);
65
101
  },
66
102
  stop: () => {
67
103
  clearInterval(timer);
@@ -81,25 +117,53 @@ const formatDuration = (startMs) => {
81
117
  };
82
118
  exports.formatDuration = formatDuration;
83
119
  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}|`);
120
+ const terminalWidth = getTerminalWidth();
121
+ const compactMode = terminalWidth < 64;
122
+ if (compactMode) {
123
+ console.log(exports.ui.gray(`--- ${title} ---`));
124
+ for (const row of rows) {
125
+ console.log(`${exports.ui.dim(row.label)}: ${row.value}`);
126
+ }
127
+ console.log(exports.ui.gray("---------------"));
128
+ return;
129
+ }
130
+ const safeRows = rows.map((row) => ({
131
+ label: row.label,
132
+ value: row.value,
133
+ }));
134
+ const cardWidth = terminalWidth - 2;
135
+ const innerWidth = cardWidth - 2;
136
+ const labelWidth = Math.min(20, Math.max(10, ...safeRows.map((row) => visibleLength(row.label))));
137
+ const valueSpace = Math.max(8, innerWidth - 3 - labelWidth - 3);
138
+ const topBorder = `┌${"─".repeat(innerWidth)}┐`;
139
+ const divider = `├${"─".repeat(innerWidth)}┤`;
140
+ const bottomBorder = `└${"─".repeat(innerWidth)}┘`;
141
+ console.log(exports.ui.gray(topBorder));
142
+ const renderedTitle = truncateText(title, innerWidth - 2);
143
+ const titlePadding = " ".repeat(Math.max(0, innerWidth - 2 - visibleLength(renderedTitle)));
144
+ console.log(`│ ${exports.ui.bold(exports.ui.cyan(renderedTitle))}${titlePadding} │`);
145
+ console.log(exports.ui.gray(divider));
146
+ for (const row of safeRows) {
147
+ const rawValue = stripAnsi(row.value);
148
+ const value = truncateText(rawValue, valueSpace);
149
+ const label = row.label.padEnd(labelWidth, " ");
150
+ const styledValue = styleCardValue(value);
151
+ const spaces = " ".repeat(Math.max(1, innerWidth - 3 - visibleLength(label) - 3 - visibleLength(value)));
152
+ console.log(`│ ${exports.ui.dim(label)} ${exports.ui.gray("::")} ${styledValue}${spaces}│`);
99
153
  }
100
- console.log(exports.ui.gray(border));
154
+ console.log(exports.ui.gray(bottomBorder));
101
155
  };
102
156
  exports.printSummaryCard = printSummaryCard;
157
+ const printGroupHeader = (title) => {
158
+ const terminalWidth = getTerminalWidth();
159
+ const marker = exports.ui.gray("──");
160
+ const text = ` ${exports.ui.bold(title)} `;
161
+ const lineLength = Math.max(0, terminalWidth - visibleLength(title) - 4);
162
+ const left = marker;
163
+ const right = exports.ui.gray("─".repeat(Math.max(0, lineLength - 2)));
164
+ console.log(`${left}${text}${right}`);
165
+ };
166
+ exports.printGroupHeader = printGroupHeader;
103
167
  const printBanner = () => {
104
168
  console.log(exports.ui.bold(exports.ui.cyan("fexapi")) +
105
169
  exports.ui.gray(" ") +
@@ -112,23 +176,23 @@ const printSpacer = () => {
112
176
  };
113
177
  exports.printSpacer = printSpacer;
114
178
  const logInfo = (message) => {
115
- console.log(`${exports.ui.blue("info")} ${message}`);
179
+ console.log(`${exports.ui.blue("•")} ${exports.ui.blue("info")} ${exports.ui.white(message)}`);
116
180
  };
117
181
  exports.logInfo = logInfo;
118
182
  const logSuccess = (message) => {
119
- console.log(`${exports.ui.green("ok ")} ${message}`);
183
+ console.log(`${exports.ui.green("✓")} ${exports.ui.green("ok ")} ${exports.ui.white(message)}`);
120
184
  };
121
185
  exports.logSuccess = logSuccess;
122
186
  const logWarn = (message) => {
123
- console.log(`${exports.ui.yellow("warn")} ${message}`);
187
+ console.log(`${exports.ui.yellow("!")} ${exports.ui.yellow("warn")} ${exports.ui.white(message)}`);
124
188
  };
125
189
  exports.logWarn = logWarn;
126
190
  const logError = (message) => {
127
- console.error(`${exports.ui.red("err ")} ${message}`);
191
+ console.error(`${exports.ui.red("✕")} ${exports.ui.red("err ")} ${exports.ui.white(message)}`);
128
192
  };
129
193
  exports.logError = logError;
130
194
  const logStep = (message) => {
131
- console.log(`${exports.ui.cyan("->")} ${message}`);
195
+ console.log(`${exports.ui.cyan("")} ${exports.ui.white(message)}`);
132
196
  };
133
197
  exports.logStep = logStep;
134
198
  const formatCommand = (command) => {
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,kBAAkB,QAAO,MA8KrC,CAAC"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,kBAAkB,QAAO,MA6KrC,CAAC"}
@@ -29,6 +29,7 @@ const generateFromSchema = () => {
29
29
  (0, ui_1.logError)("Run `fexapi init` first.");
30
30
  return 1;
31
31
  }
32
+ (0, ui_1.printGroupHeader)("Generate");
32
33
  const generationSpinner = (0, ui_1.startSpinner)("Reading schema");
33
34
  const schemaText = (0, node_fs_1.readFileSync)(schemaPath, "utf-8");
34
35
  generationSpinner.update("Parsing schema routes");
@@ -114,14 +115,15 @@ const generateFromSchema = () => {
114
115
  }
115
116
  generationSpinner.succeed(`Generate complete (${schemaChanged ? "changed" : "cached"})`);
116
117
  (0, ui_1.printSpacer)();
118
+ (0, ui_1.printGroupHeader)("Summary");
117
119
  (0, ui_1.printSummaryCard)("Generate Summary", [
118
120
  {
119
121
  label: "routes",
120
- value: ui_1.ui.cyan(String(parsed.schema.routes.length)),
122
+ value: String(parsed.schema.routes.length),
121
123
  },
122
124
  {
123
125
  label: "port",
124
- value: ui_1.ui.cyan(String(parsed.schema.port)),
126
+ value: String(parsed.schema.port),
125
127
  },
126
128
  {
127
129
  label: "schema source",
@@ -129,19 +131,19 @@ const generateFromSchema = () => {
129
131
  },
130
132
  {
131
133
  label: "generated.api.json",
132
- value: generatedStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
134
+ value: generatedStatus,
133
135
  },
134
136
  {
135
137
  label: "migration",
136
- value: migrationStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
138
+ value: migrationStatus,
137
139
  },
138
140
  {
139
141
  label: "config",
140
- value: configStatus === "changed" ? ui_1.ui.green("changed") : ui_1.ui.gray("cached"),
142
+ value: configStatus,
141
143
  },
142
144
  {
143
145
  label: "time",
144
- value: ui_1.ui.bold((0, ui_1.formatDuration)(startedAtMs)),
146
+ value: (0, ui_1.formatDuration)(startedAtMs),
145
147
  },
146
148
  ]);
147
149
  return 0;
@@ -1 +1 @@
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"}
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,CA2MjB,CAAC"}
@@ -157,6 +157,7 @@ const initializeProject = async ({ force, }) => {
157
157
  const userSchemaPath = (0, node_path_1.join)(schemasDirectoryPath, "user.yaml");
158
158
  const postSchemaPath = (0, node_path_1.join)(schemasDirectoryPath, "post.yaml");
159
159
  const wizardAnswers = await askInitWizardQuestions();
160
+ (0, ui_1.printGroupHeader)("Init");
160
161
  const initSpinner = (0, ui_1.startSpinner)("Scaffolding fexapi project files");
161
162
  (0, node_fs_1.mkdirSync)(fexapiDirectoryPath, { recursive: true });
162
163
  const configExists = (0, node_fs_1.existsSync)(configPath);
@@ -220,6 +221,7 @@ const initializeProject = async ({ force, }) => {
220
221
  (0, ui_1.logInfo)(`Detected tooling: ${detectedProject.tooling.join(", ")}`);
221
222
  }
222
223
  (0, ui_1.printSpacer)();
224
+ (0, ui_1.printGroupHeader)("Files");
223
225
  if (configExists && !force) {
224
226
  (0, ui_1.logWarn)(`Exists ${configPath}`);
225
227
  }
@@ -274,6 +276,7 @@ const initializeProject = async ({ force, }) => {
274
276
  (0, ui_1.logWarn)("No known framework dependency found. Update fexapi.config.json and schema.fexapi if needed.");
275
277
  }
276
278
  (0, ui_1.printSpacer)();
279
+ (0, ui_1.printGroupHeader)("Summary");
277
280
  const createdFiles = [
278
281
  !configExists || force,
279
282
  !schemaExists || force,
@@ -288,25 +291,23 @@ const initializeProject = async ({ force, }) => {
288
291
  },
289
292
  {
290
293
  label: "port",
291
- value: ui_1.ui.cyan(String(wizardAnswers.port)),
294
+ value: String(wizardAnswers.port),
292
295
  },
293
296
  {
294
297
  label: "cors",
295
- value: wizardAnswers.cors ? ui_1.ui.green("enabled") : ui_1.ui.gray("disabled"),
298
+ value: wizardAnswers.cors ? "enabled" : "disabled",
296
299
  },
297
300
  {
298
301
  label: "sample schemas",
299
- value: wizardAnswers.generateSampleSchemas
300
- ? ui_1.ui.green("enabled")
301
- : ui_1.ui.gray("disabled"),
302
+ value: wizardAnswers.generateSampleSchemas ? "enabled" : "disabled",
302
303
  },
303
304
  {
304
305
  label: "files changed",
305
- value: ui_1.ui.bold(String(createdFiles)),
306
+ value: String(createdFiles),
306
307
  },
307
308
  {
308
309
  label: "time",
309
- value: ui_1.ui.bold((0, ui_1.formatDuration)(initStartedAtMs)),
310
+ value: (0, ui_1.formatDuration)(initStartedAtMs),
310
311
  },
311
312
  ]);
312
313
  (0, ui_1.printSpacer)();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fexapi",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Mock API generation CLI tool for local development and testing",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",