@514labs/moose-lsp 1.0.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.
- package/dist/clickhouseData.d.ts +78 -0
- package/dist/clickhouseData.js +112 -0
- package/dist/clickhouseData.js.map +1 -0
- package/dist/clickhouseData.test.d.ts +2 -0
- package/dist/clickhouseData.test.js +93 -0
- package/dist/clickhouseData.test.js.map +1 -0
- package/dist/clickhouseVersion.d.ts +49 -0
- package/dist/clickhouseVersion.js +149 -0
- package/dist/clickhouseVersion.js.map +1 -0
- package/dist/clickhouseVersion.test.d.ts +2 -0
- package/dist/clickhouseVersion.test.js +114 -0
- package/dist/clickhouseVersion.test.js.map +1 -0
- package/dist/codeActions.d.ts +27 -0
- package/dist/codeActions.js +173 -0
- package/dist/codeActions.js.map +1 -0
- package/dist/codeActions.test.d.ts +2 -0
- package/dist/codeActions.test.js +207 -0
- package/dist/codeActions.test.js.map +1 -0
- package/dist/completions.d.ts +22 -0
- package/dist/completions.js +228 -0
- package/dist/completions.js.map +1 -0
- package/dist/completions.test.d.ts +2 -0
- package/dist/completions.test.js +283 -0
- package/dist/completions.test.js.map +1 -0
- package/dist/data/clickhouse-25.6.json +30772 -0
- package/dist/data/clickhouse-25.8.json +31872 -0
- package/dist/diagnostics.d.ts +18 -0
- package/dist/diagnostics.js +54 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/diagnostics.test.d.ts +2 -0
- package/dist/diagnostics.test.js +110 -0
- package/dist/diagnostics.test.js.map +1 -0
- package/dist/formatting.d.ts +36 -0
- package/dist/formatting.js +70 -0
- package/dist/formatting.js.map +1 -0
- package/dist/formatting.test.d.ts +2 -0
- package/dist/formatting.test.js +93 -0
- package/dist/formatting.test.js.map +1 -0
- package/dist/hover.d.ts +43 -0
- package/dist/hover.js +198 -0
- package/dist/hover.js.map +1 -0
- package/dist/hover.test.d.ts +2 -0
- package/dist/hover.test.js +319 -0
- package/dist/hover.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/projectDetector.d.ts +7 -0
- package/dist/projectDetector.js +66 -0
- package/dist/projectDetector.js.map +1 -0
- package/dist/projectDetector.test.d.ts +2 -0
- package/dist/projectDetector.test.js +114 -0
- package/dist/projectDetector.test.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.integration.test.d.ts +2 -0
- package/dist/server.integration.test.js +190 -0
- package/dist/server.integration.test.js.map +1 -0
- package/dist/server.js +426 -0
- package/dist/server.js.map +1 -0
- package/dist/serverLogic.d.ts +32 -0
- package/dist/serverLogic.js +51 -0
- package/dist/serverLogic.js.map +1 -0
- package/dist/serverLogic.test.d.ts +2 -0
- package/dist/serverLogic.test.js +264 -0
- package/dist/serverLogic.test.js.map +1 -0
- package/dist/sqlExtractor.d.ts +15 -0
- package/dist/sqlExtractor.js +106 -0
- package/dist/sqlExtractor.js.map +1 -0
- package/dist/sqlExtractor.test.d.ts +2 -0
- package/dist/sqlExtractor.test.js +268 -0
- package/dist/sqlExtractor.test.js.map +1 -0
- package/dist/sqlLocations.d.ts +31 -0
- package/dist/sqlLocations.js +52 -0
- package/dist/sqlLocations.js.map +1 -0
- package/dist/sqlLocations.test.d.ts +2 -0
- package/dist/sqlLocations.test.js +95 -0
- package/dist/sqlLocations.test.js.map +1 -0
- package/dist/typescriptService.d.ts +29 -0
- package/dist/typescriptService.js +138 -0
- package/dist/typescriptService.js.map +1 -0
- package/dist/typescriptService.test.d.ts +2 -0
- package/dist/typescriptService.test.js +201 -0
- package/dist/typescriptService.test.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
interface FunctionInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
isAggregate: boolean;
|
|
4
|
+
caseInsensitive: boolean;
|
|
5
|
+
aliasTo: string | null;
|
|
6
|
+
syntax: string;
|
|
7
|
+
description: string;
|
|
8
|
+
arguments: string;
|
|
9
|
+
returnedValue: string;
|
|
10
|
+
examples: string;
|
|
11
|
+
categories: string;
|
|
12
|
+
}
|
|
13
|
+
interface DataTypeInfo {
|
|
14
|
+
name: string;
|
|
15
|
+
caseInsensitive: boolean;
|
|
16
|
+
aliasTo: string | null;
|
|
17
|
+
}
|
|
18
|
+
interface TableEngineInfo {
|
|
19
|
+
name: string;
|
|
20
|
+
supportsSettings: boolean;
|
|
21
|
+
supportsSkippingIndices: boolean;
|
|
22
|
+
supportsProjections: boolean;
|
|
23
|
+
supportsSortOrder: boolean;
|
|
24
|
+
supportsTTL: boolean;
|
|
25
|
+
supportsReplication: boolean;
|
|
26
|
+
supportsDeduplication: boolean;
|
|
27
|
+
supportsParallelInsert: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface FormatInfo {
|
|
30
|
+
name: string;
|
|
31
|
+
isInput: boolean;
|
|
32
|
+
isOutput: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface TableFunctionInfo {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
}
|
|
38
|
+
interface SettingInfo {
|
|
39
|
+
name: string;
|
|
40
|
+
type: string;
|
|
41
|
+
description: string;
|
|
42
|
+
}
|
|
43
|
+
interface ClickHouseData {
|
|
44
|
+
version: string;
|
|
45
|
+
extractedAt: string;
|
|
46
|
+
functions: FunctionInfo[];
|
|
47
|
+
keywords: string[];
|
|
48
|
+
dataTypes: DataTypeInfo[];
|
|
49
|
+
tableEngines: TableEngineInfo[];
|
|
50
|
+
formats: FormatInfo[];
|
|
51
|
+
tableFunctions: TableFunctionInfo[];
|
|
52
|
+
aggregateCombinators: string[];
|
|
53
|
+
settings: SettingInfo[];
|
|
54
|
+
mergeTreeSettings: SettingInfo[];
|
|
55
|
+
/** Warning message if loaded version differs from requested */
|
|
56
|
+
warning?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns list of available ClickHouse versions (from data files).
|
|
60
|
+
* Versions are sorted in descending order (newest first).
|
|
61
|
+
*/
|
|
62
|
+
declare function getAvailableVersions(): string[];
|
|
63
|
+
/**
|
|
64
|
+
* Loads ClickHouse data for the specified version.
|
|
65
|
+
*
|
|
66
|
+
* If exact version is not available, loads the closest matching version
|
|
67
|
+
* and includes a warning in the result.
|
|
68
|
+
*
|
|
69
|
+
* @param requestedVersion - The requested ClickHouse version (e.g., "25.8", "25.6.9")
|
|
70
|
+
* @returns ClickHouse data with optional warning if version was substituted
|
|
71
|
+
*/
|
|
72
|
+
declare function loadClickHouseData(requestedVersion: string): Promise<ClickHouseData>;
|
|
73
|
+
/**
|
|
74
|
+
* Clears the data cache. Useful for testing.
|
|
75
|
+
*/
|
|
76
|
+
declare function clearDataCache(): void;
|
|
77
|
+
|
|
78
|
+
export { type ClickHouseData, type DataTypeInfo, type FormatInfo, type FunctionInfo, type SettingInfo, type TableEngineInfo, type TableFunctionInfo, clearDataCache, getAvailableVersions, loadClickHouseData };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var clickhouseData_exports = {};
|
|
31
|
+
__export(clickhouseData_exports, {
|
|
32
|
+
clearDataCache: () => clearDataCache,
|
|
33
|
+
getAvailableVersions: () => getAvailableVersions,
|
|
34
|
+
loadClickHouseData: () => loadClickHouseData
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(clickhouseData_exports);
|
|
37
|
+
var fs = __toESM(require("node:fs"));
|
|
38
|
+
var path = __toESM(require("node:path"));
|
|
39
|
+
var import_clickhouseVersion = require("./clickhouseVersion");
|
|
40
|
+
const dataCache = /* @__PURE__ */ new Map();
|
|
41
|
+
function getDataDirectory() {
|
|
42
|
+
const possiblePaths = [
|
|
43
|
+
path.join(__dirname, "data"),
|
|
44
|
+
path.join(__dirname, "..", "src", "data"),
|
|
45
|
+
path.join(__dirname, "..", "data")
|
|
46
|
+
];
|
|
47
|
+
for (const p of possiblePaths) {
|
|
48
|
+
if (fs.existsSync(p)) {
|
|
49
|
+
return p;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return possiblePaths[0];
|
|
53
|
+
}
|
|
54
|
+
function getAvailableVersions() {
|
|
55
|
+
const dataDir = getDataDirectory();
|
|
56
|
+
try {
|
|
57
|
+
const files = fs.readdirSync(dataDir);
|
|
58
|
+
const versions = files.filter((f) => f.startsWith("clickhouse-") && f.endsWith(".json")).map((f) => f.replace("clickhouse-", "").replace(".json", "")).sort((a, b) => {
|
|
59
|
+
const [aMajor, aMinor] = a.split(".").map(Number);
|
|
60
|
+
const [bMajor, bMinor] = b.split(".").map(Number);
|
|
61
|
+
if (aMajor !== bMajor) return bMajor - aMajor;
|
|
62
|
+
return bMinor - aMinor;
|
|
63
|
+
});
|
|
64
|
+
return versions;
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function loadClickHouseData(requestedVersion) {
|
|
70
|
+
const availableVersions = getAvailableVersions();
|
|
71
|
+
if (availableVersions.length === 0) {
|
|
72
|
+
throw new Error("No ClickHouse data files found");
|
|
73
|
+
}
|
|
74
|
+
const [major, minor] = requestedVersion.split(".");
|
|
75
|
+
const normalizedRequested = `${major}.${minor}`;
|
|
76
|
+
const matchedVersion = (0, import_clickhouseVersion.findBestMatchingVersion)(
|
|
77
|
+
normalizedRequested,
|
|
78
|
+
availableVersions
|
|
79
|
+
);
|
|
80
|
+
const cached = dataCache.get(matchedVersion);
|
|
81
|
+
if (cached) {
|
|
82
|
+
if (matchedVersion !== normalizedRequested) {
|
|
83
|
+
return {
|
|
84
|
+
...cached,
|
|
85
|
+
warning: `Requested version ${requestedVersion} not found, using ${matchedVersion} instead`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return cached;
|
|
89
|
+
}
|
|
90
|
+
const dataDir = getDataDirectory();
|
|
91
|
+
const filePath = path.join(dataDir, `clickhouse-${matchedVersion}.json`);
|
|
92
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
93
|
+
const data = JSON.parse(content);
|
|
94
|
+
dataCache.set(matchedVersion, data);
|
|
95
|
+
if (matchedVersion !== normalizedRequested) {
|
|
96
|
+
return {
|
|
97
|
+
...data,
|
|
98
|
+
warning: `Requested version ${requestedVersion} not found, using ${matchedVersion} instead`
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
function clearDataCache() {
|
|
104
|
+
dataCache.clear();
|
|
105
|
+
}
|
|
106
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
107
|
+
0 && (module.exports = {
|
|
108
|
+
clearDataCache,
|
|
109
|
+
getAvailableVersions,
|
|
110
|
+
loadClickHouseData
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=clickhouseData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/clickhouseData.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { findBestMatchingVersion } from './clickhouseVersion';\n\nexport interface FunctionInfo {\n name: string;\n isAggregate: boolean;\n caseInsensitive: boolean;\n aliasTo: string | null;\n syntax: string;\n description: string;\n arguments: string;\n returnedValue: string;\n examples: string;\n categories: string;\n}\n\nexport interface DataTypeInfo {\n name: string;\n caseInsensitive: boolean;\n aliasTo: string | null;\n}\n\nexport interface TableEngineInfo {\n name: string;\n supportsSettings: boolean;\n supportsSkippingIndices: boolean;\n supportsProjections: boolean;\n supportsSortOrder: boolean;\n supportsTTL: boolean;\n supportsReplication: boolean;\n supportsDeduplication: boolean;\n supportsParallelInsert: boolean;\n}\n\nexport interface FormatInfo {\n name: string;\n isInput: boolean;\n isOutput: boolean;\n}\n\nexport interface TableFunctionInfo {\n name: string;\n description: string;\n}\n\nexport interface SettingInfo {\n name: string;\n type: string;\n description: string;\n}\n\nexport interface ClickHouseData {\n version: string;\n extractedAt: string;\n functions: FunctionInfo[];\n keywords: string[];\n dataTypes: DataTypeInfo[];\n tableEngines: TableEngineInfo[];\n formats: FormatInfo[];\n tableFunctions: TableFunctionInfo[];\n aggregateCombinators: string[];\n settings: SettingInfo[];\n mergeTreeSettings: SettingInfo[];\n /** Warning message if loaded version differs from requested */\n warning?: string;\n}\n\n// Cache for loaded data\nconst dataCache = new Map<string, ClickHouseData>();\n\n// Data directory path - works in both dev (src) and built (dist) contexts\nfunction getDataDirectory(): string {\n // Try multiple possible locations\n const possiblePaths = [\n path.join(__dirname, 'data'),\n path.join(__dirname, '..', 'src', 'data'),\n path.join(__dirname, '..', 'data'),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p)) {\n return p;\n }\n }\n\n // Default to first option\n return possiblePaths[0];\n}\n\n/**\n * Returns list of available ClickHouse versions (from data files).\n * Versions are sorted in descending order (newest first).\n */\nexport function getAvailableVersions(): string[] {\n const dataDir = getDataDirectory();\n\n try {\n const files = fs.readdirSync(dataDir);\n const versions = files\n .filter((f) => f.startsWith('clickhouse-') && f.endsWith('.json'))\n .map((f) => f.replace('clickhouse-', '').replace('.json', ''))\n .sort((a, b) => {\n const [aMajor, aMinor] = a.split('.').map(Number);\n const [bMajor, bMinor] = b.split('.').map(Number);\n if (aMajor !== bMajor) return bMajor - aMajor;\n return bMinor - aMinor;\n });\n\n return versions;\n } catch {\n return [];\n }\n}\n\n/**\n * Loads ClickHouse data for the specified version.\n *\n * If exact version is not available, loads the closest matching version\n * and includes a warning in the result.\n *\n * @param requestedVersion - The requested ClickHouse version (e.g., \"25.8\", \"25.6.9\")\n * @returns ClickHouse data with optional warning if version was substituted\n */\nexport async function loadClickHouseData(\n requestedVersion: string,\n): Promise<ClickHouseData> {\n const availableVersions = getAvailableVersions();\n\n if (availableVersions.length === 0) {\n throw new Error('No ClickHouse data files found');\n }\n\n // Normalize requested version to major.minor\n const [major, minor] = requestedVersion.split('.');\n const normalizedRequested = `${major}.${minor}`;\n\n // Find best matching version\n const matchedVersion = findBestMatchingVersion(\n normalizedRequested,\n availableVersions,\n );\n\n // Check cache\n const cached = dataCache.get(matchedVersion);\n if (cached) {\n // Add warning if version differs\n if (matchedVersion !== normalizedRequested) {\n return {\n ...cached,\n warning: `Requested version ${requestedVersion} not found, using ${matchedVersion} instead`,\n };\n }\n return cached;\n }\n\n // Load from file\n const dataDir = getDataDirectory();\n const filePath = path.join(dataDir, `clickhouse-${matchedVersion}.json`);\n\n const content = await fs.promises.readFile(filePath, 'utf-8');\n const data: ClickHouseData = JSON.parse(content);\n\n // Cache it\n dataCache.set(matchedVersion, data);\n\n // Add warning if version differs\n if (matchedVersion !== normalizedRequested) {\n return {\n ...data,\n warning: `Requested version ${requestedVersion} not found, using ${matchedVersion} instead`,\n };\n }\n\n return data;\n}\n\n/**\n * Clears the data cache. Useful for testing.\n */\nexport function clearDataCache(): void {\n dataCache.clear();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAoB;AACpB,WAAsB;AACtB,+BAAwC;AAmExC,MAAM,YAAY,oBAAI,IAA4B;AAGlD,SAAS,mBAA2B;AAElC,QAAM,gBAAgB;AAAA,IACpB,KAAK,KAAK,WAAW,MAAM;AAAA,IAC3B,KAAK,KAAK,WAAW,MAAM,OAAO,MAAM;AAAA,IACxC,KAAK,KAAK,WAAW,MAAM,MAAM;AAAA,EACnC;AAEA,aAAW,KAAK,eAAe;AAC7B,QAAI,GAAG,WAAW,CAAC,GAAG;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AAGA,SAAO,cAAc,CAAC;AACxB;AAMO,SAAS,uBAAiC;AAC/C,QAAM,UAAU,iBAAiB;AAEjC,MAAI;AACF,UAAM,QAAQ,GAAG,YAAY,OAAO;AACpC,UAAM,WAAW,MACd,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,KAAK,EAAE,SAAS,OAAO,CAAC,EAChE,IAAI,CAAC,MAAM,EAAE,QAAQ,eAAe,EAAE,EAAE,QAAQ,SAAS,EAAE,CAAC,EAC5D,KAAK,CAAC,GAAG,MAAM;AACd,YAAM,CAAC,QAAQ,MAAM,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAChD,YAAM,CAAC,QAAQ,MAAM,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAChD,UAAI,WAAW,OAAQ,QAAO,SAAS;AACvC,aAAO,SAAS;AAAA,IAClB,CAAC;AAEH,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAWA,eAAsB,mBACpB,kBACyB;AACzB,QAAM,oBAAoB,qBAAqB;AAE/C,MAAI,kBAAkB,WAAW,GAAG;AAClC,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAGA,QAAM,CAAC,OAAO,KAAK,IAAI,iBAAiB,MAAM,GAAG;AACjD,QAAM,sBAAsB,GAAG,KAAK,IAAI,KAAK;AAG7C,QAAM,qBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,IAAI,cAAc;AAC3C,MAAI,QAAQ;AAEV,QAAI,mBAAmB,qBAAqB;AAC1C,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,qBAAqB,gBAAgB,qBAAqB,cAAc;AAAA,MACnF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGA,QAAM,UAAU,iBAAiB;AACjC,QAAM,WAAW,KAAK,KAAK,SAAS,cAAc,cAAc,OAAO;AAEvE,QAAM,UAAU,MAAM,GAAG,SAAS,SAAS,UAAU,OAAO;AAC5D,QAAM,OAAuB,KAAK,MAAM,OAAO;AAG/C,YAAU,IAAI,gBAAgB,IAAI;AAGlC,MAAI,mBAAmB,qBAAqB;AAC1C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS,qBAAqB,gBAAgB,qBAAqB,cAAc;AAAA,IACnF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,iBAAuB;AACrC,YAAU,MAAM;AAClB;","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
var assert = __toESM(require("node:assert"));
|
|
26
|
+
var import_node_test = require("node:test");
|
|
27
|
+
var import_clickhouseData = require("./clickhouseData");
|
|
28
|
+
(0, import_node_test.describe)("clickhouseData", () => {
|
|
29
|
+
(0, import_node_test.describe)("getAvailableVersions", () => {
|
|
30
|
+
(0, import_node_test.it)("returns array of available versions", () => {
|
|
31
|
+
const versions = (0, import_clickhouseData.getAvailableVersions)();
|
|
32
|
+
assert.ok(Array.isArray(versions));
|
|
33
|
+
assert.ok(versions.length > 0);
|
|
34
|
+
assert.ok(versions.includes("25.6") || versions.includes("25.8"));
|
|
35
|
+
});
|
|
36
|
+
(0, import_node_test.it)("returns versions sorted in descending order", () => {
|
|
37
|
+
const versions = (0, import_clickhouseData.getAvailableVersions)();
|
|
38
|
+
for (let i = 0; i < versions.length - 1; i++) {
|
|
39
|
+
const [aMajor, aMinor] = versions[i].split(".").map(Number);
|
|
40
|
+
const [bMajor, bMinor] = versions[i + 1].split(".").map(Number);
|
|
41
|
+
assert.ok(
|
|
42
|
+
aMajor > bMajor || aMajor === bMajor && aMinor >= bMinor,
|
|
43
|
+
`Expected ${versions[i]} >= ${versions[i + 1]}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
(0, import_node_test.describe)("loadClickHouseData", () => {
|
|
49
|
+
(0, import_node_test.it)("loads data for exact version match", async () => {
|
|
50
|
+
const versions = (0, import_clickhouseData.getAvailableVersions)();
|
|
51
|
+
if (versions.length === 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const data = await (0, import_clickhouseData.loadClickHouseData)(versions[0]);
|
|
55
|
+
assert.ok(data);
|
|
56
|
+
assert.strictEqual(data.version, versions[0]);
|
|
57
|
+
assert.ok(Array.isArray(data.functions));
|
|
58
|
+
assert.ok(Array.isArray(data.keywords));
|
|
59
|
+
assert.ok(data.functions.length > 0);
|
|
60
|
+
assert.ok(data.keywords.length > 0);
|
|
61
|
+
});
|
|
62
|
+
(0, import_node_test.it)("loads closest version when exact match not found", async () => {
|
|
63
|
+
const data = await (0, import_clickhouseData.loadClickHouseData)("25.7");
|
|
64
|
+
assert.ok(data);
|
|
65
|
+
assert.ok(["25.6", "25.8"].includes(data.version));
|
|
66
|
+
});
|
|
67
|
+
(0, import_node_test.it)("returns warning when version is not exact match", async () => {
|
|
68
|
+
const data = await (0, import_clickhouseData.loadClickHouseData)("25.7");
|
|
69
|
+
assert.ok(data);
|
|
70
|
+
assert.ok(data.warning);
|
|
71
|
+
assert.ok(data.warning.includes("25.7"));
|
|
72
|
+
});
|
|
73
|
+
(0, import_node_test.it)("data structure has expected properties", async () => {
|
|
74
|
+
const versions = (0, import_clickhouseData.getAvailableVersions)();
|
|
75
|
+
if (versions.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const data = await (0, import_clickhouseData.loadClickHouseData)(versions[0]);
|
|
79
|
+
assert.ok(typeof data.version === "string");
|
|
80
|
+
assert.ok(typeof data.extractedAt === "string");
|
|
81
|
+
assert.ok(Array.isArray(data.functions));
|
|
82
|
+
assert.ok(Array.isArray(data.keywords));
|
|
83
|
+
assert.ok(Array.isArray(data.dataTypes));
|
|
84
|
+
assert.ok(Array.isArray(data.tableEngines));
|
|
85
|
+
assert.ok(Array.isArray(data.formats));
|
|
86
|
+
assert.ok(Array.isArray(data.tableFunctions));
|
|
87
|
+
assert.ok(Array.isArray(data.aggregateCombinators));
|
|
88
|
+
assert.ok(Array.isArray(data.settings));
|
|
89
|
+
assert.ok(Array.isArray(data.mergeTreeSettings));
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=clickhouseData.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/clickhouseData.test.ts"],"sourcesContent":["import * as assert from 'node:assert';\nimport { describe, it } from 'node:test';\nimport { getAvailableVersions, loadClickHouseData } from './clickhouseData';\n\ndescribe('clickhouseData', () => {\n describe('getAvailableVersions', () => {\n it('returns array of available versions', () => {\n const versions = getAvailableVersions();\n assert.ok(Array.isArray(versions));\n assert.ok(versions.length > 0);\n // Should include our generated versions\n assert.ok(versions.includes('25.6') || versions.includes('25.8'));\n });\n\n it('returns versions sorted in descending order', () => {\n const versions = getAvailableVersions();\n for (let i = 0; i < versions.length - 1; i++) {\n const [aMajor, aMinor] = versions[i].split('.').map(Number);\n const [bMajor, bMinor] = versions[i + 1].split('.').map(Number);\n assert.ok(\n aMajor > bMajor || (aMajor === bMajor && aMinor >= bMinor),\n `Expected ${versions[i]} >= ${versions[i + 1]}`,\n );\n }\n });\n });\n\n describe('loadClickHouseData', () => {\n it('loads data for exact version match', async () => {\n const versions = getAvailableVersions();\n if (versions.length === 0) {\n // Skip if no data files exist yet\n return;\n }\n\n const data = await loadClickHouseData(versions[0]);\n\n assert.ok(data);\n assert.strictEqual(data.version, versions[0]);\n assert.ok(Array.isArray(data.functions));\n assert.ok(Array.isArray(data.keywords));\n assert.ok(data.functions.length > 0);\n assert.ok(data.keywords.length > 0);\n });\n\n it('loads closest version when exact match not found', async () => {\n const data = await loadClickHouseData('25.7');\n\n assert.ok(data);\n // Should load either 25.6 or 25.8, whichever is closest\n assert.ok(['25.6', '25.8'].includes(data.version));\n });\n\n it('returns warning when version is not exact match', async () => {\n const data = await loadClickHouseData('25.7');\n\n assert.ok(data);\n assert.ok(data.warning);\n assert.ok(data.warning.includes('25.7'));\n });\n\n it('data structure has expected properties', async () => {\n const versions = getAvailableVersions();\n if (versions.length === 0) {\n return;\n }\n\n const data = await loadClickHouseData(versions[0]);\n\n // Check structure\n assert.ok(typeof data.version === 'string');\n assert.ok(typeof data.extractedAt === 'string');\n assert.ok(Array.isArray(data.functions));\n assert.ok(Array.isArray(data.keywords));\n assert.ok(Array.isArray(data.dataTypes));\n assert.ok(Array.isArray(data.tableEngines));\n assert.ok(Array.isArray(data.formats));\n assert.ok(Array.isArray(data.tableFunctions));\n assert.ok(Array.isArray(data.aggregateCombinators));\n assert.ok(Array.isArray(data.settings));\n assert.ok(Array.isArray(data.mergeTreeSettings));\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses ClickHouse version from a Docker image tag.
|
|
3
|
+
*
|
|
4
|
+
* Handles formats:
|
|
5
|
+
* - clickhouse/clickhouse-server:25.8
|
|
6
|
+
* - docker.io/clickhouse/clickhouse-server:25.6
|
|
7
|
+
* - clickhouse/clickhouse-server:${CLICKHOUSE_VERSION:-25.6}
|
|
8
|
+
* - clickhouse/clickhouse-server:25.8.1.1234
|
|
9
|
+
*
|
|
10
|
+
* @returns Normalized version (major.minor) or null if not parseable
|
|
11
|
+
*/
|
|
12
|
+
declare function parseVersionFromImageTag(imageTag: string): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Parses ClickHouse version from docker-compose YAML content.
|
|
15
|
+
*
|
|
16
|
+
* Looks for services named:
|
|
17
|
+
* - clickhousedb (Moose dev)
|
|
18
|
+
* - clickhouse-0 (Moose prod)
|
|
19
|
+
* - clickhouse (generic)
|
|
20
|
+
*
|
|
21
|
+
* @returns Normalized version (major.minor) or null if not found
|
|
22
|
+
*/
|
|
23
|
+
declare function parseVersionFromDockerCompose(yamlContent: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Finds the best matching version from available versions.
|
|
26
|
+
*
|
|
27
|
+
* Priority:
|
|
28
|
+
* 1. Exact match
|
|
29
|
+
* 2. Same major version, closest minor (prefer lower)
|
|
30
|
+
* 3. Latest available version
|
|
31
|
+
*
|
|
32
|
+
* @param detected - The detected version (e.g., "25.7", "25.6.9")
|
|
33
|
+
* @param available - Array of available versions (e.g., ["25.6", "25.8"])
|
|
34
|
+
* @returns The best matching available version
|
|
35
|
+
*/
|
|
36
|
+
declare function findBestMatchingVersion(detected: string, available: string[]): string;
|
|
37
|
+
/**
|
|
38
|
+
* Detects ClickHouse version from a Moose project.
|
|
39
|
+
*
|
|
40
|
+
* Checks in order:
|
|
41
|
+
* 1. docker-compose.dev.override.yaml (user override)
|
|
42
|
+
* 2. .moose/docker-compose.yml (generated)
|
|
43
|
+
*
|
|
44
|
+
* @param projectRoot - Path to the Moose project root
|
|
45
|
+
* @returns Detected version or null if not found
|
|
46
|
+
*/
|
|
47
|
+
declare function detectClickHouseVersion(projectRoot: string): Promise<string | null>;
|
|
48
|
+
|
|
49
|
+
export { detectClickHouseVersion, findBestMatchingVersion, parseVersionFromDockerCompose, parseVersionFromImageTag };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var clickhouseVersion_exports = {};
|
|
31
|
+
__export(clickhouseVersion_exports, {
|
|
32
|
+
detectClickHouseVersion: () => detectClickHouseVersion,
|
|
33
|
+
findBestMatchingVersion: () => findBestMatchingVersion,
|
|
34
|
+
parseVersionFromDockerCompose: () => parseVersionFromDockerCompose,
|
|
35
|
+
parseVersionFromImageTag: () => parseVersionFromImageTag
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(clickhouseVersion_exports);
|
|
38
|
+
var fs = __toESM(require("node:fs"));
|
|
39
|
+
var path = __toESM(require("node:path"));
|
|
40
|
+
function parseVersionFromImageTag(imageTag) {
|
|
41
|
+
if (!imageTag.includes("clickhouse")) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const imageTagMatch = imageTag.match(/clickhouse-server:([^/]+)$/);
|
|
45
|
+
if (!imageTagMatch) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
let tag = imageTagMatch[1];
|
|
49
|
+
const envVarMatch = tag.match(/\$\{[^}]+:-([^}]+)\}/);
|
|
50
|
+
if (envVarMatch) {
|
|
51
|
+
tag = envVarMatch[1];
|
|
52
|
+
}
|
|
53
|
+
if (tag === "latest" || tag === "head") {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const versionMatch = tag.match(/^(\d+)\.(\d+)/);
|
|
57
|
+
if (!versionMatch) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return `${versionMatch[1]}.${versionMatch[2]}`;
|
|
61
|
+
}
|
|
62
|
+
function parseVersionFromDockerCompose(yamlContent) {
|
|
63
|
+
const servicePatterns = [
|
|
64
|
+
/clickhousedb:\s*\n(?:[^\n]*\n)*?\s*image:\s*([^\n]+)/i,
|
|
65
|
+
/clickhouse-0:\s*\n(?:[^\n]*\n)*?\s*image:\s*([^\n]+)/i,
|
|
66
|
+
/clickhouse:\s*\n(?:[^\n]*\n)*?\s*image:\s*([^\n]+)/i
|
|
67
|
+
];
|
|
68
|
+
for (const pattern of servicePatterns) {
|
|
69
|
+
const match = yamlContent.match(pattern);
|
|
70
|
+
if (match) {
|
|
71
|
+
const version = parseVersionFromImageTag(match[1].trim());
|
|
72
|
+
if (version) {
|
|
73
|
+
return version;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const imageMatch = yamlContent.match(
|
|
78
|
+
/image:\s*([^\n]*clickhouse-server[^\n]*)/i
|
|
79
|
+
);
|
|
80
|
+
if (imageMatch) {
|
|
81
|
+
return parseVersionFromImageTag(imageMatch[1].trim());
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function findBestMatchingVersion(detected, available) {
|
|
86
|
+
if (available.length === 0) {
|
|
87
|
+
throw new Error("No available versions provided");
|
|
88
|
+
}
|
|
89
|
+
const [detectedMajor, detectedMinor] = detected.split(".").map(Number);
|
|
90
|
+
const normalizedDetected = `${detectedMajor}.${detectedMinor}`;
|
|
91
|
+
if (available.includes(normalizedDetected)) {
|
|
92
|
+
return normalizedDetected;
|
|
93
|
+
}
|
|
94
|
+
const sameMajor = available.filter((v) => {
|
|
95
|
+
const [major] = v.split(".").map(Number);
|
|
96
|
+
return major === detectedMajor;
|
|
97
|
+
});
|
|
98
|
+
if (sameMajor.length > 0) {
|
|
99
|
+
const sorted2 = sameMajor.sort((a, b) => {
|
|
100
|
+
const [, aMinor] = a.split(".").map(Number);
|
|
101
|
+
const [, bMinor] = b.split(".").map(Number);
|
|
102
|
+
return aMinor - bMinor;
|
|
103
|
+
});
|
|
104
|
+
let closest = sorted2[0];
|
|
105
|
+
for (const v of sorted2) {
|
|
106
|
+
const [, minor] = v.split(".").map(Number);
|
|
107
|
+
if (minor <= detectedMinor) {
|
|
108
|
+
closest = v;
|
|
109
|
+
} else {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return closest;
|
|
114
|
+
}
|
|
115
|
+
const sorted = [...available].sort((a, b) => {
|
|
116
|
+
const [aMajor, aMinor] = a.split(".").map(Number);
|
|
117
|
+
const [bMajor, bMinor] = b.split(".").map(Number);
|
|
118
|
+
if (aMajor !== bMajor) return bMajor - aMajor;
|
|
119
|
+
return bMinor - aMinor;
|
|
120
|
+
});
|
|
121
|
+
return sorted[0];
|
|
122
|
+
}
|
|
123
|
+
async function detectClickHouseVersion(projectRoot) {
|
|
124
|
+
const filesToCheck = [
|
|
125
|
+
path.join(projectRoot, "docker-compose.dev.override.yaml"),
|
|
126
|
+
path.join(projectRoot, "docker-compose.dev.override.yml"),
|
|
127
|
+
path.join(projectRoot, ".moose", "docker-compose.yml"),
|
|
128
|
+
path.join(projectRoot, ".moose", "docker-compose.yaml")
|
|
129
|
+
];
|
|
130
|
+
for (const filePath of filesToCheck) {
|
|
131
|
+
try {
|
|
132
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
133
|
+
const version = parseVersionFromDockerCompose(content);
|
|
134
|
+
if (version) {
|
|
135
|
+
return version;
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
143
|
+
0 && (module.exports = {
|
|
144
|
+
detectClickHouseVersion,
|
|
145
|
+
findBestMatchingVersion,
|
|
146
|
+
parseVersionFromDockerCompose,
|
|
147
|
+
parseVersionFromImageTag
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=clickhouseVersion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/clickhouseVersion.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Parses ClickHouse version from a Docker image tag.\n *\n * Handles formats:\n * - clickhouse/clickhouse-server:25.8\n * - docker.io/clickhouse/clickhouse-server:25.6\n * - clickhouse/clickhouse-server:${CLICKHOUSE_VERSION:-25.6}\n * - clickhouse/clickhouse-server:25.8.1.1234\n *\n * @returns Normalized version (major.minor) or null if not parseable\n */\nexport function parseVersionFromImageTag(imageTag: string): string | null {\n // Check if this is a ClickHouse image\n if (!imageTag.includes('clickhouse')) {\n return null;\n }\n\n // Extract the tag portion after the image name colon\n // Match pattern: image-name:tag where tag doesn't contain / (path separator)\n const imageTagMatch = imageTag.match(/clickhouse-server:([^/]+)$/);\n if (!imageTagMatch) {\n return null;\n }\n\n let tag = imageTagMatch[1];\n\n // Handle env var syntax: ${CLICKHOUSE_VERSION:-25.6}\n const envVarMatch = tag.match(/\\$\\{[^}]+:-([^}]+)\\}/);\n if (envVarMatch) {\n tag = envVarMatch[1];\n }\n\n // Skip non-version tags\n if (tag === 'latest' || tag === 'head') {\n return null;\n }\n\n // Parse version: expect X.Y or X.Y.Z...\n const versionMatch = tag.match(/^(\\d+)\\.(\\d+)/);\n if (!versionMatch) {\n return null;\n }\n\n return `${versionMatch[1]}.${versionMatch[2]}`;\n}\n\n/**\n * Parses ClickHouse version from docker-compose YAML content.\n *\n * Looks for services named:\n * - clickhousedb (Moose dev)\n * - clickhouse-0 (Moose prod)\n * - clickhouse (generic)\n *\n * @returns Normalized version (major.minor) or null if not found\n */\nexport function parseVersionFromDockerCompose(\n yamlContent: string,\n): string | null {\n // Simple regex-based parsing to avoid adding yaml dependency\n // Look for image: lines under clickhouse-related services\n\n const servicePatterns = [\n /clickhousedb:\\s*\\n(?:[^\\n]*\\n)*?\\s*image:\\s*([^\\n]+)/i,\n /clickhouse-0:\\s*\\n(?:[^\\n]*\\n)*?\\s*image:\\s*([^\\n]+)/i,\n /clickhouse:\\s*\\n(?:[^\\n]*\\n)*?\\s*image:\\s*([^\\n]+)/i,\n ];\n\n for (const pattern of servicePatterns) {\n const match = yamlContent.match(pattern);\n if (match) {\n const version = parseVersionFromImageTag(match[1].trim());\n if (version) {\n return version;\n }\n }\n }\n\n // Fallback: look for any clickhouse-server image line\n const imageMatch = yamlContent.match(\n /image:\\s*([^\\n]*clickhouse-server[^\\n]*)/i,\n );\n if (imageMatch) {\n return parseVersionFromImageTag(imageMatch[1].trim());\n }\n\n return null;\n}\n\n/**\n * Finds the best matching version from available versions.\n *\n * Priority:\n * 1. Exact match\n * 2. Same major version, closest minor (prefer lower)\n * 3. Latest available version\n *\n * @param detected - The detected version (e.g., \"25.7\", \"25.6.9\")\n * @param available - Array of available versions (e.g., [\"25.6\", \"25.8\"])\n * @returns The best matching available version\n */\nexport function findBestMatchingVersion(\n detected: string,\n available: string[],\n): string {\n if (available.length === 0) {\n throw new Error('No available versions provided');\n }\n\n // Normalize detected version to major.minor\n const [detectedMajor, detectedMinor] = detected.split('.').map(Number);\n const normalizedDetected = `${detectedMajor}.${detectedMinor}`;\n\n // Exact match\n if (available.includes(normalizedDetected)) {\n return normalizedDetected;\n }\n\n // Find candidates with same major version\n const sameMajor = available.filter((v) => {\n const [major] = v.split('.').map(Number);\n return major === detectedMajor;\n });\n\n if (sameMajor.length > 0) {\n // Sort by minor version\n const sorted = sameMajor.sort((a, b) => {\n const [, aMinor] = a.split('.').map(Number);\n const [, bMinor] = b.split('.').map(Number);\n return aMinor - bMinor;\n });\n\n // Find closest lower or equal\n let closest = sorted[0];\n for (const v of sorted) {\n const [, minor] = v.split('.').map(Number);\n if (minor <= detectedMinor) {\n closest = v;\n } else {\n break;\n }\n }\n\n // If no lower version exists, return the lowest in same major\n return closest;\n }\n\n // No same major version, return latest overall\n const sorted = [...available].sort((a, b) => {\n const [aMajor, aMinor] = a.split('.').map(Number);\n const [bMajor, bMinor] = b.split('.').map(Number);\n if (aMajor !== bMajor) return bMajor - aMajor;\n return bMinor - aMinor;\n });\n\n return sorted[0];\n}\n\n/**\n * Detects ClickHouse version from a Moose project.\n *\n * Checks in order:\n * 1. docker-compose.dev.override.yaml (user override)\n * 2. .moose/docker-compose.yml (generated)\n *\n * @param projectRoot - Path to the Moose project root\n * @returns Detected version or null if not found\n */\nexport async function detectClickHouseVersion(\n projectRoot: string,\n): Promise<string | null> {\n const filesToCheck = [\n path.join(projectRoot, 'docker-compose.dev.override.yaml'),\n path.join(projectRoot, 'docker-compose.dev.override.yml'),\n path.join(projectRoot, '.moose', 'docker-compose.yml'),\n path.join(projectRoot, '.moose', 'docker-compose.yaml'),\n ];\n\n for (const filePath of filesToCheck) {\n try {\n const content = await fs.promises.readFile(filePath, 'utf-8');\n const version = parseVersionFromDockerCompose(content);\n if (version) {\n return version;\n }\n } catch {\n // File doesn't exist or can't be read, try next\n }\n }\n\n return null;\n}\n"],"mappings":"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","names":["sorted"]}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
var assert = __toESM(require("node:assert"));
|
|
26
|
+
var import_node_test = require("node:test");
|
|
27
|
+
var import_clickhouseVersion = require("./clickhouseVersion");
|
|
28
|
+
(0, import_node_test.describe)("clickhouseVersion", () => {
|
|
29
|
+
(0, import_node_test.describe)("parseVersionFromImageTag", () => {
|
|
30
|
+
(0, import_node_test.it)("parses simple version tag", () => {
|
|
31
|
+
assert.strictEqual(
|
|
32
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)("clickhouse/clickhouse-server:25.8"),
|
|
33
|
+
"25.8"
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
(0, import_node_test.it)("parses version with patch number", () => {
|
|
37
|
+
assert.strictEqual(
|
|
38
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)("clickhouse/clickhouse-server:25.8.1"),
|
|
39
|
+
"25.8"
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
(0, import_node_test.it)("parses docker.io prefixed image", () => {
|
|
43
|
+
assert.strictEqual(
|
|
44
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)("docker.io/clickhouse/clickhouse-server:25.6"),
|
|
45
|
+
"25.6"
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
(0, import_node_test.it)("extracts default from env var syntax", () => {
|
|
49
|
+
assert.strictEqual(
|
|
50
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)(
|
|
51
|
+
"clickhouse/clickhouse-server:${CLICKHOUSE_VERSION:-25.6}"
|
|
52
|
+
),
|
|
53
|
+
"25.6"
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
(0, import_node_test.it)("returns null for unrecognized format", () => {
|
|
57
|
+
assert.strictEqual(
|
|
58
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)("some-other-image:latest"),
|
|
59
|
+
null
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
(0, import_node_test.it)("returns null for latest tag", () => {
|
|
63
|
+
assert.strictEqual(
|
|
64
|
+
(0, import_clickhouseVersion.parseVersionFromImageTag)("clickhouse/clickhouse-server:latest"),
|
|
65
|
+
null
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
(0, import_node_test.describe)("parseVersionFromDockerCompose", () => {
|
|
70
|
+
(0, import_node_test.it)("extracts version from clickhousedb service", () => {
|
|
71
|
+
const yaml = `
|
|
72
|
+
services:
|
|
73
|
+
clickhousedb:
|
|
74
|
+
image: docker.io/clickhouse/clickhouse-server:\${CLICKHOUSE_VERSION:-25.6}
|
|
75
|
+
`;
|
|
76
|
+
assert.strictEqual((0, import_clickhouseVersion.parseVersionFromDockerCompose)(yaml), "25.6");
|
|
77
|
+
});
|
|
78
|
+
(0, import_node_test.it)("extracts version from clickhouse-0 service", () => {
|
|
79
|
+
const yaml = `
|
|
80
|
+
services:
|
|
81
|
+
clickhouse-0:
|
|
82
|
+
image: clickhouse/clickhouse-server:25.8
|
|
83
|
+
`;
|
|
84
|
+
assert.strictEqual((0, import_clickhouseVersion.parseVersionFromDockerCompose)(yaml), "25.8");
|
|
85
|
+
});
|
|
86
|
+
(0, import_node_test.it)("returns null when no clickhouse service found", () => {
|
|
87
|
+
const yaml = `
|
|
88
|
+
services:
|
|
89
|
+
redis:
|
|
90
|
+
image: redis:latest
|
|
91
|
+
`;
|
|
92
|
+
assert.strictEqual((0, import_clickhouseVersion.parseVersionFromDockerCompose)(yaml), null);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
(0, import_node_test.describe)("findBestMatchingVersion", () => {
|
|
96
|
+
const available = ["25.6", "25.8"];
|
|
97
|
+
(0, import_node_test.it)("returns exact match when available", () => {
|
|
98
|
+
assert.strictEqual((0, import_clickhouseVersion.findBestMatchingVersion)("25.8", available), "25.8");
|
|
99
|
+
});
|
|
100
|
+
(0, import_node_test.it)("returns closest lower version for unknown minor", () => {
|
|
101
|
+
assert.strictEqual((0, import_clickhouseVersion.findBestMatchingVersion)("25.7", available), "25.6");
|
|
102
|
+
});
|
|
103
|
+
(0, import_node_test.it)("returns closest higher version when no lower exists", () => {
|
|
104
|
+
assert.strictEqual((0, import_clickhouseVersion.findBestMatchingVersion)("25.5", available), "25.6");
|
|
105
|
+
});
|
|
106
|
+
(0, import_node_test.it)("returns latest when major version differs", () => {
|
|
107
|
+
assert.strictEqual((0, import_clickhouseVersion.findBestMatchingVersion)("24.0", available), "25.8");
|
|
108
|
+
});
|
|
109
|
+
(0, import_node_test.it)("handles patch versions by matching minor", () => {
|
|
110
|
+
assert.strictEqual((0, import_clickhouseVersion.findBestMatchingVersion)("25.6.9", available), "25.6");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=clickhouseVersion.test.js.map
|