@hypequery/cli 1.1.1 → 1.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.
Files changed (77) hide show
  1. package/README.md +71 -149
  2. package/dist/bin/cli.js +21 -81
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +74 -105
  6. package/dist/commands/dev.d.ts +1 -0
  7. package/dist/commands/dev.d.ts.map +1 -1
  8. package/dist/commands/dev.js +180 -255
  9. package/dist/commands/generate-datasets.d.ts +14 -0
  10. package/dist/commands/generate-datasets.d.ts.map +1 -0
  11. package/dist/commands/generate-datasets.js +96 -0
  12. package/dist/commands/generate.d.ts +2 -0
  13. package/dist/commands/generate.d.ts.map +1 -1
  14. package/dist/commands/generate.js +112 -167
  15. package/dist/commands/init.d.ts +7 -1
  16. package/dist/commands/init.d.ts.map +1 -1
  17. package/dist/commands/init.js +337 -390
  18. package/dist/generators/clickhouse.d.ts +1 -1
  19. package/dist/generators/clickhouse.d.ts.map +1 -1
  20. package/dist/generators/clickhouse.js +10 -269
  21. package/dist/generators/dataset-generator.d.ts +16 -0
  22. package/dist/generators/dataset-generator.d.ts.map +1 -0
  23. package/dist/generators/dataset-generator.js +213 -0
  24. package/dist/generators/index.js +4 -4
  25. package/dist/templates/api.d.ts +9 -0
  26. package/dist/templates/api.d.ts.map +1 -0
  27. package/dist/templates/api.js +26 -0
  28. package/dist/templates/auth-scaffold.d.ts +17 -0
  29. package/dist/templates/auth-scaffold.d.ts.map +1 -0
  30. package/dist/templates/auth-scaffold.js +41 -0
  31. package/dist/templates/client.js +10 -1
  32. package/dist/templates/datasets.d.ts +5 -0
  33. package/dist/templates/datasets.d.ts.map +1 -0
  34. package/dist/templates/datasets.js +23 -0
  35. package/dist/templates/env.d.ts +2 -1
  36. package/dist/templates/env.d.ts.map +1 -1
  37. package/dist/templates/env.js +19 -6
  38. package/dist/templates/gitignore.js +4 -1
  39. package/dist/templates/queries.d.ts +3 -0
  40. package/dist/templates/queries.d.ts.map +1 -1
  41. package/dist/templates/queries.js +66 -9
  42. package/dist/test-utils.d.ts +0 -72
  43. package/dist/test-utils.d.ts.map +1 -1
  44. package/dist/test-utils.js +12 -138
  45. package/dist/utils/clickhouse-client.js +11 -58
  46. package/dist/utils/clickhouse-sql.d.ts +6 -0
  47. package/dist/utils/clickhouse-sql.d.ts.map +1 -0
  48. package/dist/utils/clickhouse-sql.js +18 -0
  49. package/dist/utils/clickhouse-type-utils.d.ts +6 -0
  50. package/dist/utils/clickhouse-type-utils.d.ts.map +1 -0
  51. package/dist/utils/clickhouse-type-utils.js +59 -0
  52. package/dist/utils/dependency-installer.d.ts +5 -1
  53. package/dist/utils/dependency-installer.d.ts.map +1 -1
  54. package/dist/utils/dependency-installer.js +117 -134
  55. package/dist/utils/detect-database.js +84 -195
  56. package/dist/utils/find-files.d.ts +3 -1
  57. package/dist/utils/find-files.d.ts.map +1 -1
  58. package/dist/utils/find-files.js +82 -148
  59. package/dist/utils/load-api.d.ts.map +1 -1
  60. package/dist/utils/load-api.js +207 -396
  61. package/dist/utils/logger.js +38 -42
  62. package/dist/utils/prompts.d.ts +14 -5
  63. package/dist/utils/prompts.d.ts.map +1 -1
  64. package/dist/utils/prompts.js +170 -244
  65. package/dist/utils/runtime-guards.d.ts +4 -0
  66. package/dist/utils/runtime-guards.d.ts.map +1 -0
  67. package/dist/utils/runtime-guards.js +9 -0
  68. package/dist/utils/sha256.d.ts +2 -0
  69. package/dist/utils/sha256.d.ts.map +1 -0
  70. package/dist/utils/sha256.js +4 -0
  71. package/package.json +4 -4
  72. package/dist/utils/error-messages.d.ts +0 -6
  73. package/dist/utils/error-messages.d.ts.map +0 -1
  74. package/dist/utils/error-messages.js +0 -19
  75. package/dist/utils/load-hypequery-config.d.ts +0 -7
  76. package/dist/utils/load-hypequery-config.d.ts.map +0 -1
  77. package/dist/utils/load-hypequery-config.js +0 -89
@@ -0,0 +1,59 @@
1
+ export function splitTopLevelArgs(value) {
2
+ const parts = [];
3
+ let current = '';
4
+ let depth = 0;
5
+ let quote = null;
6
+ for (const char of value) {
7
+ if (quote) {
8
+ current += char;
9
+ if (char === quote) {
10
+ quote = null;
11
+ }
12
+ continue;
13
+ }
14
+ if (char === "'" || char === '"' || char === '`') {
15
+ quote = char;
16
+ current += char;
17
+ continue;
18
+ }
19
+ if (char === '(') {
20
+ depth += 1;
21
+ current += char;
22
+ continue;
23
+ }
24
+ if (char === ')') {
25
+ depth -= 1;
26
+ current += char;
27
+ continue;
28
+ }
29
+ if (char === ',' && depth === 0) {
30
+ parts.push(current.trim());
31
+ current = '';
32
+ continue;
33
+ }
34
+ current += char;
35
+ }
36
+ if (current.trim()) {
37
+ parts.push(current.trim());
38
+ }
39
+ return parts;
40
+ }
41
+ export function unwrapType(type, wrapperName) {
42
+ const prefix = `${wrapperName}(`;
43
+ return type.startsWith(prefix) && type.endsWith(')') ? type.slice(prefix.length, -1) : null;
44
+ }
45
+ export function matchTypeCall(type, name) {
46
+ const inner = unwrapType(type, name);
47
+ return inner === null ? null : splitTopLevelArgs(inner);
48
+ }
49
+ export function unquoteClickHouseString(value) {
50
+ const trimmed = value.trim();
51
+ if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
52
+ (trimmed.startsWith('"') && trimmed.endsWith('"'))) {
53
+ return trimmed.slice(1, -1);
54
+ }
55
+ return trimmed;
56
+ }
57
+ export function isIntegerLiteral(value) {
58
+ return /^\d+$/.test(value.trim());
59
+ }
@@ -1,2 +1,6 @@
1
- export declare function installServeDependencies(): Promise<void>;
1
+ type ScaffoldStyle = 'queries' | 'datasets';
2
+ export declare function resolveScaffoldPackages(cliVersion: string | undefined, style?: ScaffoldStyle): string[];
3
+ export declare function installScaffoldDependencies(style?: ScaffoldStyle): Promise<void>;
4
+ export declare const installServeDependencies: typeof installScaffoldDependencies;
5
+ export {};
2
6
  //# sourceMappingURL=dependency-installer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-installer.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-installer.ts"],"names":[],"mappings":"AAyEA,wBAAsB,wBAAwB,kBA4C7C"}
1
+ {"version":3,"file":"dependency-installer.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-installer.ts"],"names":[],"mappings":"AASA,KAAK,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AA0F5C,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,GAAE,aAAyB,GAAG,MAAM,EAAE,CAgBlH;AAsBD,wBAAsB,2BAA2B,CAAC,KAAK,GAAE,aAAyB,iBAiDjF;AAED,eAAO,MAAM,wBAAwB,oCAA8B,CAAC"}
@@ -1,100 +1,63 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
38
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
39
- if (ar || !(i in from)) {
40
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
41
- ar[i] = from[i];
42
- }
43
- }
44
- return to.concat(ar || Array.prototype.slice.call(from));
45
- };
46
1
  import { existsSync } from 'node:fs';
47
2
  import { readFile } from 'node:fs/promises';
48
3
  import path from 'node:path';
49
4
  import { spawn } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
50
6
  import { logger } from './logger.js';
51
- var REQUIRED_PACKAGES = ['@hypequery/clickhouse', '@hypequery/serve'];
52
- var MANUAL_COMMANDS = {
7
+ const ZOD_SCAFFOLD_VERSION = '^3.23.8';
8
+ const STABLE_SCAFFOLD_PACKAGES = ['@hypequery/clickhouse', '@hypequery/serve', `zod@${ZOD_SCAFFOLD_VERSION}`];
9
+ const CLI_PACKAGE_PATH = fileURLToPath(new URL('../../package.json', import.meta.url));
10
+ const MANUAL_COMMANDS = {
53
11
  pnpm: 'pnpm add',
54
12
  yarn: 'yarn add',
55
13
  npm: 'npm install',
56
14
  bun: 'bun add',
57
15
  };
58
- function hasDependency(pkg, name) {
59
- var _a, _b, _c;
60
- return Boolean((_b = (_a = pkg.dependencies) === null || _a === void 0 ? void 0 : _a[name]) !== null && _b !== void 0 ? _b : (_c = pkg.devDependencies) === null || _c === void 0 ? void 0 : _c[name]);
16
+ function getDependencyVersion(pkg, name) {
17
+ return pkg.dependencies?.[name] ?? pkg.devDependencies?.[name];
61
18
  }
62
- function readProjectPackageJson() {
63
- return __awaiter(this, void 0, void 0, function () {
64
- var file, _a;
65
- return __generator(this, function (_b) {
66
- switch (_b.label) {
67
- case 0:
68
- _b.trys.push([0, 2, , 3]);
69
- return [4 /*yield*/, readFile(path.join(process.cwd(), 'package.json'), 'utf8')];
70
- case 1:
71
- file = _b.sent();
72
- return [2 /*return*/, JSON.parse(file)];
73
- case 2:
74
- _a = _b.sent();
75
- return [2 /*return*/, null];
76
- case 3: return [2 /*return*/];
77
- }
78
- });
79
- });
19
+ function packageNameFromSpecifier(specifier) {
20
+ if (!specifier.startsWith('@')) {
21
+ const atIndex = specifier.lastIndexOf('@');
22
+ return atIndex > 0 ? specifier.slice(0, atIndex) : specifier;
23
+ }
24
+ const separatorIndex = specifier.indexOf('@', specifier.indexOf('/') + 1);
25
+ return separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex);
26
+ }
27
+ async function readProjectPackageJson() {
28
+ try {
29
+ const file = await readFile(path.join(process.cwd(), 'package.json'), 'utf8');
30
+ return JSON.parse(file);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ async function readCliPackageJson() {
37
+ try {
38
+ const file = await readFile(CLI_PACKAGE_PATH, 'utf8');
39
+ return JSON.parse(file);
40
+ }
41
+ catch {
42
+ return null;
43
+ }
80
44
  }
81
45
  function detectPackageManager(pkgJson) {
82
- var _a, _b;
83
- var userAgent = (_a = process.env.npm_config_user_agent) !== null && _a !== void 0 ? _a : '';
46
+ const userAgent = process.env.npm_config_user_agent ?? '';
84
47
  if (userAgent.includes('pnpm'))
85
48
  return 'pnpm';
86
49
  if (userAgent.includes('yarn'))
87
50
  return 'yarn';
88
51
  if (userAgent.includes('bun'))
89
52
  return 'bun';
90
- var declared = (_b = pkgJson === null || pkgJson === void 0 ? void 0 : pkgJson.packageManager) !== null && _b !== void 0 ? _b : '';
53
+ const declared = pkgJson?.packageManager ?? '';
91
54
  if (declared.startsWith('pnpm'))
92
55
  return 'pnpm';
93
56
  if (declared.startsWith('yarn'))
94
57
  return 'yarn';
95
58
  if (declared.startsWith('bun'))
96
59
  return 'bun';
97
- var cwd = process.cwd();
60
+ const cwd = process.cwd();
98
61
  if (existsSync(path.join(cwd, 'pnpm-lock.yaml')))
99
62
  return 'pnpm';
100
63
  if (existsSync(path.join(cwd, 'yarn.lock')))
@@ -106,75 +69,95 @@ function detectPackageManager(pkgJson) {
106
69
  function getInstallArgs(manager, packages) {
107
70
  switch (manager) {
108
71
  case 'pnpm':
109
- return __spreadArray(['add'], packages, true);
72
+ return ['add', ...packages];
110
73
  case 'yarn':
111
- return __spreadArray(['add'], packages, true);
74
+ return ['add', ...packages];
112
75
  case 'bun':
113
- return __spreadArray(['add'], packages, true);
76
+ return ['add', ...packages];
114
77
  case 'npm':
115
78
  default:
116
- return __spreadArray(['install'], packages, true);
79
+ return ['install', ...packages];
117
80
  }
118
81
  }
119
82
  function formatManualCommand(manager, packages) {
120
- return "".concat(MANUAL_COMMANDS[manager], " ").concat(packages.join(' '));
83
+ return `${MANUAL_COMMANDS[manager]} ${packages.join(' ')}`;
84
+ }
85
+ export function resolveScaffoldPackages(cliVersion, style = 'queries') {
86
+ const includeDatasets = style === 'datasets';
87
+ if (cliVersion?.includes('canary')) {
88
+ return [
89
+ `@hypequery/clickhouse@${cliVersion}`,
90
+ `@hypequery/serve@${cliVersion}`,
91
+ ...(includeDatasets ? [`@hypequery/datasets@${cliVersion}`] : []),
92
+ `zod@${ZOD_SCAFFOLD_VERSION}`,
93
+ ];
94
+ }
95
+ return [
96
+ ...STABLE_SCAFFOLD_PACKAGES,
97
+ ...(includeDatasets ? ['@hypequery/datasets'] : []),
98
+ ];
99
+ }
100
+ function shouldInstallPackage(pkgJson, specifier) {
101
+ const name = packageNameFromSpecifier(specifier);
102
+ const existingVersion = getDependencyVersion(pkgJson, name);
103
+ if (!existingVersion) {
104
+ return true;
105
+ }
106
+ const desiredHasPinnedVersion = specifier.startsWith('@')
107
+ ? specifier.indexOf('@', specifier.indexOf('/') + 1) !== -1
108
+ : specifier.includes('@');
109
+ if (!desiredHasPinnedVersion) {
110
+ return false;
111
+ }
112
+ const desiredVersion = specifier.slice(name.length + 1);
113
+ return existingVersion !== desiredVersion;
121
114
  }
122
- export function installServeDependencies() {
123
- return __awaiter(this, void 0, void 0, function () {
124
- var pkgJson, missing, manager, command, args, error_1;
125
- return __generator(this, function (_a) {
126
- switch (_a.label) {
127
- case 0:
128
- if (process.env.HYPEQUERY_SKIP_INSTALL === '1') {
129
- return [2 /*return*/];
130
- }
131
- return [4 /*yield*/, readProjectPackageJson()];
132
- case 1:
133
- pkgJson = _a.sent();
134
- if (!pkgJson) {
135
- logger.warn('package.json not found. Install @hypequery/clickhouse and @hypequery/serve manually.');
136
- return [2 /*return*/];
137
- }
138
- missing = REQUIRED_PACKAGES.filter(function (pkg) { return !hasDependency(pkgJson, pkg); });
139
- if (missing.length === 0) {
140
- return [2 /*return*/];
141
- }
142
- manager = detectPackageManager(pkgJson);
143
- command = manager === 'npm' ? 'npm' : manager;
144
- args = getInstallArgs(manager, missing);
145
- logger.info("Installing ".concat(missing.join(', '), " with ").concat(manager, "..."));
146
- _a.label = 2;
147
- case 2:
148
- _a.trys.push([2, 4, , 5]);
149
- return [4 /*yield*/, new Promise(function (resolve, reject) {
150
- var child = spawn(command, args, {
151
- cwd: process.cwd(),
152
- stdio: 'inherit',
153
- });
154
- child.on('error', reject);
155
- child.on('close', function (code) {
156
- if (code === 0) {
157
- resolve();
158
- }
159
- else {
160
- reject(new Error("".concat(command, " exited with code ").concat(code)));
161
- }
162
- });
163
- })];
164
- case 3:
165
- _a.sent();
166
- logger.success("Installed ".concat(missing.join(', ')));
167
- return [3 /*break*/, 5];
168
- case 4:
169
- error_1 = _a.sent();
170
- logger.warn('Failed to install hypequery packages automatically.');
171
- logger.info("Run manually: ".concat(formatManualCommand(manager, missing)));
172
- if (error_1 instanceof Error && error_1.message) {
173
- logger.info(error_1.message);
174
- }
175
- return [3 /*break*/, 5];
176
- case 5: return [2 /*return*/];
177
- }
115
+ export async function installScaffoldDependencies(style = 'queries') {
116
+ if (process.env.HYPEQUERY_SKIP_INSTALL === '1') {
117
+ return;
118
+ }
119
+ const [pkgJson, cliPkgJson] = await Promise.all([
120
+ readProjectPackageJson(),
121
+ readCliPackageJson(),
122
+ ]);
123
+ if (!pkgJson) {
124
+ const extra = style === 'datasets' ? ', @hypequery/datasets' : '';
125
+ logger.warn(`package.json not found. Install @hypequery/clickhouse, @hypequery/serve${extra}, and zod manually.`);
126
+ return;
127
+ }
128
+ const requestedPackages = resolveScaffoldPackages(cliPkgJson?.version, style);
129
+ const missing = requestedPackages.filter(pkg => shouldInstallPackage(pkgJson, pkg));
130
+ if (missing.length === 0) {
131
+ return;
132
+ }
133
+ const manager = detectPackageManager(pkgJson);
134
+ const command = manager === 'npm' ? 'npm' : manager;
135
+ const args = getInstallArgs(manager, missing);
136
+ logger.info(`Installing ${missing.join(', ')} with ${manager}...`);
137
+ try {
138
+ await new Promise((resolve, reject) => {
139
+ const child = spawn(command, args, {
140
+ cwd: process.cwd(),
141
+ stdio: 'inherit',
142
+ });
143
+ child.on('error', reject);
144
+ child.on('close', code => {
145
+ if (code === 0) {
146
+ resolve();
147
+ }
148
+ else {
149
+ reject(new Error(`${command} exited with code ${code}`));
150
+ }
151
+ });
178
152
  });
179
- });
153
+ logger.success(`Installed ${missing.join(', ')}`);
154
+ }
155
+ catch (error) {
156
+ logger.warn('Failed to install hypequery packages automatically.');
157
+ logger.info(`Run manually: ${formatManualCommand(manager, missing)}`);
158
+ if (error instanceof Error && error.message) {
159
+ logger.info(error.message);
160
+ }
161
+ }
180
162
  }
163
+ export const installServeDependencies = installScaffoldDependencies;