@hypequery/cli 1.17.0 → 1.18.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.
@@ -1 +1 @@
1
- {"version":3,"file":"generate-types.d.ts","sourceRoot":"","sources":["../../src/typegen/generate-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,KAAK,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC;QAChE,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;KAChD,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,qCAAqC;IACrC,MAAM,EAAE,8BAA8B,CAAC;IACvC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA2HD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,8BAA8B,EACtC,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAM,GACjD,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB"}
1
+ {"version":3,"file":"generate-types.d.ts","sourceRoot":"","sources":["../../src/typegen/generate-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,KAAK,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC;QAChE,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;KAChD,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,qCAAqC;IACrC,MAAM,EAAE,8BAA8B,CAAC;IACvC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA0HD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,8BAA8B,EACtC,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAM,GACjD,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB"}
@@ -61,8 +61,7 @@ export interface IntrospectedSchema {`;
61
61
  const columns = await describeTable(client, table.name);
62
62
  typeDefinitions += `\n ${table.name}: {`;
63
63
  for (const column of columns) {
64
- const clickHouseType = column.type.replace(/'/g, "\\'"); // Escape single quotes, e.g. `DateTime('UTC')`
65
- typeDefinitions += `\n '${column.name}': '${clickHouseType}';`;
64
+ typeDefinitions += `\n '${column.name}': ${JSON.stringify(column.type)};`;
66
65
  }
67
66
  typeDefinitions += '\n };';
68
67
  }
@@ -73,7 +72,7 @@ export interface IntrospectedSchema {`;
73
72
  const columns = await describeTable(client, table.name);
74
73
  typeDefinitions += `export interface ${capitalizeFirstLetter(table.name)}Record {`;
75
74
  for (const column of columns) {
76
- const tsType = clickhouseToTsType(column.type).replace(/'/g, '');
75
+ const tsType = clickhouseToTsType(column.type);
77
76
  typeDefinitions += `\n '${column.name}': ${tsType};`;
78
77
  }
79
78
  typeDefinitions += '\n}\n\n';
@@ -1 +1 @@
1
- {"version":3,"file":"type-parsing.d.ts","sourceRoot":"","sources":["../../src/typegen/type-parsing.ts"],"names":[],"mappings":"AAuGA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAsCjD,CAAC"}
1
+ {"version":3,"file":"type-parsing.d.ts","sourceRoot":"","sources":["../../src/typegen/type-parsing.ts"],"names":[],"mappings":"AAwLA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MA6CjD,CAAC"}
@@ -2,7 +2,27 @@ function splitTopLevelArgs(value) {
2
2
  const parts = [];
3
3
  let current = '';
4
4
  let depth = 0;
5
+ let quote = null;
6
+ let escaped = false;
5
7
  for (const char of value) {
8
+ if (quote) {
9
+ current += char;
10
+ if (escaped) {
11
+ escaped = false;
12
+ }
13
+ else if (char === '\\') {
14
+ escaped = true;
15
+ }
16
+ else if (char === quote) {
17
+ quote = null;
18
+ }
19
+ continue;
20
+ }
21
+ if (char === "'" || char === '"' || char === '`') {
22
+ quote = char;
23
+ current += char;
24
+ continue;
25
+ }
6
26
  if (char === '(') {
7
27
  depth += 1;
8
28
  current += char;
@@ -25,6 +45,50 @@ function splitTopLevelArgs(value) {
25
45
  }
26
46
  return parts;
27
47
  }
48
+ function decodeClickHouseEscape(char) {
49
+ switch (char) {
50
+ case 'b': return '\b';
51
+ case 'f': return '\f';
52
+ case 'n': return '\n';
53
+ case 'r': return '\r';
54
+ case 't': return '\t';
55
+ case '0': return '\0';
56
+ default: return char;
57
+ }
58
+ }
59
+ function parseBacktickTuplePart(part) {
60
+ let name = '';
61
+ let escaped = false;
62
+ for (let index = 1; index < part.length; index += 1) {
63
+ const char = part[index];
64
+ if (escaped) {
65
+ name += decodeClickHouseEscape(char);
66
+ escaped = false;
67
+ continue;
68
+ }
69
+ if (char === '\\') {
70
+ escaped = true;
71
+ continue;
72
+ }
73
+ if (char === '`') {
74
+ const type = part.slice(index + 1);
75
+ return /^\s+\S/s.test(type) ? { name, type: type.trim() } : null;
76
+ }
77
+ name += char;
78
+ }
79
+ return null;
80
+ }
81
+ function parseNamedTuplePart(value) {
82
+ const part = value.trim();
83
+ if (part.startsWith('`')) {
84
+ return parseBacktickTuplePart(part);
85
+ }
86
+ const match = /^([A-Za-z_][A-Za-z0-9_]*)\s+(.+)$/s.exec(part);
87
+ return match ? { name: match[1], type: match[2].trim() } : null;
88
+ }
89
+ function formatTypeScriptProperty(name) {
90
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
91
+ }
28
92
  function unwrapType(type, wrapperName) {
29
93
  // Trim whitespace and handle case-insensitive matching
30
94
  const trimmedType = type.trim();
@@ -104,24 +168,31 @@ function getPrimitiveTsType(type) {
104
168
  * equivalent TypeScript type string.
105
169
  */
106
170
  export const clickhouseToTsType = (type) => {
107
- const wrappedArrayType = unwrapType(type, 'Array');
171
+ const normalizedType = type.trim();
172
+ const wrappedArrayType = unwrapType(normalizedType, 'Array');
108
173
  if (wrappedArrayType) {
109
174
  return `Array<${clickhouseToTsType(wrappedArrayType)}>`;
110
175
  }
111
- const wrappedNullableType = unwrapType(type, 'Nullable');
176
+ const wrappedNullableType = unwrapType(normalizedType, 'Nullable');
112
177
  if (wrappedNullableType) {
113
178
  return `${clickhouseToTsType(wrappedNullableType)} | null`;
114
179
  }
115
- const wrappedLowCardinalityType = unwrapType(type, 'LowCardinality');
180
+ const wrappedLowCardinalityType = unwrapType(normalizedType, 'LowCardinality');
116
181
  if (wrappedLowCardinalityType) {
117
182
  return clickhouseToTsType(wrappedLowCardinalityType);
118
183
  }
119
- const wrappedTupleType = unwrapType(type, 'Tuple');
184
+ const wrappedTupleType = unwrapType(normalizedType, 'Tuple');
120
185
  if (wrappedTupleType) {
121
186
  const tupleParts = splitTopLevelArgs(wrappedTupleType);
187
+ const namedParts = tupleParts.map(parseNamedTuplePart);
188
+ if (namedParts.length > 0 && namedParts.every((part) => part !== null)) {
189
+ return `{ ${namedParts
190
+ .map((part) => `${formatTypeScriptProperty(part.name)}: ${clickhouseToTsType(part.type)}`)
191
+ .join('; ')} }`;
192
+ }
122
193
  return `[${tupleParts.map((part) => clickhouseToTsType(part)).join(', ')}]`;
123
194
  }
124
- const wrappedMapType = unwrapType(type, 'Map');
195
+ const wrappedMapType = unwrapType(normalizedType, 'Map');
125
196
  if (wrappedMapType) {
126
197
  const mapParts = splitTopLevelArgs(wrappedMapType);
127
198
  if (mapParts.length === 2) {
@@ -131,7 +202,7 @@ export const clickhouseToTsType = (type) => {
131
202
  }
132
203
  return 'Record<string, unknown>';
133
204
  }
134
- const primitiveType = getPrimitiveTsType(type);
205
+ const primitiveType = getPrimitiveTsType(normalizedType);
135
206
  if (primitiveType)
136
207
  return primitiveType;
137
208
  // Unsupported or more complex ClickHouse types currently preserve the historical fallback.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/cli",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "CLI for scaffolding type-safe ClickHouse analytics, semantic datasets, React manifests, and deployments",
5
5
  "keywords": [
6
6
  "clickhouse",
@@ -30,8 +30,8 @@
30
30
  "open": "^10.0.0",
31
31
  "ora": "^8.0.1",
32
32
  "prompts": "^2.4.2",
33
- "@hypequery/protocol": "0.11.0",
34
- "@hypequery/deployment": "0.7.3"
33
+ "@hypequery/deployment": "0.7.3",
34
+ "@hypequery/protocol": "0.11.0"
35
35
  },
36
36
  "optionalDependencies": {
37
37
  "@napi-rs/keyring": "1.3.0"