@mjasnikovs/pi-task 0.40.10 → 0.40.11
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/workers/docs-ecosystems.d.ts +8 -11
- package/dist/workers/docs-ecosystems.js +14 -5
- package/dist/workers/docs-index.js +2 -2
- package/dist/workers/eco-cargo.d.ts +9 -16
- package/dist/workers/eco-cargo.js +62 -8
- package/dist/workers/eco-hackage.d.ts +3 -3
- package/dist/workers/eco-hackage.js +3 -3
- package/package.json +1 -1
|
@@ -87,11 +87,15 @@ export interface EcosystemProfile {
|
|
|
87
87
|
*/
|
|
88
88
|
exportGap?: (root: string) => ExportGap;
|
|
89
89
|
/**
|
|
90
|
-
* Source of
|
|
91
|
-
*
|
|
92
|
-
*
|
|
90
|
+
* Source of everything this row contributes to a chunk's CONTENT — `surface`,
|
|
91
|
+
* `exportGap`, and every function and regex they delegate to.
|
|
92
|
+
*
|
|
93
|
+
* Required, and not derived from `String(surface)`, because that has hidden a
|
|
94
|
+
* real fix three times: `surface` here is the wrapper
|
|
95
|
+
* `content => rustSurface(content)`, which shows none of `rustSurface`, and
|
|
96
|
+
* neither gap rule's helpers appear in its entry point either.
|
|
93
97
|
*/
|
|
94
|
-
|
|
98
|
+
contentFingerprint: () => string;
|
|
95
99
|
/** The registry's own newest version, for grounding an answer in the present. */
|
|
96
100
|
latest: (name: string, io: EcosystemIo) => Promise<NpmVersionInfo | null>;
|
|
97
101
|
/** True for a file that carries the package's public API surface. */
|
|
@@ -144,13 +148,6 @@ export interface NpmProfileHooks {
|
|
|
144
148
|
resolvePackage?: typeof resolvePackage;
|
|
145
149
|
npmVersionLookup?: typeof npmVersionLookup;
|
|
146
150
|
}
|
|
147
|
-
/**
|
|
148
|
-
* The npm row, with the pieces a caller may have replaced left as parameters.
|
|
149
|
-
*
|
|
150
|
-
* `docsRaw` already takes `resolvePackage` and `npmVersionLookup` as injection
|
|
151
|
-
* hooks, and those hooks must keep reaching the resolution they are injected
|
|
152
|
-
* for. A per-call row carries them; {@link ECOSYSTEMS} holds the plain one.
|
|
153
|
-
*/
|
|
154
151
|
export declare function npmProfile(hooks?: NpmProfileHooks): EcosystemProfile;
|
|
155
152
|
/**
|
|
156
153
|
* The package.json manifest, not the lockfile: a lockfile is rewritten by
|
|
@@ -21,8 +21,8 @@ import { runAutoInstall, findDeclaredRange, extractParentPackage, resolveTypeSou
|
|
|
21
21
|
import { resolvePackage, isDtsFile, isValidModuleName } from './docs-resolve.js';
|
|
22
22
|
import { DECL_SPLIT_RE } from './docs-chunk.js';
|
|
23
23
|
import { npmVersionLookup } from './npm-version.js';
|
|
24
|
-
import { resolveCrate, cratesLatest, crateTarballUrl, crateOf, isValidCrateName, isRustFile, lockedVersion, rustSurface, cargoProjectName, childDirs, lockedDeps, manifestCrates, cargoExportGap,
|
|
25
|
-
import { resolveHackage, hackageLatest, hackageVersion, hackageTarballUrl, hackageExtractDir, hackageProjectName, supplementCandidates, hackageExportGap,
|
|
24
|
+
import { resolveCrate, cratesLatest, crateTarballUrl, crateOf, isValidCrateName, isRustFile, lockedVersion, rustSurface, cargoProjectName, childDirs, lockedDeps, manifestCrates, cargoExportGap, cargoContentFingerprint, cargoSupplementCandidates, CARGO_DECL_SPLIT_RE } from './eco-cargo.js';
|
|
25
|
+
import { resolveHackage, hackageLatest, hackageVersion, hackageTarballUrl, hackageExtractDir, hackageProjectName, supplementCandidates, hackageExportGap, hackageContentFingerprint, findCabalTarball, cachedVersions, resolvedVersions, manifestPackages, isValidHackageName, isHaskellFile, haskellSurface, HACKAGE_DECL_SPLIT_RE, HACKAGE_SKIP_DIRS } from './eco-hackage.js';
|
|
26
26
|
import { runChild } from '../shared/child-process.js';
|
|
27
27
|
/**
|
|
28
28
|
* Is any of `names` present at `cwd` or above it?
|
|
@@ -101,6 +101,9 @@ function defaultCabalPackageDirs() {
|
|
|
101
101
|
* hooks, and those hooks must keep reaching the resolution they are injected
|
|
102
102
|
* for. A per-call row carries them; {@link ECOSYSTEMS} holds the plain one.
|
|
103
103
|
*/
|
|
104
|
+
/** A `.d.ts` is already declarations only, so npm's extractor is the identity.
|
|
105
|
+
* Named rather than inline so `contentFingerprint` can point at it. */
|
|
106
|
+
const npmSurface = (content) => content;
|
|
104
107
|
export function npmProfile(hooks = {}) {
|
|
105
108
|
const resolve = hooks.resolvePackage ?? resolvePackage;
|
|
106
109
|
const versionLookup = hooks.npmVersionLookup ?? npmVersionLookup;
|
|
@@ -126,7 +129,10 @@ export function npmProfile(hooks = {}) {
|
|
|
126
129
|
afterResolve: (pkg, requested, cwd, io) => resolveTypeSourceForDocs(pkg, requested, cwd, io.spawn, resolve, io.signal),
|
|
127
130
|
latest: (name, io) => versionLookup(name, io.signal === undefined ? {} : { signal: io.signal }),
|
|
128
131
|
isSurfaceFile: isDtsFile,
|
|
129
|
-
surface:
|
|
132
|
+
surface: npmSurface,
|
|
133
|
+
// No gap rule, and a `.d.ts` IS the surface, so there is nothing below the
|
|
134
|
+
// identity for a fingerprint to miss.
|
|
135
|
+
contentFingerprint: () => String(npmSurface),
|
|
130
136
|
declSplitRe: DECL_SPLIT_RE,
|
|
131
137
|
typeKeywords: ['interface', 'type', 'class', 'enum'],
|
|
132
138
|
commentPrefix: '//',
|
|
@@ -299,9 +305,12 @@ const cargoProfile = {
|
|
|
299
305
|
return out;
|
|
300
306
|
},
|
|
301
307
|
exportGap: cargoExportGap,
|
|
302
|
-
|
|
308
|
+
contentFingerprint: cargoContentFingerprint,
|
|
303
309
|
latest: (name, io) => cratesLatest(name, io.fetch, io.signal),
|
|
304
310
|
isSurfaceFile: isRustFile,
|
|
311
|
+
// Wrapped, not passed by reference: `rustSurface` takes two more optional
|
|
312
|
+
// arguments, and a bare reference would let a `.map(profile.surface)` pass an
|
|
313
|
+
// index as `insideTrait`. `contentFingerprint` is what covers its source.
|
|
305
314
|
surface: content => rustSurface(content),
|
|
306
315
|
declSplitRe: CARGO_DECL_SPLIT_RE,
|
|
307
316
|
typeKeywords: ['struct', 'trait', 'enum', 'type', 'union'],
|
|
@@ -415,7 +424,7 @@ const hackageProfile = {
|
|
|
415
424
|
return out;
|
|
416
425
|
},
|
|
417
426
|
exportGap: hackageExportGap,
|
|
418
|
-
|
|
427
|
+
contentFingerprint: hackageContentFingerprint,
|
|
419
428
|
latest: (name, io) => hackageLatest(name, io.fetch, io.signal),
|
|
420
429
|
isSurfaceFile: isHaskellFile,
|
|
421
430
|
surface: haskellSurface,
|
|
@@ -52,7 +52,8 @@ function computeContentHash(pkg, profile, supplements = []) {
|
|
|
52
52
|
// leaves a package cached whenever a fix moves some OTHER module — the
|
|
53
53
|
// wrapped `instance` head is in aeson's `Types/FromJSON.hs`, never its entry
|
|
54
54
|
// — and nothing surfaced the duplicate drop in `ingestBody` at all.
|
|
55
|
-
hash.update(Buffer.from(`${String(profile.surface)}\u0000${
|
|
55
|
+
hash.update(Buffer.from(`${String(profile.surface)}\u0000${profile.contentFingerprint()}`
|
|
56
|
+
+ `\u0000${String(ingestBody)}`, 'utf8'));
|
|
56
57
|
hash.update(ZERO_SEP);
|
|
57
58
|
// Which packages were folded in, so gaining or losing one re-indexes — and the
|
|
58
59
|
// rule that decides WHICH of their chunks are kept, by source. Hashing the set
|
|
@@ -60,7 +61,6 @@ function computeContentHash(pkg, profile, supplements = []) {
|
|
|
60
61
|
// the chunks the old rule chose.
|
|
61
62
|
hash.update(Buffer.from(supplements.map(s => `${s.name}@${s.version}`).join('\u0000'), 'utf8'));
|
|
62
63
|
hash.update(ZERO_SEP);
|
|
63
|
-
hash.update(Buffer.from(profile.exportGapFingerprint?.() ?? String(profile.exportGap ?? ''), 'utf8'));
|
|
64
64
|
hash.update(ZERO_SEP);
|
|
65
65
|
if (pkg.entry && fs.existsSync(pkg.entry)) {
|
|
66
66
|
try {
|
|
@@ -99,16 +99,6 @@ interface Item {
|
|
|
99
99
|
* finds the end of the item it is in.
|
|
100
100
|
*/
|
|
101
101
|
export declare function splitRustItems(src: string): Item[];
|
|
102
|
-
/**
|
|
103
|
-
* Reduce Rust source to its public API surface.
|
|
104
|
-
*
|
|
105
|
-
* Function bodies go — they are the bulk of the file and answer no question the
|
|
106
|
-
* docs tool is asked. Everything a caller can name stays: the item head, its doc
|
|
107
|
-
* comment, its attributes, and for a struct or enum its fields and variants.
|
|
108
|
-
*
|
|
109
|
-
* Inside a `trait` every member is public by definition, so the `pub` test is
|
|
110
|
-
* suspended there; anywhere else a bare or `pub(crate)` item is dropped.
|
|
111
|
-
*/
|
|
112
102
|
export declare function rustSurface(src: string, insideTrait?: boolean, topLevel?: boolean): string;
|
|
113
103
|
export declare function isRustFile(name: string): boolean;
|
|
114
104
|
/** The `[package] name` of a cargo project, for labelling its own source. */
|
|
@@ -134,14 +124,17 @@ export declare function manifestCrates(cwd: string): Set<string> | undefined;
|
|
|
134
124
|
*/
|
|
135
125
|
export declare function cargoExportGap(root: string): ExportGap;
|
|
136
126
|
/**
|
|
137
|
-
* Source of
|
|
127
|
+
* Source of everything this row contributes to a chunk's CONTENT — the surface
|
|
128
|
+
* extractor, the gap rule, and every function and regex they delegate to.
|
|
138
129
|
*
|
|
139
|
-
* `String(
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
130
|
+
* `String(fn)` covers only a top level, and three separate bugs have now hidden
|
|
131
|
+
* one level below it: the chunker (which `chunkerFingerprint` closes), the gap
|
|
132
|
+
* rule's helpers, and `surface` itself, declared as the wrapper
|
|
133
|
+
* `content => rustSurface(content)` which shows none of `rustSurface`. A fix that
|
|
134
|
+
* does not move this leaves every cached crate holding the chunks the old rule
|
|
135
|
+
* chose.
|
|
143
136
|
*/
|
|
144
|
-
export declare function
|
|
137
|
+
export declare function cargoContentFingerprint(): string;
|
|
145
138
|
/**
|
|
146
139
|
* Which declared dependencies may be opened to fill the gap.
|
|
147
140
|
*
|
|
@@ -631,6 +631,37 @@ const LIST_KINDS = new Set(['use']);
|
|
|
631
631
|
* Inside a `trait` every member is public by definition, so the `pub` test is
|
|
632
632
|
* suspended there; anywhere else a bare or `pub(crate)` item is dropped.
|
|
633
633
|
*/
|
|
634
|
+
/** A `#name` interpolation. Rust item syntax has none; a `quote!` template is
|
|
635
|
+
* nothing but. Comments come out first — a doctest hides lines with `# use …`. */
|
|
636
|
+
const INTERPOLATION = /#[A-Za-z_(]/;
|
|
637
|
+
function withoutComments(body) {
|
|
638
|
+
return body
|
|
639
|
+
.split('\n')
|
|
640
|
+
.map(l => (/^\s*(?:\/\/|\*)/.test(l) ? '' : l.replace(/\/\/.*$/, '')))
|
|
641
|
+
.join('\n');
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* The body of a `name! { … }` block that WRAPS items, or null.
|
|
645
|
+
*
|
|
646
|
+
* tokio declares `pub struct TcpListener` inside `cfg_net! { … }`, and every
|
|
647
|
+
* async crate does the same: 818 public items across twenty-two crates sit inside
|
|
648
|
+
* such a block, 441 of them tokio's. Treating the invocation as one opaque item
|
|
649
|
+
* dropped all of them, `TcpListener` — a ground-truth symbol of the live test —
|
|
650
|
+
* included.
|
|
651
|
+
*
|
|
652
|
+
* The guard is what the body IS, never which macro it is. A `quote!` body is a
|
|
653
|
+
* token template, and the same measurement found zero public items inside an
|
|
654
|
+
* interpolating body, so the two populations do not overlap.
|
|
655
|
+
*/
|
|
656
|
+
function macroWrappedItems(item) {
|
|
657
|
+
if (item.body === null)
|
|
658
|
+
return null;
|
|
659
|
+
if (!/^[a-z_][a-z0-9_]*!$/.test(item.head.trim()))
|
|
660
|
+
return null;
|
|
661
|
+
if (INTERPOLATION.test(withoutComments(item.body)))
|
|
662
|
+
return null;
|
|
663
|
+
return item.body;
|
|
664
|
+
}
|
|
634
665
|
export function rustSurface(src, insideTrait = false, topLevel = true) {
|
|
635
666
|
const out = [];
|
|
636
667
|
const items = splitRustItems(src);
|
|
@@ -645,8 +676,12 @@ export function rustSurface(src, insideTrait = false, topLevel = true) {
|
|
|
645
676
|
out.push(moduleDoc);
|
|
646
677
|
for (const item of items) {
|
|
647
678
|
const headMatch = ITEM_HEAD_RE.exec(item.head);
|
|
648
|
-
if (!headMatch)
|
|
679
|
+
if (!headMatch) {
|
|
680
|
+
const wrapped = macroWrappedItems(item);
|
|
681
|
+
if (wrapped !== null)
|
|
682
|
+
out.push(rustSurface(wrapped, insideTrait, false));
|
|
649
683
|
continue;
|
|
684
|
+
}
|
|
650
685
|
const kind = headMatch[1];
|
|
651
686
|
// A `#[macro_export]` macro IS the crate's API — `anyhow::bail!`,
|
|
652
687
|
// `serde_json::json!`. Dropping every macro answered "no such thing"
|
|
@@ -1002,19 +1037,38 @@ export function cargoExportGap(root) {
|
|
|
1002
1037
|
};
|
|
1003
1038
|
}
|
|
1004
1039
|
/**
|
|
1005
|
-
* Source of
|
|
1040
|
+
* Source of everything this row contributes to a chunk's CONTENT — the surface
|
|
1041
|
+
* extractor, the gap rule, and every function and regex they delegate to.
|
|
1006
1042
|
*
|
|
1007
|
-
* `String(
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1043
|
+
* `String(fn)` covers only a top level, and three separate bugs have now hidden
|
|
1044
|
+
* one level below it: the chunker (which `chunkerFingerprint` closes), the gap
|
|
1045
|
+
* rule's helpers, and `surface` itself, declared as the wrapper
|
|
1046
|
+
* `content => rustSurface(content)` which shows none of `rustSurface`. A fix that
|
|
1047
|
+
* does not move this leaves every cached crate holding the chunks the old rule
|
|
1048
|
+
* chose.
|
|
1011
1049
|
*/
|
|
1012
|
-
export function
|
|
1013
|
-
return [
|
|
1050
|
+
export function cargoContentFingerprint() {
|
|
1051
|
+
return [
|
|
1052
|
+
rustSurface,
|
|
1053
|
+
splitRustItems,
|
|
1054
|
+
macroWrappedItems,
|
|
1055
|
+
withoutComments,
|
|
1056
|
+
keptPreamble,
|
|
1057
|
+
privateTypeNames,
|
|
1058
|
+
implTarget,
|
|
1059
|
+
fieldsOf,
|
|
1060
|
+
cargoExportGap,
|
|
1061
|
+
runtimeDeps,
|
|
1062
|
+
useTargets,
|
|
1063
|
+
rustSources,
|
|
1064
|
+
moduleOfPath
|
|
1065
|
+
]
|
|
1014
1066
|
.map(String)
|
|
1015
1067
|
.concat([
|
|
1016
1068
|
PUB_USE_RE.source,
|
|
1017
1069
|
RUST_DECL_RE.source,
|
|
1070
|
+
ITEM_HEAD_RE.source,
|
|
1071
|
+
INTERPOLATION.source,
|
|
1018
1072
|
CARGO_SKIP_DIRS.join(','),
|
|
1019
1073
|
[...OWN_PATH_ROOTS].join(',')
|
|
1020
1074
|
])
|
|
@@ -103,9 +103,9 @@ export declare function hackageProjectName(cwd: string): string | null;
|
|
|
103
103
|
export declare function manifestPackages(cwd: string): Set<string> | undefined;
|
|
104
104
|
/** Every name the extracted surface declares: signatures, heads, constructors, fields. */
|
|
105
105
|
export declare function declaredInSurface(surface: string): Set<string>;
|
|
106
|
-
/** Source of
|
|
107
|
-
* `
|
|
108
|
-
export declare function
|
|
106
|
+
/** Source of everything this row contributes to a chunk's content — see
|
|
107
|
+
* `cargoContentFingerprint` for why a top-level `String(fn)` is not enough. */
|
|
108
|
+
export declare function hackageContentFingerprint(): string;
|
|
109
109
|
export declare function hackageExportGap(root: string): ExportGap;
|
|
110
110
|
/**
|
|
111
111
|
* Which declared dependencies may be opened to fill the gap.
|
|
@@ -670,9 +670,9 @@ function haskellSources(root) {
|
|
|
670
670
|
walk(root);
|
|
671
671
|
return out;
|
|
672
672
|
}
|
|
673
|
-
/** Source of
|
|
674
|
-
* `
|
|
675
|
-
export function
|
|
673
|
+
/** Source of everything this row contributes to a chunk's content — see
|
|
674
|
+
* `cargoContentFingerprint` for why a top-level `String(fn)` is not enough. */
|
|
675
|
+
export function hackageContentFingerprint() {
|
|
676
676
|
return [hackageExportGap, haskellSources, exportListText, declaredInSurface, haskellSurface]
|
|
677
677
|
.map(String)
|
|
678
678
|
.concat([REEXPORT_RE.source, EXPORT_NAME_RE.source])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.11",
|
|
4
4
|
"description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|