@openmixer/plugin-qualify 0.14.1 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +117 -14
  2. package/bin/plugin-qualify-sync.mjs +57 -0
  3. package/bin/plugin-qualify.mjs +66 -15
  4. package/dist/adjust-cli.d.ts +83 -0
  5. package/dist/adjust-cli.js +214 -0
  6. package/dist/adjust-cli.js.map +1 -0
  7. package/dist/clap-loader.d.ts +3 -3
  8. package/dist/clap-loader.js +11 -11
  9. package/dist/clap-loader.js.map +1 -1
  10. package/dist/history-adjust.d.ts +77 -0
  11. package/dist/history-adjust.js +99 -0
  12. package/dist/history-adjust.js.map +1 -0
  13. package/dist/history-file.d.ts +73 -0
  14. package/dist/history-file.js +133 -0
  15. package/dist/history-file.js.map +1 -0
  16. package/dist/host-admission.d.ts +53 -0
  17. package/dist/host-admission.js +96 -0
  18. package/dist/host-admission.js.map +1 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +6 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/lv2-loader.d.ts +16 -2
  23. package/dist/lv2-loader.js +168 -17
  24. package/dist/lv2-loader.js.map +1 -1
  25. package/dist/measurement/cli.d.ts +6 -4
  26. package/dist/measurement/cli.js +12 -19
  27. package/dist/measurement/cli.js.map +1 -1
  28. package/dist/pins-file.d.ts +8 -2
  29. package/dist/pins-file.js +17 -3
  30. package/dist/pins-file.js.map +1 -1
  31. package/dist/probe-judge.d.ts +11 -1
  32. package/dist/probe-judge.js +20 -1
  33. package/dist/probe-judge.js.map +1 -1
  34. package/dist/probe-output-fixtures.d.ts +10 -0
  35. package/dist/probe-output-fixtures.js +86 -0
  36. package/dist/probe-output-fixtures.js.map +1 -1
  37. package/dist/probe-output.d.ts +2 -0
  38. package/dist/probe-output.js +1 -0
  39. package/dist/probe-output.js.map +1 -1
  40. package/dist/probe-runner.d.ts +9 -3
  41. package/dist/probe-runner.js +36 -12
  42. package/dist/probe-runner.js.map +1 -1
  43. package/dist/qualification-record.d.ts +109 -3
  44. package/dist/qualification-record.js +79 -13
  45. package/dist/qualification-record.js.map +1 -1
  46. package/dist/qualify-cli.d.ts +0 -1
  47. package/dist/qualify-cli.js +2 -4
  48. package/dist/qualify-cli.js.map +1 -1
  49. package/dist/qualify-declarations.d.ts +1 -1
  50. package/dist/qualify-declarations.js +1 -1
  51. package/dist/qualify-options.js +1 -2
  52. package/dist/qualify-options.js.map +1 -1
  53. package/dist/qualify-sync.d.ts +202 -0
  54. package/dist/qualify-sync.js +731 -0
  55. package/dist/qualify-sync.js.map +1 -0
  56. package/dist/whole-file.d.ts +3 -0
  57. package/dist/whole-file.js +36 -0
  58. package/dist/whole-file.js.map +1 -0
  59. package/fixtures/admission/2026-10-26.json +19 -0
  60. package/fixtures/clap-scan/fake.json +24 -24
  61. package/package.json +5 -4
  62. package/src/adjust-cli.ts +262 -0
  63. package/src/clap-loader.ts +9 -13
  64. package/src/history-adjust.ts +156 -0
  65. package/src/history-file.ts +177 -0
  66. package/src/host-admission.ts +136 -0
  67. package/src/index.ts +6 -0
  68. package/src/lv2-loader.ts +150 -15
  69. package/src/measurement/cli.ts +11 -17
  70. package/src/pins-file.ts +17 -3
  71. package/src/probe-judge.ts +27 -1
  72. package/src/probe-output-fixtures.ts +86 -0
  73. package/src/probe-output.ts +3 -0
  74. package/src/probe-runner.ts +45 -14
  75. package/src/qualification-record.ts +174 -15
  76. package/src/qualify-cli.ts +2 -5
  77. package/src/qualify-declarations.ts +1 -1
  78. package/src/qualify-options.ts +1 -2
  79. package/src/qualify-sync.ts +830 -0
  80. package/src/whole-file.ts +35 -0
  81. package/tools/_declarations.py +1 -1
  82. package/tools/gen-hosting-codes.mjs +1 -1
  83. package/tools/mod-host-admit.mjs +74 -0
@@ -0,0 +1,133 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * The running-history file plugin-hostd writes and `plugin-qualify adjust --history` reads (plugin-hostd's `data/history.json`
5
+ * and `src/history.c`): a header line, then one line per plugin binary and host class,
6
+ *
7
+ * history <uri> <binary digest> <host class> key=value ...
8
+ *
9
+ * The reader keeps the daemon's rules for what it reads: the header must be the one it knows, a line outside the grammar
10
+ * is not read (and counted, so the caller can say so), a second line of one plugin binary on one host class is not read,
11
+ * a value is a whole number or a decimal and never negative. It differs in one place on purpose: a key it does not know
12
+ * is not a reason to skip the line, it is kept on the record (`unknownKeys`) and the known keys are read, so a daemon
13
+ * that grows a key inside history/1 does not blind the qualifier. Nothing here writes the file; only the daemon does.
14
+ */
15
+ /** The header line of the format this reader knows, plugin-hostd's `PHD_HISTORY_HEADER`. */
16
+ export const HISTORY_HEADER = "# plugin-hostd history/1";
17
+ /** The verb a record line starts with, plugin-hostd's `PHD_HISTORY_RECORD`. */
18
+ export const HISTORY_RECORD = "history";
19
+ /**
20
+ * PLUGIN_HOSTD_HISTORY_KEYS in the daemon's order, each with the field it fills and how its value is written. The words
21
+ * are plugin-hostd's (`data/history.json`); `history-file.test.ts` holds this table to them.
22
+ */
23
+ const KEYS = [
24
+ { word: "first", field: "first", kind: "time" },
25
+ { word: "last", field: "last", kind: "time" },
26
+ { word: "windows_solo", field: "windowsSolo", kind: "count" },
27
+ { word: "windows_grouped", field: "windowsGrouped", kind: "count" },
28
+ { word: "cpu_p95_solo", field: "cpuP95Solo", kind: "decimal" },
29
+ { word: "cpu_max_solo", field: "cpuMaxSolo", kind: "decimal" },
30
+ { word: "pss_mb_solo", field: "pssMbSolo", kind: "decimal" },
31
+ { word: "xrun_windows_solo", field: "xrunWindowsSolo", kind: "count" },
32
+ { word: "xrun_windows_grouped", field: "xrunWindowsGrouped", kind: "count" },
33
+ { word: "crashes_solo", field: "crashesSolo", kind: "count" },
34
+ { word: "crashes_grouped", field: "crashesGrouped", kind: "count" },
35
+ { word: "restarts_grouped", field: "restartsGrouped", kind: "count" },
36
+ { word: "quarantines", field: "quarantines", kind: "count" },
37
+ { word: "last_crash", field: "lastCrash", kind: "time" },
38
+ { word: "last_crash_grouped", field: "lastCrashGrouped", kind: "time" },
39
+ ];
40
+ /** The words of the keys this reader knows, in the daemon's order. */
41
+ export const HISTORY_KEY_WORDS = KEYS.map((k) => k.word);
42
+ const HEX = /^[0-9a-f]{64}$/;
43
+ const WHOLE = /^[0-9]+$/;
44
+ const DECIMAL = /^([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
45
+ function number(text, kind) {
46
+ if (kind === "decimal") {
47
+ if (!DECIMAL.test(text))
48
+ return undefined;
49
+ const v = Number(text);
50
+ return Number.isFinite(v) ? v : undefined;
51
+ }
52
+ if (!WHOLE.test(text))
53
+ return undefined;
54
+ const v = Number(text);
55
+ return Number.isSafeInteger(v) ? v : undefined;
56
+ }
57
+ /** One record line, or the reason it is outside the grammar. */
58
+ function parseRecord(words) {
59
+ if (words.length < 4 || words[0] !== HISTORY_RECORD)
60
+ return `not a ${HISTORY_RECORD} line with a uri, a digest and a host class`;
61
+ const [, uri, digest, hostClass] = words;
62
+ if (!HEX.test(digest))
63
+ return `${digest}: not a digest of 64 lowercase hex digits`;
64
+ const values = {};
65
+ const unknownKeys = {};
66
+ const seen = new Set();
67
+ for (const word of words.slice(4)) {
68
+ const eq = word.indexOf("=");
69
+ if (eq < 0)
70
+ return `${word}: not key=value`;
71
+ const key = word.slice(0, eq);
72
+ const text = word.slice(eq + 1);
73
+ if (seen.has(key))
74
+ return `${key}: given twice`;
75
+ seen.add(key);
76
+ const known = KEYS.find((k) => k.word === key);
77
+ if (known === undefined) {
78
+ unknownKeys[key] = text;
79
+ continue;
80
+ }
81
+ const v = number(text, known.kind);
82
+ if (v === undefined)
83
+ return `${key}=${text}: not ${known.kind === "decimal" ? "a decimal" : "a whole number"}, or negative`;
84
+ values[known.field] = v;
85
+ }
86
+ const counters = Object.fromEntries(KEYS.map((k) => [k.field, values[k.field] ?? 0]));
87
+ return { uri, digest, hostClass, ...counters, unknownKeys };
88
+ }
89
+ /**
90
+ * Read the text of a history file. A file whose first line (blank lines apart) is not the header is refused as a whole,
91
+ * as the daemon blocks it: a version this reader does not know is not read by guessing. Comment lines and blank lines
92
+ * after the header are skipped.
93
+ */
94
+ export function readHistory(text) {
95
+ const lines = text.split("\n").map((l) => l.replace(/\r$/, ""));
96
+ const first = lines.findIndex((l) => l.trim() !== "");
97
+ if (first < 0)
98
+ return { ok: true, records: [], ignored: [] };
99
+ if (lines[first] !== HISTORY_HEADER) {
100
+ return {
101
+ ok: false,
102
+ problem: lines[first].startsWith("# plugin-hostd history/")
103
+ ? `${JSON.stringify(lines[first])} is a version this reader does not know (it reads ${HISTORY_HEADER})`
104
+ : "not a history file: it does not begin with " + HISTORY_HEADER,
105
+ };
106
+ }
107
+ const records = [];
108
+ const ignored = [];
109
+ for (let i = first + 1; i < lines.length; i++) {
110
+ const line = lines[i];
111
+ if (line.trim() === "" || line.startsWith("#"))
112
+ continue;
113
+ const parsed = parseRecord(line.split(/[ \t]+/).filter((w) => w !== ""));
114
+ if (typeof parsed === "string") {
115
+ ignored.push({ line: i + 1, problem: parsed });
116
+ }
117
+ else if (records.some((r) => r.uri === parsed.uri && r.digest === parsed.digest && r.hostClass === parsed.hostClass)) {
118
+ ignored.push({ line: i + 1, problem: "a second line of one plugin binary on one host class" });
119
+ }
120
+ else
121
+ records.push(parsed);
122
+ }
123
+ return { ok: true, records, ignored };
124
+ }
125
+ /** The record of one plugin binary on one host class, or `undefined`. */
126
+ export function findHistory(records, uri, digest, hostClass) {
127
+ return records.find((r) => r.uri === uri && r.digest === digest && r.hostClass === hostClass);
128
+ }
129
+ /** The host classes a history holds a record for, sorted. */
130
+ export function historyClasses(records) {
131
+ return [...new Set(records.map((r) => r.hostClass))].sort();
132
+ }
133
+ //# sourceMappingURL=history-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-file.js","sourceRoot":"","sources":["../src/history-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { HostProfile } from "./host-profiles.js";
2
+ /** The profile ids whose verdict is measured by a run. */
3
+ export declare const ADMITTED_HOSTS: readonly ["mod-host", "jalv"];
4
+ export type AdmittedHost = (typeof ADMITTED_HOSTS)[number];
5
+ /** The admitting host of a profile, or `undefined` when its verdict is judged from a declaration. */
6
+ export declare function admittedHostOf(profile: HostProfile): AdmittedHost | undefined;
7
+ /** What running the plugin under one host came to. */
8
+ export interface HostAdmission {
9
+ readonly host: AdmittedHost;
10
+ /** False when the host could not be run (not installed): there is no evidence either way. */
11
+ readonly measured: boolean;
12
+ readonly admitted: boolean;
13
+ /** Why not: `<host>.resp-<n>`, `<host>.signal-<SIG>`, `mod-host.died-on-add`, `jalv.unknown-port-type`, `<host>.not-installed`, … */
14
+ readonly code?: string;
15
+ readonly params: Readonly<Record<string, string | number>>;
16
+ }
17
+ /** One command mod-host was sent and what came of it: its `resp` number, or how the host died. */
18
+ export interface ModHostStep {
19
+ readonly cmd: "add" | "remove";
20
+ readonly resp?: number;
21
+ /** The signal that killed the host, or `exit` / `closed` when it went without one. */
22
+ readonly died?: string;
23
+ }
24
+ /** What `tools/mod-host-admit.mjs` printed. */
25
+ export interface ModHostRun {
26
+ readonly installed: boolean;
27
+ readonly steps: readonly ModHostStep[];
28
+ }
29
+ /** The verdict of a mod-host run: the first step that did not answer `resp 0` decides. */
30
+ export declare function classifyModHostRun(run: ModHostRun): HostAdmission;
31
+ /** What `jalv -n <name> <uri>` did in its window. */
32
+ export interface JalvRun {
33
+ readonly installed: boolean;
34
+ /** True when jalv was still running at the deadline and was stopped by the caller. */
35
+ readonly stillRunning: boolean;
36
+ readonly status: number | null;
37
+ readonly signal: string | null;
38
+ readonly stderr: string;
39
+ }
40
+ /** The verdict of a jalv run: alive at the deadline is hosted; a signal, an unknown port type, or an exit is not. */
41
+ export declare function classifyJalvRun(run: JalvRun): HostAdmission;
42
+ /** How long jalv must stay alive to count as hosting the plugin, in milliseconds. */
43
+ export declare const JALV_HOSTED_MS = 3000;
44
+ /** The wall clock of one whole mod-host admission, in milliseconds. */
45
+ export declare const MOD_HOST_ADMISSION_MS = 30000;
46
+ export interface AdmissionRuns {
47
+ readonly modHost: (uri: string) => ModHostRun;
48
+ readonly jalv: (uri: string) => JalvRun;
49
+ }
50
+ /** The runs against the installed hosts. */
51
+ export declare const SPAWNED_ADMISSIONS: AdmissionRuns;
52
+ /** One admission of `uri` under `host`. */
53
+ export declare function admitPlugin(host: AdmittedHost, uri: string, runs?: AdmissionRuns): HostAdmission;
@@ -0,0 +1,96 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * HOST ADMISSION — a `mod-host` or `jalv` verdict is MEASURED by running the plugin under that host,
5
+ * one admission per plugin, not judged from a declaration. mod-host: `add`, `remove` on
6
+ * its socket, a fresh host after any death (`tools/mod-host-admit.mjs` does the run and prints what
7
+ * happened; one line of JSON). jalv: `jalv -n <name> <uri>` headless, hosted when it is still alive
8
+ * at the deadline. The classifiers here are pure: what the host answered goes in, a {@link HostAdmission}
9
+ * with the deciding code comes out; the runs are injected, so a test replays recorded answers.
10
+ */
11
+ import { spawnSync } from "node:child_process";
12
+ import { fileURLToPath } from "node:url";
13
+ /** The profile ids whose verdict is measured by a run. */
14
+ export const ADMITTED_HOSTS = ["mod-host", "jalv"];
15
+ /** The admitting host of a profile, or `undefined` when its verdict is judged from a declaration. */
16
+ export function admittedHostOf(profile) {
17
+ return ADMITTED_HOSTS.find((h) => h === profile.id);
18
+ }
19
+ const admitted = (host) => ({ host, measured: true, admitted: true, params: {} });
20
+ const refused = (host, code, params = {}) => ({
21
+ host,
22
+ measured: true,
23
+ admitted: false,
24
+ code: `${host}.${code}`,
25
+ params,
26
+ });
27
+ const notInstalled = (host) => ({ host, measured: false, admitted: false, code: `${host}.not-installed`, params: {} });
28
+ /** The verdict of a mod-host run: the first step that did not answer `resp 0` decides. */
29
+ export function classifyModHostRun(run) {
30
+ if (!run.installed)
31
+ return notInstalled("mod-host");
32
+ for (const s of run.steps) {
33
+ if (s.died !== undefined) {
34
+ if (s.died.startsWith("SIG"))
35
+ return refused("mod-host", `signal-${s.died}`, { step: s.cmd });
36
+ return s.cmd === "add" ? refused("mod-host", "died-on-add", { how: s.died }) : refused("mod-host", "died", { step: s.cmd, how: s.died });
37
+ }
38
+ if (s.resp === undefined)
39
+ return refused("mod-host", "no-answer", { step: s.cmd });
40
+ // mod-host answers an error as a negative number (`resp -102`); the code carries its magnitude
41
+ if (s.resp < 0)
42
+ return refused("mod-host", `resp-${-s.resp}`, { step: s.cmd, resp: s.resp });
43
+ }
44
+ if (run.steps.length === 0)
45
+ return refused("mod-host", "no-answer");
46
+ return admitted("mod-host");
47
+ }
48
+ const UNKNOWN_PORT_TYPE = /Mandatory port "([^"]*)" has unknown type/;
49
+ /** The verdict of a jalv run: alive at the deadline is hosted; a signal, an unknown port type, or an exit is not. */
50
+ export function classifyJalvRun(run) {
51
+ if (!run.installed)
52
+ return notInstalled("jalv");
53
+ if (run.stillRunning)
54
+ return admitted("jalv");
55
+ if (run.signal !== null)
56
+ return refused("jalv", `signal-${run.signal}`);
57
+ const port = UNKNOWN_PORT_TYPE.exec(run.stderr)?.[1];
58
+ if (port !== undefined)
59
+ return refused("jalv", "unknown-port-type", { port });
60
+ if (run.status !== 0 && run.status !== null)
61
+ return refused("jalv", `exit-${run.status}`);
62
+ return admitted("jalv");
63
+ }
64
+ /** How long jalv must stay alive to count as hosting the plugin, in milliseconds. */
65
+ export const JALV_HOSTED_MS = 3000;
66
+ /** The wall clock of one whole mod-host admission, in milliseconds. */
67
+ export const MOD_HOST_ADMISSION_MS = 30000;
68
+ const MOD_HOST_ADMIT = fileURLToPath(new URL("../tools/mod-host-admit.mjs", import.meta.url));
69
+ /** The runs against the installed hosts. */
70
+ export const SPAWNED_ADMISSIONS = {
71
+ modHost(uri) {
72
+ const r = spawnSync(process.execPath, [MOD_HOST_ADMIT, uri], { encoding: "utf8", timeout: MOD_HOST_ADMISSION_MS });
73
+ if (r.error !== undefined || r.status !== 0) {
74
+ throw new Error(`mod-host admission of ${uri} gave no answer (${r.error?.message ?? `exit ${String(r.status)}`}): ${(r.stderr ?? "").trim()}`);
75
+ }
76
+ return JSON.parse(r.stdout);
77
+ },
78
+ jalv(uri) {
79
+ const r = spawnSync("jalv", ["-n", "plugin-qualify", uri], { encoding: "utf8", timeout: JALV_HOSTED_MS, input: "" });
80
+ const code = r.error?.code;
81
+ if (code === "ENOENT")
82
+ return { installed: false, stillRunning: false, status: null, signal: null, stderr: "" };
83
+ return { installed: true, stillRunning: code === "ETIMEDOUT", status: r.status, signal: code === "ETIMEDOUT" ? null : r.signal, stderr: r.stderr ?? "" };
84
+ },
85
+ };
86
+ /** One admission of `uri` under `host`. */
87
+ export function admitPlugin(host, uri, runs = SPAWNED_ADMISSIONS) {
88
+ try {
89
+ return host === "mod-host" ? classifyModHostRun(runs.modHost(uri)) : classifyJalvRun(runs.jalv(uri));
90
+ }
91
+ catch (e) {
92
+ // the run itself broke: nothing was learned about the plugin, so nothing is rated
93
+ return { host, measured: false, admitted: false, code: `${host}.admission-failed`, params: { problem: e instanceof Error ? e.message : String(e) } };
94
+ }
95
+ }
96
+ //# sourceMappingURL=host-admission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-admission.js","sourceRoot":"","sources":["../src/host-admission.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -23,3 +23,9 @@ export * from "./probe-judge.js";
23
23
  export * from "./qualification-record.js";
24
24
  export * from "./probe-runner.js";
25
25
  export * from "./judge-cli.js";
26
+ export * from "./whole-file.js";
27
+ export * from "./qualify-sync.js";
28
+ export * from "./host-admission.js";
29
+ export * from "./history-file.js";
30
+ export * from "./history-adjust.js";
31
+ export * from "./adjust-cli.js";
package/dist/index.js CHANGED
@@ -25,4 +25,10 @@ export * from "./probe-judge.js";
25
25
  export * from "./qualification-record.js";
26
26
  export * from "./probe-runner.js";
27
27
  export * from "./judge-cli.js";
28
+ export * from "./whole-file.js";
29
+ export * from "./qualify-sync.js";
30
+ export * from "./host-admission.js";
31
+ export * from "./history-file.js";
32
+ export * from "./history-adjust.js";
33
+ export * from "./adjust-cli.js";
28
34
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,sDAAsD;AACtD;;;GAGG;AACH,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,sDAAsD;AACtD;;;GAGG;AACH,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
@@ -1,5 +1,18 @@
1
1
  import type { PluginLoader } from "./loader.js";
2
- /** The plugins a bundle manifest declares: one statement per subject, `;`-separated predicates. */
2
+ /** A plugin a manifest declares, with the files it names for it, each relative to the bundle, in the order named. */
3
+ export interface ManifestPlugin {
4
+ readonly uri: string;
5
+ readonly files: readonly string[];
6
+ /** The basename of its `lv2:binary`, when it names one. */
7
+ readonly binary?: string;
8
+ }
9
+ /**
10
+ * Every plugin a bundle manifest declares and the files it names for it with `lv2:binary` or `rdfs:seeAlso`: the
11
+ * files plugin-hostd's pin holds besides `manifest.ttl` itself. A file named outside the bundle (an absolute IRI) is
12
+ * not one of them.
13
+ */
14
+ export declare function manifestPlugins(ttl: string): ManifestPlugin[];
15
+ /** The plugins a bundle manifest declares, each with its `lv2:binary` basename. */
3
16
  export declare function pluginsInManifest(ttl: string): {
4
17
  uri: string;
5
18
  binary?: string;
@@ -7,6 +20,7 @@ export declare function pluginsInManifest(ttl: string): {
7
20
  export declare const lv2Loader: PluginLoader;
8
21
  /**
9
22
  * Every `.lv2` bundle directly under the LV2 search path (`LV2_PATH`, else lilv's defaults). An
10
- * absent directory holds none; any other fs error propagates for the caller to name.
23
+ * absent directory holds none; any other fs error propagates for the caller to name. A bundle is
24
+ * a directory holding `manifest.ttl`: a dangling `.lv2` symlink or a plain `.lv2` file is not one.
11
25
  */
12
26
  export declare function lv2BundlesOnPath(env: Readonly<Record<string, string | undefined>>, home?: string): string[];
@@ -6,28 +6,167 @@
6
6
  * plugin, with its `lv2:binary` basename. Anything else shaped like a URI (`scheme:rest`) is one
7
7
  * plugin. A path that does not exist is not this loader's — the CLI refuses it by name.
8
8
  *
9
- * The manifest read is the subset every LV2 bundle's manifest uses (subject, `a lv2:Plugin`,
10
- * `lv2:binary <x.so>`), not a Turtle parser; `--all` goes through lilv itself.
9
+ * The manifest is read as plugin-hostd reads it to pin a plugin: statements of IRIs and prefixed names, with blank
10
+ * nodes and collections stepped over, not a whole Turtle parser. A plugin is a subject typed `lv2:Plugin`; its files
11
+ * are the ones the manifest names for it with `lv2:binary` or `rdfs:seeAlso`.
11
12
  */
12
13
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
13
14
  import { homedir } from "node:os";
14
15
  import { basename, join, resolve } from "node:path";
15
16
  const URI_SHAPE = /^[A-Za-z][A-Za-z0-9+.-]*:\S+$/;
16
- /** The plugins a bundle manifest declares: one statement per subject, `;`-separated predicates. */
17
- export function pluginsInManifest(ttl) {
18
- const body = ttl.replace(/#[^\n>]*$/gm, "");
17
+ const RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
18
+ const LV2_PLUGIN = "http://lv2plug.in/ns/lv2core#Plugin";
19
+ const LV2_BINARY = "http://lv2plug.in/ns/lv2core#binary";
20
+ const RDFS_SEE_ALSO = "http://www.w3.org/2000/01/rdf-schema#seeAlso";
21
+ /** The words of a Turtle text: IRIs, prefixed names, literals (with their tag or type) and punctuation; comments dropped. */
22
+ function turtleTokens(ttl) {
19
23
  const out = [];
20
- const statement = /<([^>]+)>\s+((?:[^.<"]|<[^>]*>|"[^"]*")*)\./g;
21
- for (let m = statement.exec(body); m !== null; m = statement.exec(body)) {
22
- const [, subject, predicates] = m;
23
- if (subject === undefined || predicates === undefined)
24
+ let i = 0;
25
+ while (i < ttl.length) {
26
+ const c = ttl[i];
27
+ if (/\s/.test(c))
28
+ i++;
29
+ else if (c === "#")
30
+ while (i < ttl.length && ttl[i] !== "\n")
31
+ i++;
32
+ else if (c === "<") {
33
+ const end = ttl.indexOf(">", i);
34
+ if (end < 0)
35
+ break;
36
+ out.push({ kind: "iri", text: ttl.slice(i + 1, end) });
37
+ i = end + 1;
38
+ }
39
+ else if (c === '"' || c === "'") {
40
+ const quote = ttl.startsWith(c.repeat(3), i) ? c.repeat(3) : c;
41
+ let j = i + quote.length;
42
+ while (j < ttl.length && !ttl.startsWith(quote, j))
43
+ j += ttl[j] === "\\" ? 2 : 1;
44
+ i = j + quote.length;
45
+ // a language tag or a datatype belongs to the literal
46
+ if (ttl[i] === "@")
47
+ while (i < ttl.length && /[A-Za-z0-9-@]/.test(ttl[i]))
48
+ i++;
49
+ else if (ttl.startsWith("^^", i)) {
50
+ i += 2;
51
+ if (ttl[i] === "<")
52
+ i = ttl.indexOf(">", i) + 1;
53
+ else
54
+ while (i < ttl.length && /[^\s;,.\])]/.test(ttl[i]))
55
+ i++;
56
+ }
57
+ out.push({ kind: "literal", text: "" });
58
+ }
59
+ else if (".;,[]()".includes(c)) {
60
+ out.push({ kind: "punct", text: c });
61
+ i++;
62
+ }
63
+ else {
64
+ let j = i;
65
+ while (j < ttl.length && /[^\s<>"';,\[\]()]/.test(ttl[j]) && !(ttl[j] === "." && (j + 1 >= ttl.length || /\s/.test(ttl[j + 1]))))
66
+ j++;
67
+ out.push({ kind: "name", text: ttl.slice(i, j) });
68
+ i = Math.max(j, i + 1);
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * Every plugin a bundle manifest declares and the files it names for it with `lv2:binary` or `rdfs:seeAlso`: the
75
+ * files plugin-hostd's pin holds besides `manifest.ttl` itself. A file named outside the bundle (an absolute IRI) is
76
+ * not one of them.
77
+ */
78
+ export function manifestPlugins(ttl) {
79
+ // the three vocabularies every manifest uses, so a manifest that leaves a prefix undeclared still reads
80
+ const prefixes = new Map([
81
+ ["lv2", "http://lv2plug.in/ns/lv2core#"],
82
+ ["rdfs", "http://www.w3.org/2000/01/rdf-schema#"],
83
+ ["rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"],
84
+ ]);
85
+ const subjects = new Map();
86
+ const expand = (t) => {
87
+ if (t.kind === "iri")
88
+ return t.text;
89
+ if (t.kind !== "name")
90
+ return undefined;
91
+ if (t.text === "a")
92
+ return RDF_TYPE;
93
+ const colon = t.text.indexOf(":");
94
+ const base = colon < 0 ? undefined : prefixes.get(t.text.slice(0, colon));
95
+ return base === undefined ? undefined : base + t.text.slice(colon + 1);
96
+ };
97
+ const tokens = turtleTokens(ttl);
98
+ let state = "subject";
99
+ let depth = 0;
100
+ let subject;
101
+ let predicate;
102
+ for (let k = 0; k < tokens.length; k++) {
103
+ const t = tokens[k];
104
+ if (t.kind === "name" && /^(@prefix|PREFIX)$/i.test(t.text) && state === "subject" && depth === 0) {
105
+ const name = tokens[k + 1]?.text ?? "";
106
+ const iri = tokens[k + 2];
107
+ if (iri?.kind === "iri")
108
+ prefixes.set(name.replace(/:$/, ""), iri.text);
109
+ k += t.text.startsWith("@") ? 3 : 2;
110
+ continue;
111
+ }
112
+ if (t.kind === "name" && /^(@base|BASE)$/i.test(t.text) && state === "subject" && depth === 0) {
113
+ k += t.text.startsWith("@") ? 2 : 1;
114
+ continue;
115
+ }
116
+ if (t.kind === "punct" && (t.text === "[" || t.text === "(")) {
117
+ if (depth++ === 0 && state === "subject")
118
+ subject = undefined;
24
119
  continue;
25
- if (!/(^|;)\s*a\s+lv2:Plugin\b/.test(predicates))
120
+ }
121
+ if (t.kind === "punct" && (t.text === "]" || t.text === ")")) {
122
+ if (depth > 0 && --depth === 0)
123
+ state = state === "subject" ? "predicate" : "after";
124
+ continue;
125
+ }
126
+ if (depth > 0)
127
+ continue;
128
+ if (t.kind === "punct") {
129
+ if (t.text === ".")
130
+ state = "subject";
131
+ else if (t.text === ";")
132
+ state = "predicate";
133
+ else if (t.text === ",")
134
+ state = "object";
26
135
  continue;
27
- const bin = /lv2:binary\s+<([^>]+)>/.exec(predicates)?.[1];
28
- out.push(bin === undefined ? { uri: subject } : { uri: subject, binary: basename(bin) });
136
+ }
137
+ if (state === "subject") {
138
+ subject = expand(t);
139
+ state = "predicate";
140
+ }
141
+ else if (state === "predicate") {
142
+ predicate = expand(t);
143
+ state = "object";
144
+ }
145
+ else if (state === "object") {
146
+ state = "after";
147
+ if (subject === undefined)
148
+ continue;
149
+ const entry = subjects.get(subject) ?? { typed: false, files: [] };
150
+ subjects.set(subject, entry);
151
+ const object = expand(t);
152
+ if (predicate === RDF_TYPE && object === LV2_PLUGIN)
153
+ entry.typed = true;
154
+ if ((predicate === LV2_BINARY || predicate === RDFS_SEE_ALSO) && t.kind === "iri" && !/^[A-Za-z][A-Za-z0-9+.-]*:/.test(t.text) && !t.text.startsWith("/")) {
155
+ const file = t.text.replace(/^(\.\/)+/, "");
156
+ if (!entry.files.includes(file))
157
+ entry.files.push(file);
158
+ if (predicate === LV2_BINARY && entry.binary === undefined)
159
+ entry.binary = basename(file);
160
+ }
161
+ }
29
162
  }
30
- return out;
163
+ return [...subjects.entries()]
164
+ .filter(([, e]) => e.typed)
165
+ .map(([uri, e]) => ({ uri, files: e.files, ...(e.binary === undefined ? {} : { binary: e.binary }) }));
166
+ }
167
+ /** The plugins a bundle manifest declares, each with its `lv2:binary` basename. */
168
+ export function pluginsInManifest(ttl) {
169
+ return manifestPlugins(ttl).map((p) => (p.binary === undefined ? { uri: p.uri } : { uri: p.uri, binary: p.binary }));
31
170
  }
32
171
  export const lv2Loader = {
33
172
  format: "lv2",
@@ -52,7 +191,8 @@ export const lv2Loader = {
52
191
  const LV2_DEFAULT_DIRS = [".lv2", "/usr/lib/lv2", "/usr/lib64/lv2", "/usr/local/lib/lv2", "/usr/local/lib64/lv2"];
53
192
  /**
54
193
  * Every `.lv2` bundle directly under the LV2 search path (`LV2_PATH`, else lilv's defaults). An
55
- * absent directory holds none; any other fs error propagates for the caller to name.
194
+ * absent directory holds none; any other fs error propagates for the caller to name. A bundle is
195
+ * a directory holding `manifest.ttl`: a dangling `.lv2` symlink or a plain `.lv2` file is not one.
56
196
  */
57
197
  export function lv2BundlesOnPath(env, home = homedir()) {
58
198
  const named = (env["LV2_PATH"] ?? "").split(":").filter((d) => d !== "");
@@ -69,9 +209,20 @@ export function lv2BundlesOnPath(env, home = homedir()) {
69
209
  continue;
70
210
  throw e;
71
211
  }
72
- for (const n of names.sort())
73
- if (n.endsWith(".lv2"))
74
- bundles.push(join(dir, n));
212
+ for (const n of names.sort()) {
213
+ if (!n.endsWith(".lv2"))
214
+ continue;
215
+ const path = join(dir, n);
216
+ let isBundle;
217
+ try {
218
+ isBundle = statSync(path).isDirectory() && existsSync(join(path, "manifest.ttl"));
219
+ }
220
+ catch {
221
+ isBundle = false; // a dangling symlink
222
+ }
223
+ if (isBundle)
224
+ bundles.push(path);
225
+ }
75
226
  }
76
227
  return bundles;
77
228
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lv2-loader.js","sourceRoot":"","sources":["../src/lv2-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lv2-loader.js","sourceRoot":"","sources":["../src/lv2-loader.ts"],"names":[],"mappings":"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"}
@@ -135,10 +135,12 @@ export interface HostingRunResult {
135
135
  readonly stdout: string;
136
136
  }
137
137
  /**
138
- * One plugin's run of the native measurer as the hosting sweep's JSONL line: the LAST line of its
139
- * stdout that is a JSON object (a plugin may print its own banner first), with the exit status
140
- * beside it, a death written as 128 + its signal and a timeout as 124. A run that printed no line
141
- * is `crashed`, its exit kept: what that exit means is the reader's (`sweep-jsonl.ts`) to say.
138
+ * One plugin's run of the native measurer as the hosting sweep's JSONL line: its stdout's JSON
139
+ * record ({@link extractJsonRecord}, which repairs a plugin's banner printed into the middle of
140
+ * the line), with the exit status beside it, a death written as 128 + its signal and a timeout
141
+ * as 124. A run whose stdout had a `{`-leading line that never repaired is `parseError`; one
142
+ * with no such line at all is `crashed`. Either way the exit is kept: what it means is the
143
+ * reader's (`sweep-jsonl.ts`) to say.
142
144
  */
143
145
  export declare function hostingLine(uri: string, run: HostingRunResult): Record<string, unknown>;
144
146
  /** A parsed command line, or the reason it could not be parsed. */