import path from 'node:path';
type Source = 'sdk_pkg' | 'fallback';
type Result = {
apiLevel: number;
source: Source;
detectedFrom?: string;
devecoHome?: string;
};
type Pkg = {
data?: {
apiVersion?: unknown;
};
apiVersion?: unknown;
};
function envPath() {
return String(process.env.DEVECO_HOME || '').trim();
}
async function isDir(file: string) {
if (!file) {
return false;
}
return Bun.file(file)
.stat()
.then((info) => info.isDirectory())
.catch(() => false);
}
function defaults() {
if (process.platform === 'darwin') {
return ['/Applications/DevEco-Studio.app/Contents'];
}
if (process.platform === 'linux') {
const home = String(process.env.HOME || '').trim();
return [
home ? path.join(home, 'devecostudio/Contents') : '',
home ? path.join(home, 'DevEco-Studio/Contents') : '',
].filter(Boolean);
}
const home = String(process.env.USERPROFILE || '').trim();
return [
'C:\\Program Files\\Huawei\\DevEco Studio',
'C:\\Program Files\\DevEco Studio',
'C:\\Program Files (x86)\\DevEco Studio',
home ? path.join(home, 'DevEco Studio') : '',
].filter(Boolean);
}
function nodePath(home: string) {
return process.platform === 'win32'
? path.join(home, 'tools', 'node', 'node.exe')
: path.join(home, 'tools', 'node', 'bin', 'node');
}
async function findDevEcoHome() {
const env = envPath();
if (env && (await isDir(env)) && (await Bun.file(nodePath(env)).exists())) {
return env;
}
for (const item of defaults()) {
if (!(await isDir(item))) {
continue;
}
if (await Bun.file(nodePath(item)).exists()) {
return item;
}
}
}
function ok(apiLevel: number) {
return Number.isInteger(apiLevel) && apiLevel >= 17 && apiLevel <= 24;
}
function parse(raw: unknown) {
if (typeof raw !== 'string') {
return;
}
const apiLevel = Number(raw);
if (!ok(apiLevel)) {
return;
}
return apiLevel;
}
async function json(file: string) {
const item = Bun.file(file);
if (!(await item.exists())) {
return;
}
return item.json() as Promise<Pkg>;
}
export async function detectApiLevel(): Promise<Result> {
const home = await findDevEcoHome().catch(() => undefined);
if (!home) {
return {
apiLevel: 22,
source: 'fallback',
};
}
const sdk = path.join(home, 'sdk', 'default', 'sdk-pkg.json');
const first = await json(sdk).catch(() => undefined);
const firstLevel = parse(first?.data?.apiVersion);
if (firstLevel) {
return {
apiLevel: firstLevel,
source: 'sdk_pkg',
detectedFrom: sdk,
devecoHome: home,
};
}
return {
apiLevel: 22,
source: 'fallback',
devecoHome: home,
};
}