wyvrnpm 2.11.0 → 2.12.2

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 (49) hide show
  1. package/README.md +1914 -1905
  2. package/bin/{wyvrn.js → wyvrnpm.js} +31 -0
  3. package/cmake/cpp.cmake +9 -9
  4. package/cmake/functions.cmake +224 -224
  5. package/cmake/macros.cmake +284 -284
  6. package/package.json +3 -2
  7. package/src/auth.js +66 -66
  8. package/src/binary-dir.js +95 -0
  9. package/src/bootstrap/cookbook.js +196 -196
  10. package/src/bootstrap/detect.js +150 -150
  11. package/src/bootstrap/index.js +220 -220
  12. package/src/bootstrap/version.js +72 -72
  13. package/src/build/cache.js +344 -344
  14. package/src/build/clone.js +170 -170
  15. package/src/build/cmake.js +342 -342
  16. package/src/build/index.js +299 -297
  17. package/src/build/msvc-env.js +260 -260
  18. package/src/build/recipe.js +188 -188
  19. package/src/commands/add.js +141 -141
  20. package/src/commands/bootstrap.js +96 -96
  21. package/src/commands/build.js +482 -452
  22. package/src/commands/cache.js +189 -189
  23. package/src/commands/clean.js +80 -80
  24. package/src/commands/configure.js +92 -92
  25. package/src/commands/init.js +70 -70
  26. package/src/commands/install-skill.js +115 -115
  27. package/src/commands/install.js +730 -674
  28. package/src/commands/link.js +320 -320
  29. package/src/commands/profile.js +237 -237
  30. package/src/commands/publish.js +584 -555
  31. package/src/commands/show.js +252 -252
  32. package/src/commands/version.js +187 -187
  33. package/src/compat.js +273 -273
  34. package/src/conf/index.js +415 -391
  35. package/src/conf/namespaces.js +94 -94
  36. package/src/context.js +230 -230
  37. package/src/http-fetch.js +53 -53
  38. package/src/ignore.js +118 -118
  39. package/src/logger.js +122 -122
  40. package/src/options.js +303 -303
  41. package/src/settings-overrides.js +152 -152
  42. package/src/toolchain/deps.js +164 -164
  43. package/src/toolchain/index.js +212 -212
  44. package/src/toolchain/presets.js +356 -340
  45. package/src/toolchain/template.cmake +77 -77
  46. package/src/upload-built.js +265 -265
  47. package/src/version-range.js +301 -301
  48. package/src/zip-safe.js +52 -52
  49. package/src/zip-stream.js +126 -0
package/src/auth.js CHANGED
@@ -1,66 +1,66 @@
1
- 'use strict';
2
-
3
- /**
4
- * Resolve an authentication token for HTTP-source reads/writes.
5
- *
6
- * Closes EVALUATION.md S8 — passing `--token <value>` on the command line
7
- * leaks the token into any shell history, process table, or CI job log
8
- * that captures argv. `--token-env <VAR>` and the config equivalent
9
- * `tokenEnv` let users keep the literal value in env only.
10
- *
11
- * Resolution order (first match wins):
12
- * 1. `token` — literal string from CLI or config (explicit beats env).
13
- * 2. `tokenEnv` — name of an env var; its value becomes the token.
14
- *
15
- * Returns `undefined` when nothing is configured (valid — not every source
16
- * needs auth). Throws when `tokenEnv` names a var that is unset or empty.
17
- *
18
- * @param {{ token?: string, tokenEnv?: string }} opts
19
- * @returns {string|undefined}
20
- */
21
- function resolveToken(opts = {}) {
22
- const { token, tokenEnv } = opts;
23
-
24
- if (typeof token === 'string' && token.length > 0) {
25
- return token;
26
- }
27
-
28
- if (typeof tokenEnv === 'string' && tokenEnv.length > 0) {
29
- const value = process.env[tokenEnv];
30
- if (typeof value !== 'string' || value.length === 0) {
31
- throw new Error(
32
- `--token-env ${tokenEnv} (or config tokenEnv=${tokenEnv}) is set, ` +
33
- `but the environment variable is unset or empty.`,
34
- );
35
- }
36
- return value;
37
- }
38
-
39
- return undefined;
40
- }
41
-
42
- /**
43
- * Merge CLI auth args + a source-config entry into a final `{ token }`
44
- * object ready for passing to a provider. Centralises the "CLI wins,
45
- * then env-backed CLI, then config literal, then config env-backed"
46
- * precedence so call sites don't each re-implement it.
47
- *
48
- * @param {{ token?: string, tokenEnv?: string }} cli
49
- * @param {{ token?: string, tokenEnv?: string } | null | undefined} source
50
- * @returns {{ token: string|undefined }}
51
- */
52
- function resolveSourceAuth(cli, source) {
53
- // Try CLI first; if it produced nothing, fall back to the source's
54
- // own stored auth. Each call to resolveToken handles its own
55
- // precedence (literal > env) and throws on invalid tokenEnv.
56
- const fromCli = resolveToken(cli);
57
- if (fromCli !== undefined) return { token: fromCli };
58
-
59
- const fromSource = source ? resolveToken(source) : undefined;
60
- return { token: fromSource };
61
- }
62
-
63
- module.exports = {
64
- resolveToken,
65
- resolveSourceAuth,
66
- };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Resolve an authentication token for HTTP-source reads/writes.
5
+ *
6
+ * Closes EVALUATION.md S8 — passing `--token <value>` on the command line
7
+ * leaks the token into any shell history, process table, or CI job log
8
+ * that captures argv. `--token-env <VAR>` and the config equivalent
9
+ * `tokenEnv` let users keep the literal value in env only.
10
+ *
11
+ * Resolution order (first match wins):
12
+ * 1. `token` — literal string from CLI or config (explicit beats env).
13
+ * 2. `tokenEnv` — name of an env var; its value becomes the token.
14
+ *
15
+ * Returns `undefined` when nothing is configured (valid — not every source
16
+ * needs auth). Throws when `tokenEnv` names a var that is unset or empty.
17
+ *
18
+ * @param {{ token?: string, tokenEnv?: string }} opts
19
+ * @returns {string|undefined}
20
+ */
21
+ function resolveToken(opts = {}) {
22
+ const { token, tokenEnv } = opts;
23
+
24
+ if (typeof token === 'string' && token.length > 0) {
25
+ return token;
26
+ }
27
+
28
+ if (typeof tokenEnv === 'string' && tokenEnv.length > 0) {
29
+ const value = process.env[tokenEnv];
30
+ if (typeof value !== 'string' || value.length === 0) {
31
+ throw new Error(
32
+ `--token-env ${tokenEnv} (or config tokenEnv=${tokenEnv}) is set, ` +
33
+ `but the environment variable is unset or empty.`,
34
+ );
35
+ }
36
+ return value;
37
+ }
38
+
39
+ return undefined;
40
+ }
41
+
42
+ /**
43
+ * Merge CLI auth args + a source-config entry into a final `{ token }`
44
+ * object ready for passing to a provider. Centralises the "CLI wins,
45
+ * then env-backed CLI, then config literal, then config env-backed"
46
+ * precedence so call sites don't each re-implement it.
47
+ *
48
+ * @param {{ token?: string, tokenEnv?: string }} cli
49
+ * @param {{ token?: string, tokenEnv?: string } | null | undefined} source
50
+ * @returns {{ token: string|undefined }}
51
+ */
52
+ function resolveSourceAuth(cli, source) {
53
+ // Try CLI first; if it produced nothing, fall back to the source's
54
+ // own stored auth. Each call to resolveToken handles its own
55
+ // precedence (literal > env) and throws on invalid tokenEnv.
56
+ const fromCli = resolveToken(cli);
57
+ if (fromCli !== undefined) return { token: fromCli };
58
+
59
+ const fromSource = source ? resolveToken(source) : undefined;
60
+ return { token: fromSource };
61
+ }
62
+
63
+ module.exports = {
64
+ resolveToken,
65
+ resolveSourceAuth,
66
+ };
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ // Project-local CMake binary-dir root. Sibling concept to `conf` —
4
+ // non-ABI, dev-local, never published. Two channels feed it:
5
+ //
6
+ // 1. CLI flag `--build-dir <path>` (install + build)
7
+ // 2. wyvrn.local.json `binaryDirRoot` (persistent per-developer)
8
+ //
9
+ // CLI > local > default `"build"`. The resolved value plugs into the
10
+ // preset's binaryDir as `${sourceDir}/<binaryDirRoot>/wyvrn-<profile>`.
11
+ //
12
+ // Why this exists: repos with a `BUILD` Bazel/Buck file at the root
13
+ // collide with the default `build/` subdir on case-insensitive
14
+ // filesystems (Windows NTFS, macOS HFS+ default). gRPC is the
15
+ // canonical case.
16
+
17
+ const path = require('path');
18
+
19
+ const DEFAULT_BINARY_DIR_ROOT = 'build';
20
+
21
+ /**
22
+ * Validate + normalise a candidate binaryDirRoot value. Returns the
23
+ * normalised string (forward slashes, no trailing separator) or
24
+ * throws with a `<source>:` prefix so the caller knows which channel
25
+ * the bad value came from.
26
+ *
27
+ * @param {unknown} value
28
+ * @param {string} source e.g. "--build-dir" or "wyvrn.local.json"
29
+ * @returns {string}
30
+ */
31
+ function validateBinaryDirRoot(value, source) {
32
+ if (typeof value !== 'string') {
33
+ throw new Error(`${source}: binaryDirRoot must be a string, got ${typeof value}`);
34
+ }
35
+ const trimmed = value.trim();
36
+ if (trimmed.length === 0) {
37
+ throw new Error(`${source}: binaryDirRoot must not be empty`);
38
+ }
39
+ // Reject absolute paths — the preset macro is `${sourceDir}/<root>`,
40
+ // so an absolute value would produce nonsense (`${sourceDir}//abs`
41
+ // or `${sourceDir}/C:/...`). If a user genuinely wants an absolute
42
+ // build dir they can hand-edit CMakeUserPresets.json; that's a
43
+ // different escape hatch.
44
+ if (path.isAbsolute(trimmed) || /^[a-zA-Z]:[\\/]/.test(trimmed)) {
45
+ throw new Error(
46
+ `${source}: binaryDirRoot must be relative to the project root, ` +
47
+ `got ${JSON.stringify(trimmed)}`,
48
+ );
49
+ }
50
+
51
+ // Normalise to forward slashes (CMake preset macros expect them) and
52
+ // strip any trailing separators so the join is deterministic.
53
+ const normalised = trimmed.replace(/\\/g, '/').replace(/\/+$/, '');
54
+ if (normalised.length === 0) {
55
+ throw new Error(`${source}: binaryDirRoot must not be empty`);
56
+ }
57
+
58
+ // `..` segments would let a value escape the project root — reject
59
+ // rather than silently allow it. Single `.` segments are harmless and
60
+ // CMake handles them fine.
61
+ if (normalised.split('/').some((seg) => seg === '..')) {
62
+ throw new Error(`${source}: binaryDirRoot must not contain ".." segments`);
63
+ }
64
+
65
+ return normalised;
66
+ }
67
+
68
+ /**
69
+ * Resolve the effective binaryDirRoot from the two configured channels.
70
+ * Pure function — deliberately takes pre-read values rather than doing
71
+ * filesystem I/O so unit tests don't need temp dirs.
72
+ *
73
+ * @param {object} args
74
+ * @param {string|null|undefined} [args.cliBuildDir]
75
+ * Value of `--build-dir` from argv. `undefined`/`null` = not passed.
76
+ * @param {string|null|undefined} [args.localOverlayBinaryDirRoot]
77
+ * Value of `binaryDirRoot` read out of wyvrn.local.json (already
78
+ * parsed; this module does NOT re-read the file).
79
+ * @returns {string}
80
+ */
81
+ function resolveBinaryDirRoot({ cliBuildDir, localOverlayBinaryDirRoot } = {}) {
82
+ if (cliBuildDir !== undefined && cliBuildDir !== null) {
83
+ return validateBinaryDirRoot(cliBuildDir, '--build-dir');
84
+ }
85
+ if (localOverlayBinaryDirRoot !== undefined && localOverlayBinaryDirRoot !== null) {
86
+ return validateBinaryDirRoot(localOverlayBinaryDirRoot, 'wyvrn.local.json');
87
+ }
88
+ return DEFAULT_BINARY_DIR_ROOT;
89
+ }
90
+
91
+ module.exports = {
92
+ DEFAULT_BINARY_DIR_ROOT,
93
+ resolveBinaryDirRoot,
94
+ validateBinaryDirRoot,
95
+ };
@@ -1,196 +1,196 @@
1
- 'use strict';
2
-
3
- /**
4
- * Known-library cookbook for `wyvrnpm bootstrap`.
5
- *
6
- * Each entry captures the non-obvious tweaks a wyvrnpm recipe needs for a
7
- * popular upstream — the CMake cache variables that disable tests /
8
- * examples / docs so the install tree doesn't balloon, install gates the
9
- * upstream hides behind a flag (the `ZLIB_INSTALL=ON` class of gotcha,
10
- * see SKILL.md references/manifest-authoring.md §build), and any
11
- * transitive wyvrnpm deps the upstream already depends on.
12
- *
13
- * Keyed by a case-insensitive match on the repo tail. Matching is
14
- * restricted to exact tails so `wyvrnpm bootstrap` never surprises a
15
- * user whose fork name collides coincidentally — unmatched tails get
16
- * the safe-default recipe.
17
- *
18
- * Keep this file short and dumb. Rich per-library behaviour belongs in
19
- * the author's actual `wyvrn.json` — the cookbook is just the "everyone
20
- * hits these flags on day one" cheat sheet.
21
- *
22
- * @typedef {Object} CookbookEntry
23
- * @property {'HeaderOnlyLib'|'StaticLib'|'DynamicLib'} [kind]
24
- * Override `detect.js` when upstream's CMakeLists lies (e.g. fmt has
25
- * both a STATIC lib and an INTERFACE `fmt-header-only`).
26
- * @property {string[]} [configure]
27
- * `-DKEY=VAL` args threaded into build.configure. Preserves order so a
28
- * `-DBUILD_SHARED_LIBS=OFF` comes before a `-DXYZ_OPTION=...` override.
29
- * @property {Record<string,string>} [dependencies]
30
- * Known wyvrnpm deps — merged into manifest.dependencies. Versions
31
- * use `"latest"` so the user picks up whatever the team's registry
32
- * publishes; they can pin in review.
33
- * @property {string[]} [notes]
34
- * Human-readable reminders appended to the TODO report.
35
- */
36
-
37
- /** @type {Record<string, CookbookEntry>} */
38
- const KNOWN_LIBRARIES = Object.freeze({
39
- // ── Formatting / logging ─────────────────────────────────────────────
40
- fmt: {
41
- kind: 'StaticLib',
42
- configure: ['-DFMT_TEST=OFF', '-DFMT_DOC=OFF'],
43
- notes: [
44
- 'fmt also ships a `fmt-header-only` INTERFACE target. If you want ' +
45
- 'the header-only variant, declare kind=HeaderOnlyLib and add -DFMT_INSTALL=ON.',
46
- ],
47
- },
48
- spdlog: {
49
- kind: 'StaticLib',
50
- configure: [
51
- '-DSPDLOG_BUILD_TESTS=OFF',
52
- '-DSPDLOG_BUILD_EXAMPLE=OFF',
53
- '-DSPDLOG_INSTALL=ON',
54
- '-DSPDLOG_FMT_EXTERNAL=ON',
55
- ],
56
- dependencies: { fmt: 'latest' },
57
- notes: [
58
- 'SPDLOG_FMT_EXTERNAL=ON makes spdlog link against the wyvrnpm fmt package ' +
59
- 'instead of its bundled fork. Drop if you want the bundled copy.',
60
- ],
61
- },
62
-
63
- // ── JSON / config / serialization ────────────────────────────────────
64
- json: { kind: 'HeaderOnlyLib', configure: ['-DJSON_BuildTests=OFF'] },
65
- rapidjson: { kind: 'HeaderOnlyLib', configure: ['-DRAPIDJSON_BUILD_TESTS=OFF', '-DRAPIDJSON_BUILD_EXAMPLES=OFF', '-DRAPIDJSON_BUILD_DOC=OFF'] },
66
- jsoncpp: { kind: 'StaticLib', configure: ['-DJSONCPP_WITH_TESTS=OFF', '-DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF'] },
67
- 'yaml-cpp':{ kind: 'StaticLib', configure: ['-DYAML_CPP_BUILD_TESTS=OFF', '-DYAML_CPP_BUILD_TOOLS=OFF', '-DYAML_CPP_INSTALL=ON'] },
68
- pugixml: { kind: 'StaticLib', configure: ['-DPUGIXML_BUILD_TESTS=OFF'] },
69
- tinyxml2: { kind: 'StaticLib', configure: ['-Dtinyxml2_BUILD_TESTING=OFF'] },
70
- cereal: { kind: 'HeaderOnlyLib', configure: ['-DJUST_INSTALL_CEREAL=ON'] },
71
- 'msgpack-c': { kind: 'StaticLib', configure: ['-DMSGPACK_BUILD_TESTS=OFF', '-DMSGPACK_BUILD_EXAMPLES=OFF'] },
72
-
73
- // ── CLI / utilities ──────────────────────────────────────────────────
74
- cli11: { kind: 'HeaderOnlyLib', configure: ['-DCLI11_BUILD_TESTS=OFF', '-DCLI11_BUILD_EXAMPLES=OFF'] },
75
- cxxopts: { kind: 'HeaderOnlyLib', configure: ['-DCXXOPTS_BUILD_TESTS=OFF', '-DCXXOPTS_BUILD_EXAMPLES=OFF'] },
76
- magic_enum: { kind: 'HeaderOnlyLib', configure: ['-DMAGIC_ENUM_OPT_BUILD_EXAMPLES=OFF', '-DMAGIC_ENUM_OPT_BUILD_TESTS=OFF'] },
77
- date: { kind: 'StaticLib', configure: ['-DBUILD_TZ_LIB=ON', '-DUSE_SYSTEM_TZ_DB=OFF'] },
78
- utfcpp: { kind: 'HeaderOnlyLib', configure: ['-DUTF8_TESTS=OFF', '-DUTF8_SAMPLES=OFF'] },
79
-
80
- // ── Testing / benchmarking ──────────────────────────────────────────
81
- catch2: { kind: 'StaticLib', configure: ['-DCATCH_INSTALL_DOCS=OFF', '-DCATCH_BUILD_TESTING=OFF'] },
82
- doctest: { kind: 'HeaderOnlyLib', configure: ['-DDOCTEST_WITH_TESTS=OFF', '-DDOCTEST_WITH_MAIN_IN_STATIC_LIB=OFF'] },
83
- benchmark: {
84
- kind: 'StaticLib',
85
- configure: ['-DBENCHMARK_ENABLE_TESTING=OFF', '-DBENCHMARK_ENABLE_GTEST_TESTS=OFF'],
86
- notes: ['google/benchmark — only one of several projects named "benchmark"; confirm the repo URL.'],
87
- },
88
-
89
- // ── Compression ──────────────────────────────────────────────────────
90
- zlib: {
91
- kind: 'StaticLib',
92
- configure: ['-DZLIB_BUILD_EXAMPLES=OFF'],
93
- notes: [
94
- 'zlib is the textbook example for an `options.shared` toggle — see ' +
95
- 'references/worked-example-zlib.md. Consider declaring it before you publish.',
96
- ],
97
- },
98
- lz4: { kind: 'StaticLib', configure: ['-DLZ4_BUILD_LEGACY_LZ4C=OFF', '-DLZ4_BUILD_CLI=OFF', '-DBUILD_SHARED_LIBS=OFF'] },
99
- snappy: { kind: 'StaticLib', configure: ['-DSNAPPY_BUILD_TESTS=OFF', '-DSNAPPY_BUILD_BENCHMARKS=OFF'] },
100
- brotli: { kind: 'StaticLib', configure: ['-DBROTLI_DISABLE_TESTS=ON'] },
101
- bzip2: {
102
- notes: [
103
- 'bzip2 uses autotools (no CMakeLists.txt). Either ship a wrapper CMakeLists.txt ' +
104
- 'in your fork or prebuild + publish as a binary-only artefact.',
105
- ],
106
- },
107
-
108
- // ── Networking / HTTP ────────────────────────────────────────────────
109
- 'cpp-httplib': { kind: 'HeaderOnlyLib', configure: ['-DHTTPLIB_TEST=OFF'] },
110
- cpr: {
111
- kind: 'StaticLib',
112
- configure: ['-DCPR_BUILD_TESTS=OFF', '-DCPR_USE_SYSTEM_CURL=ON'],
113
- notes: ['cpr needs libcurl — add a wyvrnpm `libcurl` dep if your registry publishes one, or rely on system curl.'],
114
- },
115
- websocketpp: {
116
- kind: 'HeaderOnlyLib',
117
- notes: ['websocketpp requires boost::asio or standalone Asio — add the appropriate dep.'],
118
- },
119
- cppzmq: {
120
- kind: 'HeaderOnlyLib',
121
- notes: ['cppzmq needs libzmq — add a wyvrnpm dep for libzmq before publish.'],
122
- },
123
- hiredis: { kind: 'StaticLib', configure: ['-DDISABLE_TESTS=ON', '-DENABLE_EXAMPLES=OFF'] },
124
- 'redis-plus-plus': {
125
- kind: 'StaticLib',
126
- configure: ['-DREDIS_PLUS_PLUS_BUILD_TEST=OFF', '-DREDIS_PLUS_PLUS_USE_TLS=OFF'],
127
- dependencies: { hiredis: 'latest' },
128
- },
129
-
130
- // ── Concurrency ──────────────────────────────────────────────────────
131
- concurrentqueue: { kind: 'HeaderOnlyLib' },
132
- readerwriterqueue: { kind: 'HeaderOnlyLib' },
133
-
134
- // ── Graphics / image ─────────────────────────────────────────────────
135
- stb: {
136
- kind: 'HeaderOnlyLib',
137
- notes: [
138
- 'stb is a header drop — no CMakeLists.txt upstream. Ship a small wrapper ' +
139
- 'CMakeLists.txt in your fork that declares an INTERFACE target with ' +
140
- 'target_include_directories(... INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) and install() rules.',
141
- ],
142
- },
143
- glm: { kind: 'HeaderOnlyLib', configure: ['-DGLM_TEST_ENABLE=OFF', '-DGLM_BUILD_LIBRARY=OFF'] },
144
- imgui: {
145
- notes: [
146
- 'imgui ships no CMakeLists.txt. Ship a wrapper CMakeLists.txt in your fork ' +
147
- 'that picks the backends you need (OpenGL3/Win32/DX11/etc) and declares a ' +
148
- 'StaticLib with them.',
149
- ],
150
- },
151
- nuklear: {
152
- kind: 'HeaderOnlyLib',
153
- notes: [
154
- 'Nuklear is a single-header drop. Same pattern as stb: ship an INTERFACE ' +
155
- 'wrapper CMakeLists.txt in your fork.',
156
- ],
157
- },
158
-
159
- // ── Database ─────────────────────────────────────────────────────────
160
- sqlitecpp: { kind: 'StaticLib', configure: ['-DSQLITECPP_RUN_CPPLINT=OFF', '-DSQLITECPP_RUN_CPPCHECK=OFF', '-DSQLITECPP_BUILD_TESTS=OFF', '-DSQLITECPP_BUILD_EXAMPLES=OFF'] },
161
-
162
- // ── Crypto ───────────────────────────────────────────────────────────
163
- libsodium: {
164
- notes: [
165
- 'libsodium uses autotools (configure.ac, Makefile.am). wyvrnpm source-build ' +
166
- 'supports cmake only — ship a wrapper CMakeLists.txt in your fork, or ' +
167
- 'prebuild + publish as a binary-only artefact.',
168
- ],
169
- },
170
-
171
- // ── Text / regex ─────────────────────────────────────────────────────
172
- re2: { kind: 'StaticLib', configure: ['-DRE2_BUILD_TESTING=OFF'] },
173
- });
174
-
175
- /**
176
- * Look up cookbook hints for a given package tail (e.g. "fmt", "zlib").
177
- * Case-insensitive; returns a defensive copy so callers can merge freely.
178
- *
179
- * @param {string} key
180
- * @returns {CookbookEntry | null}
181
- */
182
- function lookupCookbook(key) {
183
- if (typeof key !== 'string') return null;
184
- const normal = key.trim().toLowerCase();
185
- if (!normal) return null;
186
- const entry = KNOWN_LIBRARIES[normal];
187
- if (!entry) return null;
188
- return {
189
- ...entry,
190
- configure: entry.configure ? [...entry.configure] : undefined,
191
- dependencies: entry.dependencies ? { ...entry.dependencies } : undefined,
192
- notes: entry.notes ? [...entry.notes] : undefined,
193
- };
194
- }
195
-
196
- module.exports = { KNOWN_LIBRARIES, lookupCookbook };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Known-library cookbook for `wyvrnpm bootstrap`.
5
+ *
6
+ * Each entry captures the non-obvious tweaks a wyvrnpm recipe needs for a
7
+ * popular upstream — the CMake cache variables that disable tests /
8
+ * examples / docs so the install tree doesn't balloon, install gates the
9
+ * upstream hides behind a flag (the `ZLIB_INSTALL=ON` class of gotcha,
10
+ * see SKILL.md references/manifest-authoring.md §build), and any
11
+ * transitive wyvrnpm deps the upstream already depends on.
12
+ *
13
+ * Keyed by a case-insensitive match on the repo tail. Matching is
14
+ * restricted to exact tails so `wyvrnpm bootstrap` never surprises a
15
+ * user whose fork name collides coincidentally — unmatched tails get
16
+ * the safe-default recipe.
17
+ *
18
+ * Keep this file short and dumb. Rich per-library behaviour belongs in
19
+ * the author's actual `wyvrn.json` — the cookbook is just the "everyone
20
+ * hits these flags on day one" cheat sheet.
21
+ *
22
+ * @typedef {Object} CookbookEntry
23
+ * @property {'HeaderOnlyLib'|'StaticLib'|'DynamicLib'} [kind]
24
+ * Override `detect.js` when upstream's CMakeLists lies (e.g. fmt has
25
+ * both a STATIC lib and an INTERFACE `fmt-header-only`).
26
+ * @property {string[]} [configure]
27
+ * `-DKEY=VAL` args threaded into build.configure. Preserves order so a
28
+ * `-DBUILD_SHARED_LIBS=OFF` comes before a `-DXYZ_OPTION=...` override.
29
+ * @property {Record<string,string>} [dependencies]
30
+ * Known wyvrnpm deps — merged into manifest.dependencies. Versions
31
+ * use `"latest"` so the user picks up whatever the team's registry
32
+ * publishes; they can pin in review.
33
+ * @property {string[]} [notes]
34
+ * Human-readable reminders appended to the TODO report.
35
+ */
36
+
37
+ /** @type {Record<string, CookbookEntry>} */
38
+ const KNOWN_LIBRARIES = Object.freeze({
39
+ // ── Formatting / logging ─────────────────────────────────────────────
40
+ fmt: {
41
+ kind: 'StaticLib',
42
+ configure: ['-DFMT_TEST=OFF', '-DFMT_DOC=OFF'],
43
+ notes: [
44
+ 'fmt also ships a `fmt-header-only` INTERFACE target. If you want ' +
45
+ 'the header-only variant, declare kind=HeaderOnlyLib and add -DFMT_INSTALL=ON.',
46
+ ],
47
+ },
48
+ spdlog: {
49
+ kind: 'StaticLib',
50
+ configure: [
51
+ '-DSPDLOG_BUILD_TESTS=OFF',
52
+ '-DSPDLOG_BUILD_EXAMPLE=OFF',
53
+ '-DSPDLOG_INSTALL=ON',
54
+ '-DSPDLOG_FMT_EXTERNAL=ON',
55
+ ],
56
+ dependencies: { fmt: 'latest' },
57
+ notes: [
58
+ 'SPDLOG_FMT_EXTERNAL=ON makes spdlog link against the wyvrnpm fmt package ' +
59
+ 'instead of its bundled fork. Drop if you want the bundled copy.',
60
+ ],
61
+ },
62
+
63
+ // ── JSON / config / serialization ────────────────────────────────────
64
+ json: { kind: 'HeaderOnlyLib', configure: ['-DJSON_BuildTests=OFF'] },
65
+ rapidjson: { kind: 'HeaderOnlyLib', configure: ['-DRAPIDJSON_BUILD_TESTS=OFF', '-DRAPIDJSON_BUILD_EXAMPLES=OFF', '-DRAPIDJSON_BUILD_DOC=OFF'] },
66
+ jsoncpp: { kind: 'StaticLib', configure: ['-DJSONCPP_WITH_TESTS=OFF', '-DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF'] },
67
+ 'yaml-cpp':{ kind: 'StaticLib', configure: ['-DYAML_CPP_BUILD_TESTS=OFF', '-DYAML_CPP_BUILD_TOOLS=OFF', '-DYAML_CPP_INSTALL=ON'] },
68
+ pugixml: { kind: 'StaticLib', configure: ['-DPUGIXML_BUILD_TESTS=OFF'] },
69
+ tinyxml2: { kind: 'StaticLib', configure: ['-Dtinyxml2_BUILD_TESTING=OFF'] },
70
+ cereal: { kind: 'HeaderOnlyLib', configure: ['-DJUST_INSTALL_CEREAL=ON'] },
71
+ 'msgpack-c': { kind: 'StaticLib', configure: ['-DMSGPACK_BUILD_TESTS=OFF', '-DMSGPACK_BUILD_EXAMPLES=OFF'] },
72
+
73
+ // ── CLI / utilities ──────────────────────────────────────────────────
74
+ cli11: { kind: 'HeaderOnlyLib', configure: ['-DCLI11_BUILD_TESTS=OFF', '-DCLI11_BUILD_EXAMPLES=OFF'] },
75
+ cxxopts: { kind: 'HeaderOnlyLib', configure: ['-DCXXOPTS_BUILD_TESTS=OFF', '-DCXXOPTS_BUILD_EXAMPLES=OFF'] },
76
+ magic_enum: { kind: 'HeaderOnlyLib', configure: ['-DMAGIC_ENUM_OPT_BUILD_EXAMPLES=OFF', '-DMAGIC_ENUM_OPT_BUILD_TESTS=OFF'] },
77
+ date: { kind: 'StaticLib', configure: ['-DBUILD_TZ_LIB=ON', '-DUSE_SYSTEM_TZ_DB=OFF'] },
78
+ utfcpp: { kind: 'HeaderOnlyLib', configure: ['-DUTF8_TESTS=OFF', '-DUTF8_SAMPLES=OFF'] },
79
+
80
+ // ── Testing / benchmarking ──────────────────────────────────────────
81
+ catch2: { kind: 'StaticLib', configure: ['-DCATCH_INSTALL_DOCS=OFF', '-DCATCH_BUILD_TESTING=OFF'] },
82
+ doctest: { kind: 'HeaderOnlyLib', configure: ['-DDOCTEST_WITH_TESTS=OFF', '-DDOCTEST_WITH_MAIN_IN_STATIC_LIB=OFF'] },
83
+ benchmark: {
84
+ kind: 'StaticLib',
85
+ configure: ['-DBENCHMARK_ENABLE_TESTING=OFF', '-DBENCHMARK_ENABLE_GTEST_TESTS=OFF'],
86
+ notes: ['google/benchmark — only one of several projects named "benchmark"; confirm the repo URL.'],
87
+ },
88
+
89
+ // ── Compression ──────────────────────────────────────────────────────
90
+ zlib: {
91
+ kind: 'StaticLib',
92
+ configure: ['-DZLIB_BUILD_EXAMPLES=OFF'],
93
+ notes: [
94
+ 'zlib is the textbook example for an `options.shared` toggle — see ' +
95
+ 'references/worked-example-zlib.md. Consider declaring it before you publish.',
96
+ ],
97
+ },
98
+ lz4: { kind: 'StaticLib', configure: ['-DLZ4_BUILD_LEGACY_LZ4C=OFF', '-DLZ4_BUILD_CLI=OFF', '-DBUILD_SHARED_LIBS=OFF'] },
99
+ snappy: { kind: 'StaticLib', configure: ['-DSNAPPY_BUILD_TESTS=OFF', '-DSNAPPY_BUILD_BENCHMARKS=OFF'] },
100
+ brotli: { kind: 'StaticLib', configure: ['-DBROTLI_DISABLE_TESTS=ON'] },
101
+ bzip2: {
102
+ notes: [
103
+ 'bzip2 uses autotools (no CMakeLists.txt). Either ship a wrapper CMakeLists.txt ' +
104
+ 'in your fork or prebuild + publish as a binary-only artefact.',
105
+ ],
106
+ },
107
+
108
+ // ── Networking / HTTP ────────────────────────────────────────────────
109
+ 'cpp-httplib': { kind: 'HeaderOnlyLib', configure: ['-DHTTPLIB_TEST=OFF'] },
110
+ cpr: {
111
+ kind: 'StaticLib',
112
+ configure: ['-DCPR_BUILD_TESTS=OFF', '-DCPR_USE_SYSTEM_CURL=ON'],
113
+ notes: ['cpr needs libcurl — add a wyvrnpm `libcurl` dep if your registry publishes one, or rely on system curl.'],
114
+ },
115
+ websocketpp: {
116
+ kind: 'HeaderOnlyLib',
117
+ notes: ['websocketpp requires boost::asio or standalone Asio — add the appropriate dep.'],
118
+ },
119
+ cppzmq: {
120
+ kind: 'HeaderOnlyLib',
121
+ notes: ['cppzmq needs libzmq — add a wyvrnpm dep for libzmq before publish.'],
122
+ },
123
+ hiredis: { kind: 'StaticLib', configure: ['-DDISABLE_TESTS=ON', '-DENABLE_EXAMPLES=OFF'] },
124
+ 'redis-plus-plus': {
125
+ kind: 'StaticLib',
126
+ configure: ['-DREDIS_PLUS_PLUS_BUILD_TEST=OFF', '-DREDIS_PLUS_PLUS_USE_TLS=OFF'],
127
+ dependencies: { hiredis: 'latest' },
128
+ },
129
+
130
+ // ── Concurrency ──────────────────────────────────────────────────────
131
+ concurrentqueue: { kind: 'HeaderOnlyLib' },
132
+ readerwriterqueue: { kind: 'HeaderOnlyLib' },
133
+
134
+ // ── Graphics / image ─────────────────────────────────────────────────
135
+ stb: {
136
+ kind: 'HeaderOnlyLib',
137
+ notes: [
138
+ 'stb is a header drop — no CMakeLists.txt upstream. Ship a small wrapper ' +
139
+ 'CMakeLists.txt in your fork that declares an INTERFACE target with ' +
140
+ 'target_include_directories(... INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) and install() rules.',
141
+ ],
142
+ },
143
+ glm: { kind: 'HeaderOnlyLib', configure: ['-DGLM_TEST_ENABLE=OFF', '-DGLM_BUILD_LIBRARY=OFF'] },
144
+ imgui: {
145
+ notes: [
146
+ 'imgui ships no CMakeLists.txt. Ship a wrapper CMakeLists.txt in your fork ' +
147
+ 'that picks the backends you need (OpenGL3/Win32/DX11/etc) and declares a ' +
148
+ 'StaticLib with them.',
149
+ ],
150
+ },
151
+ nuklear: {
152
+ kind: 'HeaderOnlyLib',
153
+ notes: [
154
+ 'Nuklear is a single-header drop. Same pattern as stb: ship an INTERFACE ' +
155
+ 'wrapper CMakeLists.txt in your fork.',
156
+ ],
157
+ },
158
+
159
+ // ── Database ─────────────────────────────────────────────────────────
160
+ sqlitecpp: { kind: 'StaticLib', configure: ['-DSQLITECPP_RUN_CPPLINT=OFF', '-DSQLITECPP_RUN_CPPCHECK=OFF', '-DSQLITECPP_BUILD_TESTS=OFF', '-DSQLITECPP_BUILD_EXAMPLES=OFF'] },
161
+
162
+ // ── Crypto ───────────────────────────────────────────────────────────
163
+ libsodium: {
164
+ notes: [
165
+ 'libsodium uses autotools (configure.ac, Makefile.am). wyvrnpm source-build ' +
166
+ 'supports cmake only — ship a wrapper CMakeLists.txt in your fork, or ' +
167
+ 'prebuild + publish as a binary-only artefact.',
168
+ ],
169
+ },
170
+
171
+ // ── Text / regex ─────────────────────────────────────────────────────
172
+ re2: { kind: 'StaticLib', configure: ['-DRE2_BUILD_TESTING=OFF'] },
173
+ });
174
+
175
+ /**
176
+ * Look up cookbook hints for a given package tail (e.g. "fmt", "zlib").
177
+ * Case-insensitive; returns a defensive copy so callers can merge freely.
178
+ *
179
+ * @param {string} key
180
+ * @returns {CookbookEntry | null}
181
+ */
182
+ function lookupCookbook(key) {
183
+ if (typeof key !== 'string') return null;
184
+ const normal = key.trim().toLowerCase();
185
+ if (!normal) return null;
186
+ const entry = KNOWN_LIBRARIES[normal];
187
+ if (!entry) return null;
188
+ return {
189
+ ...entry,
190
+ configure: entry.configure ? [...entry.configure] : undefined,
191
+ dependencies: entry.dependencies ? { ...entry.dependencies } : undefined,
192
+ notes: entry.notes ? [...entry.notes] : undefined,
193
+ };
194
+ }
195
+
196
+ module.exports = { KNOWN_LIBRARIES, lookupCookbook };