@oniroproject/core 0.17.0 → 0.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.
package/dist/index.js CHANGED
@@ -599,14 +599,14 @@ var pipelineAsync = promisify(pipeline);
599
599
  async function downloadFile(opts) {
600
600
  const { url, dest, progress, abortSignal } = opts;
601
601
  const proto = url.startsWith("https") ? https : http;
602
- return new Promise((resolve21, reject) => {
602
+ return new Promise((resolve22, reject) => {
603
603
  const s = Math.max(0, Math.min(100, opts.start ?? 0));
604
604
  const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
605
605
  let settled = false;
606
606
  const done = (err) => {
607
607
  if (settled) return;
608
608
  settled = true;
609
- err ? reject(err) : resolve21();
609
+ err ? reject(err) : resolve22();
610
610
  };
611
611
  if (abortSignal?.aborted) {
612
612
  done(new CancelledError("Download cancelled before start."));
@@ -787,10 +787,10 @@ async function extractTarball(tarPath, dest, strip = 0, filter) {
787
787
  var SIGNED_HAP_CHUNK_SIZE = 128 * 1024;
788
788
  async function withHapZip(zipPath, use) {
789
789
  const zip = new StreamZip({ file: zipPath, chunkSize: SIGNED_HAP_CHUNK_SIZE, storeEntries: true });
790
- const close = () => new Promise((resolve21) => zip.close(() => resolve21()));
790
+ const close = () => new Promise((resolve22) => zip.close(() => resolve22()));
791
791
  try {
792
- await new Promise((resolve21, reject) => {
793
- zip.once("ready", () => resolve21());
792
+ await new Promise((resolve22, reject) => {
793
+ zip.once("ready", () => resolve22());
794
794
  zip.once("error", (err) => reject(err));
795
795
  });
796
796
  return await use({ entries: () => zip.entries(), entryData: (name) => zip.entryDataSync(name) });
@@ -2280,7 +2280,7 @@ function runProcess(opts) {
2280
2280
  const { command, args, cwd, env, onOutput } = opts;
2281
2281
  const timeoutMs = opts.timeoutMs ?? 6e4;
2282
2282
  const { abortSignal } = opts;
2283
- return new Promise((resolve21, reject) => {
2283
+ return new Promise((resolve22, reject) => {
2284
2284
  if (abortSignal?.aborted) {
2285
2285
  reject(new CancelledError(`Command aborted before start: ${command}`));
2286
2286
  return;
@@ -2353,7 +2353,7 @@ ${stderr.trim()}` : "")
2353
2353
  );
2354
2354
  return;
2355
2355
  }
2356
- resolve21({ code: code ?? -1, stdout, stderr });
2356
+ resolve22({ code: code ?? -1, stdout, stderr });
2357
2357
  });
2358
2358
  });
2359
2359
  }
@@ -3004,11 +3004,11 @@ async function getDefaultInstanceStatus(config, opts) {
3004
3004
  };
3005
3005
  }
3006
3006
  function isTcpPortFree(port, host = "127.0.0.1") {
3007
- return new Promise((resolve21) => {
3007
+ return new Promise((resolve22) => {
3008
3008
  const srv = net.createServer();
3009
- srv.once("error", () => resolve21(false));
3009
+ srv.once("error", () => resolve22(false));
3010
3010
  srv.listen({ port, host, exclusive: true }, () => {
3011
- srv.close(() => resolve21(true));
3011
+ srv.close(() => resolve22(true));
3012
3012
  });
3013
3013
  });
3014
3014
  }
@@ -3169,9 +3169,9 @@ async function startPoolInstance(opts) {
3169
3169
  } finally {
3170
3170
  fs22.closeSync(logFd);
3171
3171
  }
3172
- const earlyExit = new Promise((resolve21) => {
3173
- child.once("exit", (code) => resolve21(code));
3174
- child.once("error", () => resolve21(-1));
3172
+ const earlyExit = new Promise((resolve22) => {
3173
+ child.once("exit", (code) => resolve22(code));
3174
+ child.once("error", () => resolve22(-1));
3175
3175
  });
3176
3176
  if (!child.pid) {
3177
3177
  await earlyExit;
@@ -3381,11 +3381,11 @@ async function startEmulator(opts) {
3381
3381
  fs23.writeFileSync(DEFAULT_EMULATOR_PID_FILE, String(child.pid));
3382
3382
  child.unref();
3383
3383
  logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
3384
- const earlyExit = new Promise((resolve21) => {
3385
- child.once("exit", (code) => resolve21(code));
3386
- child.once("error", () => resolve21(-1));
3384
+ const earlyExit = new Promise((resolve22) => {
3385
+ child.once("exit", (code) => resolve22(code));
3386
+ child.once("error", () => resolve22(-1));
3387
3387
  });
3388
- const liveness = new Promise((resolve21) => setTimeout(() => resolve21("alive"), 2e3));
3388
+ const liveness = new Promise((resolve22) => setTimeout(() => resolve22("alive"), 2e3));
3389
3389
  const outcome = await Promise.race([earlyExit, liveness]);
3390
3390
  if (outcome !== "alive") {
3391
3391
  const tail = readTail(logPath, 4e3);
@@ -3714,7 +3714,7 @@ async function getDisplaySize(config, opts = {}) {
3714
3714
 
3715
3715
  // src/hdc/wait.ts
3716
3716
  function delay(ms, signal) {
3717
- return new Promise((resolve21, reject) => {
3717
+ return new Promise((resolve22, reject) => {
3718
3718
  if (signal?.aborted) {
3719
3719
  reject(new CancelledError("Wait cancelled."));
3720
3720
  return;
@@ -3729,7 +3729,7 @@ function delay(ms, signal) {
3729
3729
  };
3730
3730
  const timer = setTimeout(() => {
3731
3731
  cleanup();
3732
- resolve21();
3732
+ resolve22();
3733
3733
  }, ms);
3734
3734
  signal?.addEventListener("abort", onAbort, { once: true });
3735
3735
  });
@@ -3904,8 +3904,8 @@ async function resolveInstallHap(opts, logger) {
3904
3904
  return hap;
3905
3905
  };
3906
3906
  const configured = opts.hapPath ?? opts.config.get("hapPath", "");
3907
- const relative7 = configured || defaultPaths.hapPath;
3908
- const hapPath = path26.isAbsolute(relative7) ? relative7 : path26.join(opts.projectDir, relative7);
3907
+ const relative8 = configured || defaultPaths.hapPath;
3908
+ const hapPath = path26.isAbsolute(relative8) ? relative8 : path26.join(opts.projectDir, relative8);
3909
3909
  if (configured) {
3910
3910
  const hap = existingHapOrUnsigned(hapPath);
3911
3911
  if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);
@@ -4022,7 +4022,7 @@ function listRunningProcesses(config, options = {}) {
4022
4022
  const logger = options.logger ?? noopLogger;
4023
4023
  const timeoutMs = options.timeoutMs ?? 1e3;
4024
4024
  const hdc = getHdcPath(config);
4025
- return new Promise((resolve21, reject) => {
4025
+ return new Promise((resolve22, reject) => {
4026
4026
  let proc;
4027
4027
  try {
4028
4028
  proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), "track-jpid"]);
@@ -4042,7 +4042,7 @@ function listRunningProcesses(config, options = {}) {
4042
4042
  if (options.targetProcessName && name === options.targetProcessName && !resolved) {
4043
4043
  resolved = true;
4044
4044
  killProcessTree(proc);
4045
- resolve21(pid);
4045
+ resolve22(pid);
4046
4046
  return;
4047
4047
  }
4048
4048
  }
@@ -4063,7 +4063,7 @@ function listRunningProcesses(config, options = {}) {
4063
4063
  if (options.targetProcessName) {
4064
4064
  reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
4065
4065
  } else {
4066
- resolve21(processes);
4066
+ resolve22(processes);
4067
4067
  }
4068
4068
  }, timeoutMs);
4069
4069
  proc.on("close", () => {
@@ -4073,7 +4073,7 @@ function listRunningProcesses(config, options = {}) {
4073
4073
  if (options.targetProcessName) {
4074
4074
  reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
4075
4075
  } else {
4076
- resolve21(processes);
4076
+ resolve22(processes);
4077
4077
  }
4078
4078
  });
4079
4079
  });
@@ -4697,9 +4697,9 @@ var Parser = class {
4697
4697
  return tok2.t === "name" && tok2.v === v;
4698
4698
  }
4699
4699
  parseTop() {
4700
- const path60 = this.parsePath();
4700
+ const path62 = this.parsePath();
4701
4701
  if (this.peek().t !== "eof") this.fail("unexpected trailing input");
4702
- return path60;
4702
+ return path62;
4703
4703
  }
4704
4704
  parsePath() {
4705
4705
  const startTok = this.peek();
@@ -4714,10 +4714,10 @@ var Parser = class {
4714
4714
  }
4715
4715
  const steps = [];
4716
4716
  for (; ; ) {
4717
- const sep6 = this.peek();
4718
- if (sep6.t !== "/" && sep6.t !== "//") break;
4717
+ const sep7 = this.peek();
4718
+ if (sep7.t !== "/" && sep7.t !== "//") break;
4719
4719
  this.next();
4720
- steps.push(this.parseStep(sep6.t === "//"));
4720
+ steps.push(this.parseStep(sep7.t === "//"));
4721
4721
  }
4722
4722
  if (start === "root" && steps.length === 0) this.fail("expected a step");
4723
4723
  return { source: this.src, start, steps };
@@ -5567,7 +5567,7 @@ async function listWindows(opts) {
5567
5567
  // src/hdc/uiActions.ts
5568
5568
  var FOCUS_SETTLE_MS = 400;
5569
5569
  var KEYBOARD_SETTLE_MS = 400;
5570
- var sleep = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
5570
+ var sleep = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
5571
5571
  function selectableTree(layout, windowId) {
5572
5572
  const kb = layout.keyboard;
5573
5573
  return kb?.shown && kb.bundle && windowId === void 0 ? withoutWindow(layout.tree, kb.bundle) : layout.tree;
@@ -5733,7 +5733,7 @@ import * as fs29 from "fs";
5733
5733
  function setHilogLevel(opts) {
5734
5734
  const logger = opts.logger ?? noopLogger;
5735
5735
  const hdc = getHdcPath(opts.config);
5736
- return new Promise((resolve21, reject) => {
5736
+ return new Promise((resolve22, reject) => {
5737
5737
  let child;
5738
5738
  try {
5739
5739
  child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), "shell", "hilog", "-b", opts.level]);
@@ -5753,7 +5753,7 @@ function setHilogLevel(opts) {
5753
5753
  });
5754
5754
  child.once("close", (code) => {
5755
5755
  if (code === 0) {
5756
- resolve21();
5756
+ resolve22();
5757
5757
  } else {
5758
5758
  const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
5759
5759
  logger.error(`[hilog] ${msg}`);
@@ -5855,7 +5855,7 @@ async function recentEntryFilter(opts) {
5855
5855
  };
5856
5856
  }
5857
5857
  function waitForLog(opts) {
5858
- return new Promise((resolve21, reject) => {
5858
+ return new Promise((resolve22, reject) => {
5859
5859
  const deadline = Date.now() + opts.timeoutMs;
5860
5860
  let settled = false;
5861
5861
  let child = null;
@@ -5876,7 +5876,7 @@ function waitForLog(opts) {
5876
5876
  if (settled) return;
5877
5877
  settled = true;
5878
5878
  cleanup();
5879
- resolve21(entry);
5879
+ resolve22(entry);
5880
5880
  };
5881
5881
  const fail = (err) => {
5882
5882
  if (settled) return;
@@ -5931,7 +5931,7 @@ function waitForLog(opts) {
5931
5931
  });
5932
5932
  }
5933
5933
  function watchLog(opts) {
5934
- return new Promise((resolve21, reject) => {
5934
+ return new Promise((resolve22, reject) => {
5935
5935
  const matches = [];
5936
5936
  let settled = false;
5937
5937
  let child = null;
@@ -5950,7 +5950,7 @@ function watchLog(opts) {
5950
5950
  if (settled) return;
5951
5951
  settled = true;
5952
5952
  cleanup();
5953
- resolve21(opts.dedup === false ? matches : dedupEntries(matches));
5953
+ resolve22(opts.dedup === false ? matches : dedupEntries(matches));
5954
5954
  };
5955
5955
  const onAbort = () => {
5956
5956
  if (settled) return;
@@ -5999,7 +5999,7 @@ async function captureLog(opts) {
5999
5999
  let lines = 0;
6000
6000
  let reconnects = 0;
6001
6001
  try {
6002
- await new Promise((resolve21, reject) => {
6002
+ await new Promise((resolve22, reject) => {
6003
6003
  const deadline = opts.durationMs !== void 0 ? Date.now() + opts.durationMs : Infinity;
6004
6004
  let settled = false;
6005
6005
  let child = null;
@@ -6029,7 +6029,7 @@ async function captureLog(opts) {
6029
6029
  if (settled) return;
6030
6030
  settled = true;
6031
6031
  cleanup();
6032
- resolve21();
6032
+ resolve22();
6033
6033
  }
6034
6034
  const fail = (err) => {
6035
6035
  if (settled) return;
@@ -6476,7 +6476,7 @@ function analyzeBlank(img) {
6476
6476
  var DEFAULT_SMOKE_DELAY_MS = 2e3;
6477
6477
  var DEFAULT_SMOKE_PID_TIMEOUT_MS = 1e4;
6478
6478
  var PID_POLL_MS = 500;
6479
- var sleep2 = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
6479
+ var sleep2 = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
6480
6480
  async function pidOf(opts) {
6481
6481
  const proc = await findRunningProcess({ config: opts.config, bundle: opts.bundle, deviceSerial: opts.deviceSerial });
6482
6482
  return proc ? Number(proc.pid) : null;
@@ -6629,7 +6629,7 @@ function runHvigorw(opts) {
6629
6629
  }
6630
6630
  }
6631
6631
  const env = { ...process.env, ...sdkEnv };
6632
- return new Promise((resolve21, reject) => {
6632
+ return new Promise((resolve22, reject) => {
6633
6633
  if (opts.abortSignal?.aborted) {
6634
6634
  reject(new CancelledError("hvigorw build cancelled."));
6635
6635
  return;
@@ -6673,7 +6673,7 @@ function runHvigorw(opts) {
6673
6673
  settled = true;
6674
6674
  cleanup();
6675
6675
  const exitCode = code ?? 1;
6676
- if (exitCode === 0) resolve21({ exitCode });
6676
+ if (exitCode === 0) resolve22({ exitCode });
6677
6677
  else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
6678
6678
  });
6679
6679
  });
@@ -7057,17 +7057,17 @@ function sdkTooOldDiagnostic(diagnostics, sdkHome, projectApi) {
7057
7057
  } catch {
7058
7058
  return null;
7059
7059
  }
7060
- const cache = /* @__PURE__ */ new Map();
7060
+ const cache2 = /* @__PURE__ */ new Map();
7061
7061
  const declares = (api2, s) => {
7062
7062
  const file = moduleDeclarationFile(path33.join(sdkHome, String(api2)), s.module);
7063
- if (!cache.has(file)) {
7063
+ if (!cache2.has(file)) {
7064
7064
  try {
7065
- cache.set(file, fs35.readFileSync(file, "utf8"));
7065
+ cache2.set(file, fs35.readFileSync(file, "utf8"));
7066
7066
  } catch {
7067
- cache.set(file, null);
7067
+ cache2.set(file, null);
7068
7068
  }
7069
7069
  }
7070
- const text = cache.get(file);
7070
+ const text = cache2.get(file);
7071
7071
  return !!text && new RegExp(`\\b${s.symbol.replace(/\$/g, "\\$")}\\b`).test(text);
7072
7072
  };
7073
7073
  const api = apis.find((a) => missing.every((s) => declares(a, s)));
@@ -8169,8 +8169,8 @@ async function startCallbackServer(opts) {
8169
8169
  }
8170
8170
  let resolveCallback;
8171
8171
  let rejectCallback;
8172
- const callback = new Promise((resolve21, reject) => {
8173
- resolveCallback = resolve21;
8172
+ const callback = new Promise((resolve22, reject) => {
8173
+ resolveCallback = resolve22;
8174
8174
  rejectCallback = reject;
8175
8175
  });
8176
8176
  callback.catch(() => {
@@ -8222,12 +8222,12 @@ async function startCallbackServer(opts) {
8222
8222
  }
8223
8223
  });
8224
8224
  server.keepAliveTimeout = 1;
8225
- await new Promise((resolve21, reject) => {
8225
+ await new Promise((resolve22, reject) => {
8226
8226
  server.once("error", (err) => {
8227
8227
  const why = err.code === "EADDRINUSE" ? `port ${requested} is already in use on 127.0.0.1; pick another with --port` : err.code === "EACCES" ? `this user may not listen on port ${requested}; pick one above 1023` : err.message;
8228
8228
  reject(new OniroError(`Failed to start the local login callback server: ${why}.`, err));
8229
8229
  });
8230
- server.listen(requested, "127.0.0.1", resolve21);
8230
+ server.listen(requested, "127.0.0.1", resolve22);
8231
8231
  });
8232
8232
  const port = server.address().port;
8233
8233
  return {
@@ -8249,12 +8249,12 @@ async function startCallbackServer(opts) {
8249
8249
  return { accepted: true };
8250
8250
  },
8251
8251
  stop() {
8252
- return new Promise((resolve21) => {
8252
+ return new Promise((resolve22) => {
8253
8253
  server.closeAllConnections?.();
8254
- const timer = setTimeout(resolve21, 100);
8254
+ const timer = setTimeout(resolve22, 100);
8255
8255
  server.close(() => {
8256
8256
  clearTimeout(timer);
8257
- resolve21();
8257
+ resolve22();
8258
8258
  });
8259
8259
  });
8260
8260
  }
@@ -8286,11 +8286,11 @@ function openBrowser(url) {
8286
8286
  windowsHide: true
8287
8287
  });
8288
8288
  child.unref();
8289
- return new Promise((resolve21, reject) => {
8289
+ return new Promise((resolve22, reject) => {
8290
8290
  child.on("error", (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));
8291
8291
  child.on(
8292
8292
  "exit",
8293
- (code) => code === 0 ? resolve21() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`))
8293
+ (code) => code === 0 ? resolve22() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`))
8294
8294
  );
8295
8295
  });
8296
8296
  }
@@ -12699,13 +12699,13 @@ function cycleFrom(start, g) {
12699
12699
  const node = queue.shift();
12700
12700
  for (const n of g.out.get(key2(node)) ?? []) {
12701
12701
  if (same(n, start)) {
12702
- const path60 = [];
12702
+ const path62 = [];
12703
12703
  let cursor = node;
12704
12704
  while (cursor && !same(cursor, start)) {
12705
- path60.push(cursor);
12705
+ path62.push(cursor);
12706
12706
  cursor = parent.get(key2(cursor));
12707
12707
  }
12708
- return cursor ? [start, ...path60.reverse()] : null;
12708
+ return cursor ? [start, ...path62.reverse()] : null;
12709
12709
  }
12710
12710
  const k = key2(n);
12711
12711
  if (!seen.has(k) && g.out.has(k)) {
@@ -13237,7 +13237,7 @@ async function latestCrash(opts) {
13237
13237
  return verdict;
13238
13238
  }
13239
13239
  if (Date.now() >= deadline) return null;
13240
- await new Promise((resolve21) => setTimeout(resolve21, Math.min(opts.pollMs ?? 1e3, Math.max(0, deadline - Date.now()))));
13240
+ await new Promise((resolve22) => setTimeout(resolve22, Math.min(opts.pollMs ?? 1e3, Math.max(0, deadline - Date.now()))));
13241
13241
  }
13242
13242
  }
13243
13243
 
@@ -13792,12 +13792,12 @@ var UI_RECORD_CSV = "/data/local/tmp/record.csv";
13792
13792
  var RECORD_CONSOLE = "/data/local/tmp/oniro_record_console.txt";
13793
13793
  var MMI_SERVER_DOMAIN = "0xD002801";
13794
13794
  function sleep3(ms, signal) {
13795
- return new Promise((resolve21) => {
13796
- if (signal?.aborted) return resolve21();
13795
+ return new Promise((resolve22) => {
13796
+ if (signal?.aborted) return resolve22();
13797
13797
  const done = () => {
13798
13798
  clearTimeout(t);
13799
13799
  signal?.removeEventListener("abort", done);
13800
- resolve21();
13800
+ resolve22();
13801
13801
  };
13802
13802
  const t = setTimeout(done, ms);
13803
13803
  signal?.addEventListener("abort", done, { once: true });
@@ -14661,11 +14661,11 @@ function parseActiveRefreshRate(hidumper) {
14661
14661
  const m = /activeMode:[^\n]*?refreshRate=(\d+(?:\.\d+)?)/.exec(hidumper);
14662
14662
  return m ? Number(m[1]) : null;
14663
14663
  }
14664
- var sleep5 = (ms, signal) => new Promise((resolve21, reject) => {
14664
+ var sleep5 = (ms, signal) => new Promise((resolve22, reject) => {
14665
14665
  if (signal?.aborted) return reject(new CancelledError("Capture cancelled."));
14666
14666
  const t = setTimeout(() => {
14667
14667
  signal?.removeEventListener("abort", onAbort);
14668
- resolve21();
14668
+ resolve22();
14669
14669
  }, ms);
14670
14670
  const onAbort = () => {
14671
14671
  clearTimeout(t);
@@ -14851,8 +14851,394 @@ async function collectHiperf(run, device, remotePerf, localPerf) {
14851
14851
  return { ...parsed, data };
14852
14852
  }
14853
14853
 
14854
+ // src/docs/search.ts
14855
+ import * as fs63 from "fs";
14856
+ import * as path60 from "path";
14857
+ var SKIP_DIRS = /* @__PURE__ */ new Set(["figures", "figure", "images", "image", "public_sys-resources"]);
14858
+ function listMarkdown(tree) {
14859
+ const out = [];
14860
+ const walk3 = (dir) => {
14861
+ let entries;
14862
+ try {
14863
+ entries = fs63.readdirSync(dir, { withFileTypes: true });
14864
+ } catch {
14865
+ return;
14866
+ }
14867
+ for (const e of entries) {
14868
+ if (e.isDirectory()) {
14869
+ if (!SKIP_DIRS.has(e.name)) walk3(path60.join(dir, e.name));
14870
+ } else if (e.isFile() && e.name.endsWith(".md")) {
14871
+ out.push(path60.join(dir, e.name));
14872
+ }
14873
+ }
14874
+ };
14875
+ walk3(tree);
14876
+ return out.sort();
14877
+ }
14878
+ var WORD = /[a-z0-9_@.]+/g;
14879
+ function docTokens(text) {
14880
+ const out = [];
14881
+ for (const m of text.toLowerCase().matchAll(WORD)) {
14882
+ const w = m[0].replace(/^[.@]+|[.@]+$/g, "");
14883
+ if (w.length >= 2 && w.length <= 40 && !/^\d{13,}$/.test(w)) out.push(w);
14884
+ }
14885
+ return out;
14886
+ }
14887
+ function docQueryTerms(query) {
14888
+ const out = /* @__PURE__ */ new Map();
14889
+ const add = (t, w) => {
14890
+ if (t.length >= 2 && (out.get(t) ?? 0) < w) out.set(t, w);
14891
+ };
14892
+ for (const w of docTokens(query)) {
14893
+ add(w, 1);
14894
+ for (const p of w.split(/[._]/)) if (p.length >= 3 && p !== w) add(p, 0.4);
14895
+ }
14896
+ for (const m of query.matchAll(/[A-Z][a-z]+|[a-z]+|[A-Z]+(?![a-z])|[0-9]+/g)) {
14897
+ if (m[0].length >= 3) add(m[0].toLowerCase(), 0.4);
14898
+ }
14899
+ return [...out].map(([term, weight]) => ({ term, weight }));
14900
+ }
14901
+ function wordIn(text, term) {
14902
+ let i = text.indexOf(term);
14903
+ while (i >= 0) {
14904
+ const before = i === 0 ? "" : text[i - 1] ?? "";
14905
+ const after = text[i + term.length] ?? "";
14906
+ if (!/[a-z0-9]/.test(before) && !/[a-z]/.test(after)) return true;
14907
+ i = text.indexOf(term, i + 1);
14908
+ }
14909
+ return false;
14910
+ }
14911
+ var flat = (s) => Buffer.from(s, "utf8").toString("utf8");
14912
+ function stripMd(line) {
14913
+ return line.replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/<[^>]+>/g, "").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*_]/g, "").trim();
14914
+ }
14915
+ function parseDoc(rel, text) {
14916
+ const lines = text.split("\n");
14917
+ let title = "";
14918
+ const headings = [];
14919
+ for (let i = 0; i < lines.length; i++) {
14920
+ const m = /^(#{1,4})\s+(.+?)\s*#*\s*$/.exec(lines[i] ?? "");
14921
+ if (!m) continue;
14922
+ const level = (m[1] ?? "#").length;
14923
+ const text2 = flat(stripMd(m[2] ?? ""));
14924
+ if (level === 1 && !title) title = text2;
14925
+ else headings.push({ line: i + 1, level, text: text2 });
14926
+ }
14927
+ if (!title) title = path60.basename(rel, ".md");
14928
+ return { path: rel, title, headings, bytes: text.length };
14929
+ }
14930
+ function docWords(rel, text) {
14931
+ const words = /* @__PURE__ */ new Set();
14932
+ const add = (w) => {
14933
+ words.add(w);
14934
+ const stem = /^([a-z_]{3,})\d{1,2}$/.exec(w)?.[1];
14935
+ if (stem !== void 0) words.add(stem);
14936
+ };
14937
+ for (const w of docTokens(text)) {
14938
+ add(w);
14939
+ if (w.includes(".")) {
14940
+ for (const p of w.split(".")) if (p.length >= 3) add(p);
14941
+ }
14942
+ }
14943
+ for (const w of docTokens(rel.replace(/[-/]/g, " "))) words.add(w);
14944
+ return words;
14945
+ }
14946
+ var cache = /* @__PURE__ */ new Map();
14947
+ var DocsIndex = class _DocsIndex {
14948
+ constructor(tree, docs, words, buildMs) {
14949
+ this.tree = tree;
14950
+ this.docs = docs;
14951
+ this.buildMs = buildMs;
14952
+ const lists = /* @__PURE__ */ new Map();
14953
+ let id = 0;
14954
+ for (const set of words) {
14955
+ for (const w of set) {
14956
+ const list = lists.get(w);
14957
+ if (list) list.push(id);
14958
+ else lists.set(flat(w), [id]);
14959
+ }
14960
+ id++;
14961
+ }
14962
+ for (const [w, list] of lists) this.postings.set(w, Int32Array.from(list));
14963
+ }
14964
+ tree;
14965
+ docs;
14966
+ buildMs;
14967
+ /** word → ascending document ids (packed: 4 bytes per occurrence). */
14968
+ postings = /* @__PURE__ */ new Map();
14969
+ /** The index of a tree, built on the first call of a process and kept. */
14970
+ static load(tree) {
14971
+ const key3 = path60.resolve(tree);
14972
+ const hit = cache.get(key3);
14973
+ if (hit) return hit;
14974
+ const started = Date.now();
14975
+ const docs = [];
14976
+ const words = [];
14977
+ for (const abs of listMarkdown(key3)) {
14978
+ const rel = path60.relative(key3, abs).split(path60.sep).join("/");
14979
+ const text = fs63.readFileSync(abs, "utf8");
14980
+ docs.push(parseDoc(rel, text));
14981
+ words.push(docWords(rel, text));
14982
+ }
14983
+ const idx = new _DocsIndex(key3, docs, words, Date.now() - started);
14984
+ cache.set(key3, idx);
14985
+ return idx;
14986
+ }
14987
+ /** An index over in-memory documents (tests). `tree` is used by `show` for reading files. */
14988
+ static fromDocs(tree, docs) {
14989
+ return new _DocsIndex(
14990
+ tree,
14991
+ docs.map((d) => parseDoc(d.path, d.text)),
14992
+ docs.map((d) => docWords(d.path, d.text)),
14993
+ 0
14994
+ );
14995
+ }
14996
+ /** Forget the cached index of a tree (after a sync). */
14997
+ static forget(tree) {
14998
+ cache.delete(path60.resolve(tree));
14999
+ }
15000
+ get size() {
15001
+ return this.docs.length;
15002
+ }
15003
+ has(term) {
15004
+ return this.postings.get(term) ?? [];
15005
+ }
15006
+ /**
15007
+ * Documents containing every word of the query (any of them when none does), scored by
15008
+ * where the words occur: title, headings, path, body; a document whose title is exactly a
15009
+ * query word, or that contains the whole query in a title or heading, ranks higher; the
15010
+ * generated API reference ranks a little below the guides, system-API pages and tables of
15011
+ * contents below everything.
15012
+ */
15013
+ search(query, o = {}) {
15014
+ const terms = docQueryTerms(query);
15015
+ const full = terms.filter((t) => t.weight === 1);
15016
+ const result = { query, terms: terms.map((t) => t.term), total: 0, hits: [] };
15017
+ if (!terms.length) return result;
15018
+ const limit = Math.max(1, Math.min(o.limit ?? 8, 30));
15019
+ const section = o.section?.replace(/^\/+|\/+$/g, "").toLowerCase();
15020
+ const inScope = (d) => !section || d.path.toLowerCase().startsWith(`${section}/`) || d.path.toLowerCase().includes(`/${section}/`);
15021
+ const phrase = query.trim().toLowerCase();
15022
+ const presentBy = /* @__PURE__ */ new Map();
15023
+ for (const t of terms) {
15024
+ for (const id of this.has(t.term)) {
15025
+ const l = presentBy.get(id);
15026
+ if (l) l.push(t);
15027
+ else presentBy.set(id, [t]);
15028
+ }
15029
+ }
15030
+ const scored = (requireAll) => {
15031
+ const out = [];
15032
+ for (const [id, present] of presentBy) {
15033
+ const d = this.docs[id];
15034
+ if (!d) continue;
15035
+ const fullPresent = present.filter((t) => t.weight === 1).length;
15036
+ if (!inScope(d) || requireAll && fullPresent < full.length) continue;
15037
+ const title = d.title.toLowerCase();
15038
+ const p = d.path.toLowerCase();
15039
+ let score = 0;
15040
+ const headingHits = [];
15041
+ for (const h of d.headings) {
15042
+ const ht = h.text.toLowerCase();
15043
+ const n = present.reduce((a, t) => a + (wordIn(ht, t.term) ? t.weight : 0), 0);
15044
+ if (n) headingHits.push({ line: h.line, text: h.text, n });
15045
+ }
15046
+ for (const t of present) {
15047
+ if (wordIn(title, t.term)) score += 8 * t.weight;
15048
+ if (wordIn(p, t.term)) score += 3 * t.weight;
15049
+ score += t.weight;
15050
+ }
15051
+ if (full.some((t) => title === t.term || title.replace(/\s*\(.*\)$/, "") === t.term)) score += 6;
15052
+ if (headingHits.length) score += Math.min(12, headingHits.reduce((a, h) => a + h.n * 2, 0));
15053
+ if (phrase.length > 3) {
15054
+ if (title.includes(phrase)) score += 20;
15055
+ else if (headingHits.some((h) => h.text.toLowerCase().includes(phrase))) score += 10;
15056
+ }
15057
+ if (p.startsWith("reference/apis-")) score -= 2;
15058
+ if (/-sys\.md$/.test(p) || /\(system api\)/i.test(title)) score -= 12;
15059
+ if (/\/(readme|summary)\.md$/i.test(p) || /^readme/i.test(p)) score -= 6;
15060
+ if (fullPresent === full.length) score += 4;
15061
+ headingHits.sort((a, b) => b.n - a.n || a.line - b.line);
15062
+ out.push({
15063
+ d,
15064
+ score: Math.round(score * 10) / 10,
15065
+ headings: headingHits.slice(0, 6).map(({ line, text }) => ({ line, text }))
15066
+ });
15067
+ }
15068
+ return out;
15069
+ };
15070
+ let hits = scored(true);
15071
+ if (!hits.length) hits = scored(false);
15072
+ hits.sort((a, b) => b.score - a.score || a.d.path.localeCompare(b.d.path));
15073
+ result.total = hits.length;
15074
+ result.hits = hits.slice(0, limit).map(({ d, score, headings }) => ({
15075
+ path: d.path,
15076
+ title: d.title,
15077
+ score,
15078
+ headings,
15079
+ snippet: this.snippet(d)
15080
+ }));
15081
+ return result;
15082
+ }
15083
+ snippet(d) {
15084
+ let text;
15085
+ try {
15086
+ text = fs63.readFileSync(path60.join(this.tree, d.path), "utf8");
15087
+ } catch {
15088
+ return "";
15089
+ }
15090
+ const lines = text.split("\n");
15091
+ for (let i = lines.findIndex((l) => /^#\s/.test(l)) + 1; i < lines.length; i++) {
15092
+ const s = stripMd(lines[i] ?? "");
15093
+ if (s && !/^[#>|<-]/.test(s)) return s.length > 220 ? `${s.slice(0, 217)}\u2026` : s;
15094
+ }
15095
+ return "";
15096
+ }
15097
+ /**
15098
+ * A document, or one of its sections: from the heading that matches `heading`
15099
+ * (exactly, else by substring, case-insensitive) to the next heading of the same or a
15100
+ * higher level. Image lines and inline HTML are dropped; the text is cut at `maxLines`
15101
+ * with a note of what was left out.
15102
+ */
15103
+ show(rel, o = {}) {
15104
+ const clean2 = rel.replace(/\\/g, "/").replace(/^\/+/, "").replace(/^en\/application-dev\//, "");
15105
+ const abs = path60.resolve(this.tree, clean2);
15106
+ const inside = abs.startsWith(this.tree + path60.sep);
15107
+ if (!inside || !fs63.existsSync(abs) || !fs63.statSync(abs).isFile()) {
15108
+ const base = path60.basename(clean2, ".md").toLowerCase();
15109
+ let suggestions = this.docs.filter((d) => d.path.toLowerCase().includes(base)).slice(0, 5).map((d) => d.path);
15110
+ if (!suggestions.length) suggestions = this.search(base.replace(/[-_]/g, " "), { limit: 5 }).hits.map((h) => h.path);
15111
+ return { found: false, path: clean2, error: `No document at ${clean2}.`, suggestions };
15112
+ }
15113
+ const text = fs63.readFileSync(abs, "utf8");
15114
+ const entry = this.docs.find((d) => d.path === clean2) ?? parseDoc(clean2, text);
15115
+ const lines = text.split("\n");
15116
+ let from = 0;
15117
+ let to = lines.length;
15118
+ if (o.heading) {
15119
+ const needle = o.heading.toLowerCase().replace(/^#+\s*/, "").trim();
15120
+ const h = entry.headings.find((x2) => x2.text.toLowerCase() === needle) ?? entry.headings.find((x2) => x2.text.toLowerCase().includes(needle));
15121
+ if (!h) {
15122
+ return {
15123
+ found: false,
15124
+ path: clean2,
15125
+ error: `No heading matching "${o.heading}" in ${clean2}.`,
15126
+ suggestions: entry.headings.slice(0, 30).map((x2) => x2.text)
15127
+ };
15128
+ }
15129
+ from = h.line - 1;
15130
+ const next2 = entry.headings.find((x2) => x2.line > h.line && x2.level <= h.level);
15131
+ to = next2 ? next2.line - 1 : lines.length;
15132
+ }
15133
+ const max = Math.max(20, Math.min(o.maxLines ?? 250, 1200));
15134
+ const body = lines.slice(from, to).filter((l) => !/^\s*!\[[^\]]*\]\([^)]*\)\s*$/.test(l) && !/^\s*<img\b/i.test(l)).map((l) => l.replace(/<br\s*\/?>/gi, " ").replace(/<\/?(p|div|span|b|i|em|strong|sup|sub)>/gi, ""));
15135
+ const truncated = body.length > max;
15136
+ const shown = body.slice(0, max).join("\n") + (truncated ? `
15137
+
15138
+ [\u2026 ${body.length - max} more lines; ask for one section with heading]` : "");
15139
+ return {
15140
+ found: true,
15141
+ path: clean2,
15142
+ text: shown,
15143
+ truncated,
15144
+ lines: body.length,
15145
+ headings: entry.headings.filter((h) => h.line > from && h.line <= to).map(({ line, text: t }) => ({ line, text: t }))
15146
+ };
15147
+ }
15148
+ };
15149
+
15150
+ // src/docs/sync.ts
15151
+ import * as fs64 from "fs";
15152
+ import * as path61 from "path";
15153
+ var DOCS_REPO = "https://gitcode.com/openharmony/docs";
15154
+ var DOCS_SPARSE_PATH = "en/application-dev";
15155
+ var DOCS_SPARSE_PATTERNS = [
15156
+ `/${DOCS_SPARSE_PATH}/`,
15157
+ "!**/figures/",
15158
+ "!**/*.png",
15159
+ "!**/*.gif",
15160
+ "!**/*.jpg",
15161
+ "!**/*.jpeg"
15162
+ ];
15163
+ function docsRefFor(sdk) {
15164
+ const m = sdk.version ? /^(\d+)\.(\d+)\.(\d+)/.exec(sdk.version) : null;
15165
+ if (m) {
15166
+ const [, major, minor, patch] = m;
15167
+ return `OpenHarmony-${Number(major) >= 6 ? `${major}.${minor}` : `${major}.${minor}.${patch}`}-Release`;
15168
+ }
15169
+ const api = sdk.api;
15170
+ if (api === void 0) return "master";
15171
+ if (api <= 18) return "OpenHarmony-5.1.0-Release";
15172
+ if (api <= 20) return "OpenHarmony-6.0-Release";
15173
+ if (api <= 23) return "OpenHarmony-6.1-Release";
15174
+ if (api <= 26) return "OpenHarmony-7.0-Release";
15175
+ return "master";
15176
+ }
15177
+ function readSdkRelease(sdkDir) {
15178
+ try {
15179
+ const pkg = JSON.parse(fs64.readFileSync(path61.join(sdkDir, "ets", "oh-uni-package.json"), "utf8"));
15180
+ const api = Number(pkg.apiVersion);
15181
+ return { api: Number.isFinite(api) ? api : void 0, version: typeof pkg.version === "string" ? pkg.version : void 0 };
15182
+ } catch {
15183
+ return {};
15184
+ }
15185
+ }
15186
+ function getDocsRootDir(config) {
15187
+ return config.get("docsDir", path61.join(getSdkRootDir(config), "docs"));
15188
+ }
15189
+ function docsDirFor(config, ref) {
15190
+ return path61.join(getDocsRootDir(config), ref);
15191
+ }
15192
+ function docsTree(docsDir) {
15193
+ const tree = path61.join(docsDir, DOCS_SPARSE_PATH);
15194
+ return fs64.existsSync(tree) ? tree : null;
15195
+ }
15196
+ async function syncDocs(opts) {
15197
+ const { ref, dir } = opts;
15198
+ const repo = opts.repo ?? DOCS_REPO;
15199
+ const logger = opts.logger;
15200
+ const git = async (args, cwd) => {
15201
+ const r = await runProcess({
15202
+ command: "git",
15203
+ args,
15204
+ cwd,
15205
+ timeoutMs: opts.timeoutMs ?? 6e5,
15206
+ abortSignal: opts.abortSignal,
15207
+ onOutput: (chunk) => {
15208
+ for (const line of chunk.split(/\r?\n/)) if (line.trim()) logger?.debug(`git: ${line.trim()}`);
15209
+ }
15210
+ }).catch((err) => {
15211
+ const msg = err instanceof Error ? err.message : String(err);
15212
+ throw new OniroError(/ENOENT/.test(msg) ? "git is not installed or not on the PATH; `docs sync` needs it." : msg);
15213
+ });
15214
+ if (r.code !== 0) {
15215
+ const tail = (r.stderr || r.stdout).trim().split("\n").filter(Boolean).slice(-3).join(" | ");
15216
+ throw new OniroError(`git ${args[0]} failed (exit ${r.code}): ${tail}`);
15217
+ }
15218
+ return r.stdout;
15219
+ };
15220
+ const exists = fs64.existsSync(path61.join(dir, ".git"));
15221
+ if (exists) {
15222
+ logger?.info(`Updating the ${ref} docs in ${dir}`);
15223
+ await git(["fetch", "--depth", "1", "origin", ref], dir);
15224
+ await git(["sparse-checkout", "set", "--no-cone", ...DOCS_SPARSE_PATTERNS], dir);
15225
+ await git(["reset", "--hard", "FETCH_HEAD"], dir);
15226
+ } else {
15227
+ logger?.info(`Cloning the ${ref} docs (${DOCS_SPARSE_PATH} only) into ${dir}`);
15228
+ fs64.mkdirSync(path61.dirname(dir), { recursive: true });
15229
+ await git(["clone", "--depth", "1", "--filter=blob:none", "--no-checkout", "--branch", ref, repo, dir]);
15230
+ await git(["sparse-checkout", "set", "--no-cone", ...DOCS_SPARSE_PATTERNS], dir);
15231
+ await git(["checkout", ref], dir);
15232
+ }
15233
+ const commit = (await git(["rev-parse", "--short", "HEAD"], dir)).trim() || void 0;
15234
+ const tree = docsTree(dir);
15235
+ const files = tree ? listMarkdown(tree).length : 0;
15236
+ if (!files) throw new OniroError(`The ${ref} clone at ${dir} holds no Markdown under ${DOCS_SPARSE_PATH}.`);
15237
+ return { dir, ref, files, updated: exists, commit };
15238
+ }
15239
+
14854
15240
  // src/index.ts
14855
- var VERSION = "0.17.0";
15241
+ var VERSION = "0.18.0";
14856
15242
  export {
14857
15243
  ALL_SDKS,
14858
15244
  API_INDEX_FORMAT,
@@ -14876,6 +15262,10 @@ export {
14876
15262
  DEFAULT_SMOKE_PID_TIMEOUT_MS,
14877
15263
  DEFAULT_TRACE_BUFFER_KB,
14878
15264
  DEFAULT_TRACE_CATEGORIES,
15265
+ DOCS_REPO,
15266
+ DOCS_SPARSE_PATH,
15267
+ DOCS_SPARSE_PATTERNS,
15268
+ DocsIndex,
14879
15269
  EMULATOR_KERNEL_APPEND,
14880
15270
  FAULTLOG_DIR,
14881
15271
  FAULTLOG_TEMP_DIR,
@@ -14998,6 +15388,12 @@ export {
14998
15388
  diffHapAssets,
14999
15389
  diffLayouts,
15000
15390
  discoverHaps,
15391
+ docQueryTerms,
15392
+ docTokens,
15393
+ docWords,
15394
+ docsDirFor,
15395
+ docsRefFor,
15396
+ docsTree,
15001
15397
  downloadAndInstallSdk,
15002
15398
  downloadFile,
15003
15399
  dumpLayout,
@@ -15058,6 +15454,7 @@ export {
15058
15454
  getDefaultInstanceStatus,
15059
15455
  getDeviceInfo,
15060
15456
  getDisplaySize,
15457
+ getDocsRootDir,
15061
15458
  getEmulatorDir,
15062
15459
  getEmulatorStatus,
15063
15460
  getFreeSpaceBytes,
@@ -15121,6 +15518,7 @@ export {
15121
15518
  listDevices,
15122
15519
  listFaultLogs,
15123
15520
  listLayoutWindows,
15521
+ listMarkdown,
15124
15522
  listModules,
15125
15523
  listPoolInstanceNumbers,
15126
15524
  listPoolInstanceStatuses,
@@ -15161,6 +15559,7 @@ export {
15161
15559
  parseCrashRecordHeads,
15162
15560
  parseDeviceList,
15163
15561
  parseDeviceTime,
15562
+ parseDoc,
15164
15563
  parseDocBlock,
15165
15564
  parseFaultLogList,
15166
15565
  parseFaultLogName,
@@ -15217,6 +15616,7 @@ export {
15217
15616
  readPoolState,
15218
15617
  readProvisionProfile,
15219
15618
  readSdkPkg,
15619
+ readSdkRelease,
15220
15620
  readTestModuleName,
15221
15621
  readZipEntry,
15222
15622
  reboot,
@@ -15279,6 +15679,7 @@ export {
15279
15679
  summarizeDivergenceLayout,
15280
15680
  summarizeLayout,
15281
15681
  summarizeTrace,
15682
+ syncDocs,
15282
15683
  takeScreenshot,
15283
15684
  testHapPath,
15284
15685
  toLongPath,
@@ -15302,6 +15703,7 @@ export {
15302
15703
  windowSubtree,
15303
15704
  withHapZip,
15304
15705
  withoutWindow,
15706
+ wordIn,
15305
15707
  writeJson5File,
15306
15708
  writeJsonFile,
15307
15709
  writePoolState