generate-ui-cli 2.1.7 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateMenu = generateMenu;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function generateMenu(schemasRoot) {
10
+ const menu = loadMenuConfig(schemasRoot) ??
11
+ buildMenuFromRoutes(loadRoutesConfig(schemasRoot)) ?? {
12
+ groups: [],
13
+ ungrouped: []
14
+ };
15
+ const out = path_1.default.join(schemasRoot, 'menu.gen.ts');
16
+ const content = `
17
+ export type GeneratedMenuItem = {
18
+ id: string
19
+ label: string
20
+ route: string
21
+ hidden?: boolean
22
+ icon?: string
23
+ }
24
+
25
+ export type GeneratedMenuGroup = {
26
+ id: string
27
+ label: string
28
+ items: GeneratedMenuItem[]
29
+ hidden?: boolean
30
+ }
31
+
32
+ export type GeneratedMenu = {
33
+ groups: GeneratedMenuGroup[]
34
+ ungrouped: GeneratedMenuItem[]
35
+ }
36
+
37
+ export const generatedMenu: GeneratedMenu = ${JSON.stringify(normalizeMenu(menu), null, 2)}
38
+ `;
39
+ fs_1.default.writeFileSync(out, content.trimStart());
40
+ }
41
+ function loadMenuConfig(schemasRoot) {
42
+ const overridePath = path_1.default.join(schemasRoot, 'menu.overrides.json');
43
+ const basePath = path_1.default.join(schemasRoot, 'menu.json');
44
+ if (fs_1.default.existsSync(overridePath)) {
45
+ const override = JSON.parse(fs_1.default.readFileSync(overridePath, 'utf-8'));
46
+ const hasOverride = Array.isArray(override?.groups) &&
47
+ override.groups.length > 0
48
+ ? true
49
+ : Array.isArray(override?.ungrouped) &&
50
+ override.ungrouped.length > 0;
51
+ if (hasOverride) {
52
+ return override;
53
+ }
54
+ }
55
+ if (fs_1.default.existsSync(basePath)) {
56
+ return JSON.parse(fs_1.default.readFileSync(basePath, 'utf-8'));
57
+ }
58
+ return null;
59
+ }
60
+ function loadRoutesConfig(schemasRoot) {
61
+ const routesPath = path_1.default.join(schemasRoot, 'routes.json');
62
+ if (!fs_1.default.existsSync(routesPath))
63
+ return null;
64
+ try {
65
+ return JSON.parse(fs_1.default.readFileSync(routesPath, 'utf-8'));
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ function normalizeMenu(value) {
72
+ return {
73
+ groups: Array.isArray(value?.groups)
74
+ ? value.groups.map(normalizeGroup)
75
+ : [],
76
+ ungrouped: Array.isArray(value?.ungrouped)
77
+ ? value.ungrouped.map(normalizeItem)
78
+ : []
79
+ };
80
+ }
81
+ function normalizeGroup(value) {
82
+ return {
83
+ id: String(value?.id ?? ''),
84
+ label: String(value?.label ?? ''),
85
+ hidden: Boolean(value?.hidden) || undefined,
86
+ items: Array.isArray(value?.items)
87
+ ? value.items.map(normalizeItem)
88
+ : []
89
+ };
90
+ }
91
+ function normalizeItem(value) {
92
+ return {
93
+ id: String(value?.id ?? ''),
94
+ label: String(value?.label ?? ''),
95
+ route: String(value?.route ?? ''),
96
+ hidden: Boolean(value?.hidden) || undefined,
97
+ icon: value?.icon ? String(value.icon) : undefined
98
+ };
99
+ }
100
+ function buildMenuFromRoutes(routes) {
101
+ if (!Array.isArray(routes) || routes.length === 0)
102
+ return null;
103
+ const groups = [];
104
+ const ungrouped = [];
105
+ const groupMap = new Map();
106
+ for (const route of routes) {
107
+ if (!route?.path || !route?.operationId)
108
+ continue;
109
+ const item = {
110
+ id: String(route.operationId),
111
+ label: String(route.label ?? route.operationId),
112
+ route: normalizeRoutePath(String(route.path ?? route.operationId ?? ''))
113
+ };
114
+ const rawGroup = route.group ? String(route.group) : '';
115
+ if (!rawGroup) {
116
+ ungrouped.push(item);
117
+ continue;
118
+ }
119
+ const groupId = toKebab(rawGroup);
120
+ let group = groupMap.get(groupId);
121
+ if (!group) {
122
+ group = {
123
+ id: groupId,
124
+ label: toLabel(rawGroup),
125
+ items: []
126
+ };
127
+ groupMap.set(groupId, group);
128
+ groups.push(group);
129
+ }
130
+ group.items.push(item);
131
+ }
132
+ return { groups, ungrouped };
133
+ }
134
+ function toKebab(value) {
135
+ return String(value)
136
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
137
+ .replace(/[_\\s]+/g, '-')
138
+ .toLowerCase();
139
+ }
140
+ function toLabel(value) {
141
+ return String(value)
142
+ .replace(/[_-]/g, ' ')
143
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
144
+ .replace(/\\b\\w/g, char => char.toUpperCase());
145
+ }
146
+ function normalizeRoutePath(value) {
147
+ if (!value)
148
+ return value;
149
+ if (value.includes('/'))
150
+ return value.replace(/^\//, '');
151
+ const pascal = toPascalCase(value);
152
+ return toRouteSegment(pascal);
153
+ }
154
+ function toRouteSegment(value) {
155
+ if (!value)
156
+ return value;
157
+ return value[0].toLowerCase() + value.slice(1);
158
+ }
159
+ function toPascalCase(value) {
160
+ return String(value)
161
+ .split(/[^a-zA-Z0-9]+/)
162
+ .filter(Boolean)
163
+ .map(part => part[0].toUpperCase() + part.slice(1))
164
+ .join('');
165
+ }
package/dist/index.js CHANGED
@@ -7,12 +7,15 @@ const angular_1 = require("./commands/angular");
7
7
  const login_1 = require("./commands/login");
8
8
  const config_1 = require("./runtime/config");
9
9
  const telemetry_1 = require("./telemetry");
10
+ const logger_1 = require("./runtime/logger");
10
11
  const program = new commander_1.Command();
11
12
  program
12
13
  .name('generate-ui')
13
14
  .description('Generate UI from OpenAPI')
14
15
  .version((0, config_1.getCliVersion)())
15
- .option('--no-telemetry', 'Disable telemetry');
16
+ .option('--no-telemetry', 'Disable telemetry')
17
+ .option('--dev', 'Enable verbose logs')
18
+ .option('--verbose', 'Enable verbose logs (same as --dev)');
16
19
  /**
17
20
  * 1️⃣ OpenAPI → Screen schemas
18
21
  */
@@ -23,7 +26,8 @@ program
23
26
  .option('--output <path>', 'Output directory for generate-ui (default: ./src/generate-ui or ./generate-ui)')
24
27
  .option('-d, --debug', 'Explain merge decisions')
25
28
  .action(async (options) => {
26
- const { telemetry } = program.opts();
29
+ const { telemetry, dev, verbose } = program.opts();
30
+ (0, logger_1.setVerbose)(Boolean(dev || verbose));
27
31
  try {
28
32
  await (0, telemetry_1.trackGenerateCalled)();
29
33
  await (0, generate_1.generate)({
@@ -46,7 +50,8 @@ program
46
50
  .option('-s, --schemas <path>', 'Directory containing generate-ui (with overlays/)')
47
51
  .option('-f, --features <path>', 'Angular features output directory')
48
52
  .action(async (options) => {
49
- const { telemetry } = program.opts();
53
+ const { telemetry, dev, verbose } = program.opts();
54
+ (0, logger_1.setVerbose)(Boolean(dev || verbose));
50
55
  try {
51
56
  await (0, angular_1.angular)({
52
57
  schemasPath: options.schemas,
@@ -65,7 +70,8 @@ program
65
70
  .command('login')
66
71
  .description('Login to unlock Dev features')
67
72
  .action(async () => {
68
- const { telemetry } = program.opts();
73
+ const { telemetry, dev, verbose } = program.opts();
74
+ (0, logger_1.setVerbose)(Boolean(dev || verbose));
69
75
  try {
70
76
  await (0, login_1.login)({ telemetryEnabled: telemetry });
71
77
  }
@@ -76,6 +82,15 @@ program
76
82
  function handleCliError(error) {
77
83
  if (error instanceof Error) {
78
84
  console.error(error.message.replace(/\\n/g, '\n'));
85
+ if ((0, logger_1.isVerbose)() && error.stack) {
86
+ console.error('');
87
+ console.error('🔎 Stack trace:');
88
+ console.error(error.stack);
89
+ }
90
+ else {
91
+ console.error('');
92
+ console.error('ℹ️ Tip: re-run with --dev to see detailed logs.');
93
+ }
79
94
  }
80
95
  else {
81
96
  console.error('Unexpected error');
@@ -86,7 +86,7 @@ async function getPermissions() {
86
86
  return { plan: cache.plan, features: cache.features };
87
87
  }
88
88
  if (tokenPresent) {
89
- throw new Error('Please reconnect to verify your license.');
89
+ throw new Error('Login concluído, mas não foi possível validar sua licença agora. Verifique sua conexão com a API e tente novamente.');
90
90
  }
91
91
  return FREE_DEFAULT;
92
92
  }
@@ -25,16 +25,32 @@ function loadToken() {
25
25
  const parsed = JSON.parse(fs_1.default.readFileSync(TOKEN_PATH, 'utf-8'));
26
26
  if (!parsed.accessToken || !parsed.expiresAt)
27
27
  return null;
28
- const expiresAt = new Date(parsed.expiresAt).getTime();
29
- if (Number.isNaN(expiresAt) || expiresAt <= Date.now()) {
28
+ const expiresAt = normalizeExpiresAt(parsed.expiresAt);
29
+ if (!expiresAt || expiresAt <= Date.now()) {
30
30
  return null;
31
31
  }
32
- return parsed;
32
+ return {
33
+ ...parsed,
34
+ expiresAt: new Date(expiresAt).toISOString()
35
+ };
33
36
  }
34
37
  catch {
35
38
  return null;
36
39
  }
37
40
  }
41
+ function normalizeExpiresAt(value) {
42
+ const trimmed = String(value).trim();
43
+ if (!trimmed.length)
44
+ return null;
45
+ const asNumber = Number(trimmed);
46
+ if (Number.isFinite(asNumber)) {
47
+ return asNumber < 1e12 ? asNumber * 1000 : asNumber;
48
+ }
49
+ const parsed = new Date(trimmed).getTime();
50
+ if (Number.isNaN(parsed))
51
+ return null;
52
+ return parsed;
53
+ }
38
54
  function saveToken(token) {
39
55
  ensureConfigDir();
40
56
  fs_1.default.writeFileSync(TOKEN_PATH, JSON.stringify(token, null, 2));
@@ -26,3 +26,10 @@ async function sendInstallEvent() {
26
26
  }
27
27
  }
28
28
  void sendInstallEvent();
29
+ console.log('');
30
+ console.log('👋 GenerateUI CLI installed');
31
+ console.log(' Quick start:');
32
+ console.log(' 1) generate-ui generate --openapi /path/to/openapi.yaml');
33
+ console.log(' 2) generate-ui angular --schemas /path/to/generate-ui --features /path/to/app/src/app/features');
34
+ console.log(' Tip: customize screens in generate-ui/overlays and menu in generate-ui/menu.overrides.json');
35
+ console.log('');
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setVerbose = setVerbose;
4
+ exports.isVerbose = isVerbose;
5
+ exports.logDebug = logDebug;
6
+ exports.logStep = logStep;
7
+ exports.logTip = logTip;
8
+ let verbose = false;
9
+ function setVerbose(value) {
10
+ verbose = value;
11
+ }
12
+ function isVerbose() {
13
+ return verbose;
14
+ }
15
+ function logDebug(message) {
16
+ if (!verbose)
17
+ return;
18
+ console.log(`🔎 ${message}`);
19
+ }
20
+ function logStep(message) {
21
+ if (!verbose)
22
+ return;
23
+ console.log(`🧭 ${message}`);
24
+ }
25
+ function logTip(message) {
26
+ if (!verbose)
27
+ return;
28
+ console.log(`💡 ${message}`);
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generate-ui-cli",
3
- "version": "2.1.7",
3
+ "version": "2.2.0",
4
4
  "description": "Generate UI from OpenAPI",
5
5
  "license": "MIT",
6
6
  "repository": {