@bloodhound-rs/core 0.1.1 → 0.2.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/types.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- export type ResourceKind = 'js' | 'html' | 'css' | 'asset';
2
- export type ScriptMode = 'classic' | 'module' | 'unknown';
3
- export type Environment = 'window' | 'worker' | 'unknown';
4
- export type ScanStatus = 'completed' | 'partial' | 'failed';
1
+ /**
2
+ * Public types of `@bloodhound-rs/core`.
3
+ *
4
+ * These mirror the Rust data model in `native/src/model.rs`. The Rust side is
5
+ * the source of truth; keep field names and enum values in sync.
6
+ */
7
+ /** Where a resource's bytes come from. */
5
8
  export type Source = {
6
9
  type: 'file';
7
10
  path: string;
@@ -11,234 +14,209 @@ export type Source = {
11
14
  } | {
12
15
  type: 'content';
13
16
  content: string;
14
- resourceUrl: string;
17
+ /** Logical URL used to resolve relative dependencies and to label the resource. */
18
+ resourceUrl?: string;
15
19
  };
16
- export interface ImportMap {
17
- imports?: Record<string, string | null>;
18
- scopes?: Record<string, Record<string, string | null>>;
19
- }
20
- export interface Context {
21
- scriptMode: ScriptMode;
22
- executionEnvironment: Environment;
23
- baseUrl?: string;
24
- importMap?: ImportMap;
25
- importMapBaseUrl?: string;
26
- scopeKey: string;
27
- publicPath?: string;
28
- versions: Record<string, string>;
20
+ export type ResourceKind = 'js' | 'html' | 'css';
21
+ /**
22
+ * How a JavaScript resource executes. Top-level `var`/`function` in a classic
23
+ * script become `window` properties; in a module they stay module-local.
24
+ */
25
+ export type ScriptMode = 'classic' | 'module';
26
+ export type DependencyMode = 'single' | 'recursive';
27
+ export interface ScanEntry {
28
+ kind: ResourceKind;
29
+ source: Source;
30
+ /** Overrides the logical URL of the source. */
31
+ resourceUrl?: string;
32
+ /** Script mode for JS entries. Defaults to `ScanOptions.scriptMode`. */
33
+ scriptMode?: ScriptMode;
29
34
  }
30
35
  export interface Budgets {
36
+ /** Maximum in-flight load-and-analysis jobs. Default 8, at most 256. */
31
37
  concurrency: number;
38
+ /** Worker count, capped by concurrency. Default: CPU count, at most 256. */
32
39
  analysisConcurrency: number;
40
+ /** Wall clock limit for the whole scan. Default 120 000. */
33
41
  timeoutMs: number;
42
+ /** Per-request network timeout. Default 30 000. */
34
43
  resourceTimeoutMs: number;
44
+ /** Maximum resources loaded. Default 500. */
35
45
  maxResources: number;
36
- maxBytes: number;
46
+ /** Maximum size of one resource. Default 16 MiB. */
37
47
  maxResourceBytes: number;
38
- maxBufferedBytes: number;
39
- maxRecords: number;
48
+ /** Maximum total bytes loaded. Default 256 MiB. */
49
+ maxBytes: number;
50
+ /** Maximum dependency depth from an entry. Default 16. */
40
51
  maxDepth: number;
52
+ /** Maximum AST nodes visited per JavaScript resource. Default 2 000 000. */
41
53
  maxSteps: number;
54
+ /** Maximum string candidates tracked per value. Default 32. */
42
55
  maxCandidates: number;
43
- maxSummaryPasses: number;
56
+ /** HTTP redirects followed per request. Default 5. */
44
57
  maxRedirects: number;
58
+ /** HTTP retries on transport failure. Default 1. */
45
59
  retries: number;
46
60
  }
61
+ export interface Access {
62
+ /** Allowed URL schemes with trailing colon, e.g. `['https:']`. Default: file, http, https. */
63
+ protocols?: string[];
64
+ /** Allowed `host[:port]` values for network requests. */
65
+ hosts?: string[];
66
+ /** Directories that `file:` URLs must live inside. */
67
+ fileRoots?: string[];
68
+ }
69
+ export interface ImportMap {
70
+ imports?: Record<string, string | null>;
71
+ scopes?: Record<string, Record<string, string | null>>;
72
+ }
73
+ export interface ScanOptions {
74
+ /** Script mode for JS entries and for scripts whose mode is unknown. Default `classic`. */
75
+ scriptMode?: ScriptMode;
76
+ /** `single` analyzes only the entries; `recursive` follows dependencies. Default `recursive`. */
77
+ dependencyMode?: DependencyMode;
78
+ /** Logical URL for a string or content input (used by `scanHtml`/`scanJs`). */
79
+ resourceUrl?: string;
80
+ /** Document base when a resource has no usable URL of its own. */
81
+ baseUrl?: string;
82
+ /** Import map applied to standalone JS entries. HTML entries read their own. */
83
+ importMap?: ImportMap;
84
+ budgets?: Partial<Budgets>;
85
+ access?: Access;
86
+ /**
87
+ * Regex source strings (Rust regex syntax: no lookaround or backreferences) matched against
88
+ * the resolved logical URL of recursively discovered dependencies, e.g. `'/vendor/'` or
89
+ * `'\\.min\\.js($|\\?)'`. Matching dependencies are not loaded or analyzed and appear in
90
+ * `dependencies` as `not-followed` with `reason: 'excluded'`. Inline scripts are not matched.
91
+ * A matching entry, or an invalid pattern, rejects the scan (throws).
92
+ */
93
+ excludeUrls?: string[];
94
+ /** Substitute sources for resolved URLs (offline scanning of bundler output). */
95
+ resourceMappings?: Record<string, Source>;
96
+ /** Extra request headers keyed by `host[:port]`. */
97
+ requestHeaders?: Record<string, Record<string, string>>;
98
+ proxy?: string;
99
+ /** Decode `sourceMappingURL` comments and attach original locations. */
100
+ sourceMaps?: boolean;
101
+ /** Cancels a running scan. The result is a manifest with `status: 'cancelled'`. */
102
+ signal?: AbortSignal;
103
+ }
104
+ /**
105
+ * Pollution categories reported by the scanner.
106
+ *
107
+ * | rule | meaning |
108
+ * |------------------------|---------------------------------------------------------------------|
109
+ * | `global-write` | `window.x = …`, top-level `var`/`function` in classic scripts |
110
+ * | `document-write` | `document.body.className = …`, `document.body.setAttribute(…)` |
111
+ * | `builtin-mutation` | `Array.prototype.x = …`, `Promise.allSettled = …` |
112
+ * | `host-api-override` | `window.fetch = …`, `XMLHttpRequest.prototype.open = …` |
113
+ * | `dom-insertion` | `document.body.appendChild(…)`, `document.write(…)` |
114
+ * | `style-injection` | `<style>`/`<link>` inserted by script without removal |
115
+ * | `document-style-write` | `document.body.style.x = …`, `documentElement.style.setProperty(…)` |
116
+ * | `global-listener` | `window.addEventListener(…)` without `removeEventListener` |
117
+ * | `html-global-style` | `style=` attribute on `<html>`/`<body>` |
118
+ */
119
+ export type Rule = 'global-write' | 'document-write' | 'builtin-mutation' | 'host-api-override' | 'dom-insertion' | 'style-injection' | 'document-style-write' | 'global-listener' | 'html-global-style';
120
+ export type Severity = 'info' | 'warning' | 'error';
121
+ /**
122
+ * `high`: the receiver is provably the global object, `document`, or a builtin.
123
+ * `medium`: the receiver was tracked through a reassignable alias or a branch.
124
+ */
125
+ export type Confidence = 'high' | 'medium';
126
+ export type ScanStatus = 'completed' | 'partial' | 'failed' | 'cancelled';
127
+ export type SourceStatus = 'completed' | 'partial' | 'failed';
128
+ export type DependencyStatus = 'resolved' | 'not-followed' | 'unresolved';
129
+ export type DependencyKind = 'script' | 'inline-script' | 'style' | 'module-preload' | 'iframe' | 'import' | 'dynamic-import' | 'worker' | 'dynamic-script' | 'dynamic-style';
130
+ /** Lines are 1-based; columns are 0-based UTF-16 code units. */
47
131
  export interface Location {
48
- start: number;
49
- end: number;
50
132
  line: number;
51
133
  column: number;
52
134
  endLine: number;
53
135
  endColumn: number;
54
- offsetEncoding: 'utf16';
136
+ /** Original position from a source map when `sourceMaps` was enabled. */
55
137
  original?: {
56
138
  source: string;
57
139
  line: number;
58
140
  column: number;
59
141
  name?: string;
60
142
  };
61
- container?: {
62
- resourceUrl: string;
63
- offset: number;
64
- line: number;
65
- column: number;
66
- approximate?: boolean;
67
- };
68
143
  }
69
- export interface Resource {
70
- resourceId: string;
71
- requestedUrl: string;
72
- finalUrl: string;
73
- contentHash: string;
144
+ export interface ManifestSource {
145
+ /** Manifest-local id such as `s1`. */
146
+ id: string;
74
147
  kind: ResourceKind;
75
- bytes: number;
76
- scmId?: string;
148
+ /** Logical URL. Absent for anonymous inline content. */
149
+ url?: string;
150
+ /** Present for inline scripts extracted from an HTML parent. */
77
151
  inline?: {
78
- parentUrl: string;
79
- offset: number;
80
- approximate?: boolean;
152
+ parent: string;
153
+ line: number;
154
+ column: number;
81
155
  };
82
- }
83
- export interface AnalysisInstance {
84
- analysisId: string;
85
- resourceId: string;
86
- contextHash: string;
87
- context: Context;
88
- scanStatus: ScanStatus;
89
- exports: Record<string, unknown>;
90
- sourceMapStatus: 'absent' | 'mapped' | 'unavailable';
91
- }
92
- export interface Reference {
93
- referenceId: string;
94
- fromAnalysisId: string;
95
- toAnalysisIds: string[];
96
- kind: string;
97
- specifier?: string;
98
- resolvedUrl?: string;
99
- resolution: 'resolved' | 'candidate' | 'unresolved' | 'not-followed';
100
- location: Location;
101
- condition?: string;
102
- attributes?: Record<string, string>;
103
- reason?: string;
104
- }
105
- export interface Target {
106
- targetId: string;
107
- scopeKey: string;
108
- namespace: string;
109
- pathSegments: string[];
110
- keyKind: string;
111
- }
112
- export interface GlobalAccess {
113
- accessId: string;
114
- analysisId: string;
115
- targetRefs: string[];
156
+ scriptMode?: ScriptMode;
157
+ status: SourceStatus;
158
+ bytes: number;
159
+ contentHash: string;
160
+ /** Ids of the sources that referenced this one. Empty for entries. */
161
+ referrers: string[];
162
+ /** Shortest chain of source ids from an entry to this source, inclusive. */
163
+ chain: string[];
164
+ }
165
+ export interface ManifestFinding {
166
+ /** Source id containing the pollution. */
167
+ source: string;
168
+ rule: Rule;
169
+ severity: Severity;
170
+ /** Dotted path of the polluted target, e.g. `window.sharedConfig`. */
171
+ target: string;
172
+ /** `write` | `update` | `define` | `delete` | `declare` | `insert` | `listen` | `style`. */
116
173
  operation: string;
117
- valueType: string;
174
+ confidence: Confidence;
118
175
  location: Location;
119
- evidence: string[];
120
- fingerprint: string;
176
+ /** Trimmed excerpt of the offending expression. */
177
+ snippet: string;
178
+ detail?: string;
121
179
  }
122
- export interface Finding {
123
- findingId: string;
124
- ruleId: string;
125
- kind: 'global' | 'dom' | 'css';
126
- analysisId: string;
127
- accessRefs: string[];
180
+ export interface ManifestDependency {
181
+ from: string;
182
+ /** Set when the dependency was resolved and analyzed. */
183
+ to?: string;
184
+ kind: DependencyKind;
185
+ specifier?: string;
186
+ url?: string;
187
+ status: DependencyStatus;
188
+ reason?: string;
128
189
  location: Location;
129
- details: Record<string, unknown>;
130
- fingerprint: string;
131
190
  }
132
- export interface Unresolved {
133
- analysisId?: string;
134
- referenceId?: string;
135
- location?: Location;
191
+ export interface ManifestGap {
192
+ source?: string;
136
193
  reason: string;
137
- affectedCapabilities: string[];
194
+ count: number;
138
195
  detail?: string;
196
+ location?: Location;
139
197
  }
140
- export interface PendingResource {
141
- kind: ResourceKind;
142
- source: Source;
143
- resourceUrl: string;
144
- context: Context;
145
- depth: number;
146
- incoming: string[];
147
- inline?: {
148
- parentUrl: string;
149
- offset: number;
150
- parentContent: string;
151
- };
152
- }
153
- export interface Checkpoint {
154
- checkpointVersion: 1;
155
- configHash: string;
156
- entries: ScanEntry[];
157
- pending: PendingResource[];
158
- report: Report;
159
- options?: Pick<ScanOptions, 'access' | 'resourceMappings' | 'sourceMaps'>;
160
- }
161
- export interface ScanEntry {
162
- kind: ResourceKind;
163
- source: Source;
164
- resourceUrl?: string;
198
+ export interface Summary {
199
+ sources: number;
200
+ findings: number;
201
+ errors: number;
202
+ warnings: number;
203
+ dependencies: number;
204
+ unresolved: number;
205
+ gaps: number;
206
+ bytes: number;
207
+ elapsedMs: number;
165
208
  }
166
- export interface Report {
167
- schemaVersion: 1;
168
- indexSchemaVersion: 1;
209
+ /** The scan result. */
210
+ export interface Manifest {
211
+ schemaVersion: 2;
169
212
  scannerVersion: string;
170
- scanId: string;
171
- scopeKey: string;
172
- scanStatus: ScanStatus;
173
- runStatus: 'finished' | 'cancelled';
174
- startedAt: string;
175
- finishedAt: string;
176
- configuration: {
177
- context: Context;
178
- budgets: Budgets;
179
- dependencyMode: 'single' | 'recursive';
180
- };
181
- entryAnalysisIds: string[];
182
- resources: Resource[];
183
- analysisInstances: AnalysisInstance[];
184
- references: Reference[];
185
- globalTargets: Target[];
186
- globalAccesses: GlobalAccess[];
187
- findings: Finding[];
188
- unresolved: Unresolved[];
189
- coverage: {
190
- analyzed: number;
191
- failed: number;
192
- unresolved: number;
193
- bytes: number;
194
- dependencyMode: 'single' | 'recursive';
195
- sourceMapped: number;
196
- elapsedMs: number;
197
- };
198
- }
199
- export interface ScanOptions {
200
- scriptMode?: ScriptMode;
201
- executionEnvironment?: Environment;
202
- /** 离线资源的逻辑地址;直接扫描 URL 时无需重复设置。 */
203
- resourceUrl?: string;
204
- /** 补充文档基准;HTML 中的有效 base 标签会被自动读取。 */
205
- baseUrl?: string;
206
- /** 补充页面上下文,供单独扫描 JS 等场景使用;HTML 内的 Import Map 自动读取。 */
207
- importMap?: ImportMap;
208
- /** 外部传入 importMap 中相对地址的解析基准。 */
209
- importMapBaseUrl?: string;
210
- publicPath?: string;
211
- scopeKey?: string;
212
- scope?: Record<string, unknown>;
213
- versions?: Record<string, string>;
214
- dependencyMode?: 'single' | 'recursive';
215
- budgets?: Partial<Budgets>;
216
- signal?: AbortSignal;
217
- access?: {
218
- protocols?: string[];
219
- hosts?: string[];
220
- fileRoots?: string[];
221
- };
222
- /** 用本地文件或源码替代已解析的资源 URL;不是 HTML Import Map,普通页面扫描无需设置。 */
223
- resourceMappings?: Record<string, Source>;
224
- requestHeaders?: Record<string, Record<string, string>>;
225
- proxy?: string;
226
- jsonlPath?: string;
227
- reportPath?: string;
228
- checkpointPath?: string;
229
- resumePath?: string;
230
- sourceMaps?: boolean;
231
- resume?: Checkpoint;
213
+ status: ScanStatus;
214
+ dependencyMode: DependencyMode;
215
+ summary: Summary;
216
+ /** Source ids of the entries, in request order. */
217
+ entries: string[];
218
+ sources: ManifestSource[];
219
+ findings: ManifestFinding[];
220
+ dependencies: ManifestDependency[];
221
+ gaps: ManifestGap[];
232
222
  }
233
- export type StreamRecord = {
234
- type: 'resetAnalysis';
235
- value: {
236
- analysisId: string;
237
- };
238
- } | {
239
- type: keyof Pick<Report, 'resources' | 'analysisInstances' | 'references' | 'globalTargets' | 'globalAccesses' | 'findings' | 'unresolved'>;
240
- value: unknown;
241
- } | {
242
- type: 'summary';
243
- value: Omit<Report, 'resources' | 'analysisInstances' | 'references' | 'globalTargets' | 'globalAccesses' | 'findings' | 'unresolved'>;
244
- };
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Public types of `@bloodhound-rs/core`.
3
+ *
4
+ * These mirror the Rust data model in `native/src/model.rs`. The Rust side is
5
+ * the source of truth; keep field names and enum values in sync.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,53 +1,45 @@
1
1
  {
2
2
  "name": "@bloodhound-rs/core",
3
- "version": "0.1.1",
4
- "description": "Rust static resource scanner with a thin Node.js SDK",
3
+ "version": "0.2.0",
4
+ "description": "Rust static scanner that finds global-environment pollution in JavaScript and HTML",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "engines": {
8
8
  "node": ">=22"
9
9
  },
10
- "packageManager": "pnpm@10.20.0",
11
10
  "main": "./dist/index.js",
12
11
  "types": "./dist/index.d.ts",
13
12
  "exports": {
14
13
  ".": {
15
14
  "types": "./dist/index.d.ts",
16
15
  "import": "./dist/index.js"
17
- },
18
- "./schema": "./schemas/report.schema.json",
19
- "./index-schema": "./schemas/index.schema.json"
16
+ }
20
17
  },
21
18
  "files": [
22
- "dist",
23
- "schemas",
19
+ "dist/*.js",
20
+ "dist/*.d.ts",
24
21
  "README.md",
25
- "docs/support.md",
26
22
  "CHANGELOG.md"
27
23
  ],
28
- "scripts": {
29
- "build:native": "node scripts/build-native.mjs",
30
- "build:ts": "tsc --emitDeclarationOnly",
31
- "build": "node scripts/clean-dist.mjs && pnpm build:native && pnpm build:ts",
32
- "typecheck": "tsc --noEmit --skipLibCheck false",
33
- "prepack": "pnpm build",
34
- "example": "node examples/scan.mjs",
35
- "example:html": "node examples/scan-html.mjs",
36
- "format": "prettier --write src scripts examples schemas README.md docs/support.md docs/verification.md .github .changeset docs/releasing.md package.json tsconfig.json",
37
- "format:check": "prettier --check src scripts examples schemas README.md docs/support.md docs/verification.md .github .changeset docs/releasing.md package.json tsconfig.json",
38
- "changeset": "changeset",
39
- "changeset:status": "changeset status",
40
- "version:packages": "changeset version && node scripts/sync-native-version.mjs"
41
- },
42
24
  "devDependencies": {
43
25
  "@changesets/cli": "3.0.3",
44
26
  "@napi-rs/cli": "3.10.8",
45
27
  "@types/node": "^22.19.0",
46
28
  "prettier": "3.6.2",
47
- "typescript": "^5.9.3"
29
+ "rolldown": "1.2.14",
30
+ "rollup": "^4.64.12",
31
+ "typescript": "^5.9.3",
32
+ "@bloodhound-rs/rollup-plugin": "0.2.0"
48
33
  },
49
34
  "napi": {
50
- "binaryName": "bloodhound"
35
+ "binaryName": "bloodhound",
36
+ "targets": [
37
+ "x86_64-unknown-linux-gnu",
38
+ "aarch64-unknown-linux-gnu",
39
+ "aarch64-apple-darwin",
40
+ "x86_64-apple-darwin",
41
+ "x86_64-pc-windows-msvc"
42
+ ]
51
43
  },
52
44
  "publishConfig": {
53
45
  "access": "public",
@@ -57,5 +49,38 @@
57
49
  "repository": {
58
50
  "type": "git",
59
51
  "url": "git+https://github.com/Justinidlerz/bloodhound.git"
52
+ },
53
+ "optionalDependencies": {
54
+ "@bloodhound-rs/core-darwin-arm64": "0.2.0",
55
+ "@bloodhound-rs/core-linux-arm64-gnu": "0.2.0",
56
+ "@bloodhound-rs/core-linux-x64-gnu": "0.2.0",
57
+ "@bloodhound-rs/core-win32-x64-msvc": "0.2.0",
58
+ "@bloodhound-rs/core-darwin-x64": "0.2.0"
59
+ },
60
+ "scripts": {
61
+ "build:native": "node scripts/build-native.mjs",
62
+ "build:ts": "tsc -p tsconfig.json",
63
+ "build:plugin": "pnpm --filter @bloodhound-rs/rollup-plugin build",
64
+ "build": "node scripts/clean-dist.mjs && pnpm build:native && pnpm build:ts && pnpm build:plugin",
65
+ "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit --strict --skipLibCheck --module NodeNext --target ES2023 tests/types.test.ts && pnpm --filter @bloodhound-rs/rollup-plugin typecheck && pnpm typecheck:playground",
66
+ "example": "node examples/scan.mjs",
67
+ "example:html": "node examples/scan-html.mjs",
68
+ "example:rollup": "rollup -c examples/rollup/rollup.config.mjs",
69
+ "example:rolldown": "rolldown -c examples/rollup/rolldown.config.mjs",
70
+ "playground": "node playground/scripts/dev.mjs",
71
+ "build:playground": "node playground/scripts/build.mjs",
72
+ "typecheck:playground": "tsc --noEmit -p playground/tsconfig.json",
73
+ "format": "prettier --write src scripts tests examples packages playground README.md docs .github .changeset package.json tsconfig.json npm pnpm-workspace.yaml",
74
+ "format:check": "prettier --check src scripts tests examples packages playground README.md docs .github .changeset package.json tsconfig.json npm pnpm-workspace.yaml",
75
+ "changeset": "changeset",
76
+ "changeset:status": "changeset status",
77
+ "version:packages": "changeset version && node scripts/sync-native-version.mjs && node scripts/sync-platform-packages.mjs",
78
+ "platforms:sync": "node scripts/sync-platform-packages.mjs",
79
+ "pack:release": "node scripts/pack-ci.mjs",
80
+ "test": "pnpm test:rust && pnpm test:scripts && pnpm build && pnpm typecheck && pnpm test:sdk && pnpm test:plugin",
81
+ "test:rust": "cargo test --locked --lib",
82
+ "test:scripts": "node --test tests/scripts.test.mjs tests/release.test.mjs",
83
+ "test:sdk": "node --test tests/sdk.test.mjs",
84
+ "test:plugin": "pnpm --filter @bloodhound-rs/rollup-plugin test"
60
85
  }
61
- }
86
+ }
Binary file
Binary file
Binary file
Binary file
package/docs/support.md DELETED
@@ -1,55 +0,0 @@
1
- # 支持范围
2
-
3
- | 范围 | 实现 | 未完成项 |
4
- | --------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
5
- | JS 输入 | 文件、URL、内容,classic / module / unknown | 语法错误、模式或环境缺失 |
6
- | 绑定与目标 | Oxc 作用域、局部遮蔽、全局词法与对象属性分离、未绑定引用 | `with` 动态作用域 |
7
- | 全局操作 | 声明、读、赋值、复合赋值、更新、delete、Object / Reflect、原型 | 未知属性键保留独立访问,不创建共享空目标 |
8
- | 别名 | 顺序赋值、失效、有限分支合并、直接 IIFE 与可绑定包装函数参数 | 复杂解构赋值、异常及 switch 的值传播、一般函数副作用 |
9
- | 有限求值 | 字面量、拼接、模板、有限条件、数组与对象常量键、受限返回表达式 | getter、Proxy、一般调用、扩张超预算 |
10
- | ESM | import / export、动态 import 候选、跨模块原始值摘要、有界迭代 | 非有限动态依赖、未知裸模块映射 |
11
- | webpack | 运行时对象属性、纯 chunk 映射函数、脚本 src 表达式、有限 ID 表 | 自动 publicPath、复杂运行时函数及未知地址 |
12
- | Vite | 动态 import;具有链接创建与回调调用结构的 preload 包装函数及有限依赖数组 | 一般缓存型 mapDeps 包装及非有限数组 |
13
- | DOM | document / body / head 及别名的操作候选、可还原节点资源地址 | 未知节点身份、运行时插入、退出残留 |
14
- | Worker / iframe | 入口可解析时建立独立 scope,保留引用边 | 文档基准未知、动态子环境地址 |
15
- | HTML | HTML5 分词、raw-text、base、Import Map 快照、脚本、样式、iframe、内联偏移 | foreign-content 树上下文、noscript 环境、token 恢复、事件处理器特殊作用域 |
16
- | CSS | CSS Syntax 解析、@import、url、全局选择器、reset、自定义属性、动画 | 解析恢复、未知资源值;候选不代表实际匹配或污染 |
17
- | source map | Rust sourcemap,外链和 data URL | 缺失或不可用只影响可选源码位置 |
18
-
19
- HTML 使用有位置的 HTML5 分词,不模拟完整浏览器 DOM 树构造。模板内容保持惰性,特殊树上下文明确降低覆盖。`srcdoc` 等实体解码内容的宿主定位只保留属性所属标签范围,子资源内部位置独立记录。
20
-
21
- webpack 适配按语法结构和 Oxc 绑定关联,不匹配固定的压缩变量名。chunk 映射给出有限候选,并不证明每个 chunk 都会加载。Vite 的普通动态 import 始终由 ESM 分析处理,preload 只是补充资源边。
22
-
23
- # 状态
24
-
25
- | 状态 | 含义 |
26
- | --------- | ------------------------------------------------ |
27
- | completed | 声明范围内没有已记录的必检缺口 |
28
- | partial | 有结果,同时存在未知依赖、上下文、语义或预算缺口 |
29
- | failed | 没有建立有效分析结果 |
30
- | cancelled | runStatus,独立于以上扫描状态 |
31
-
32
- `single` 明确排除依赖闭包,引用边标记 `not-followed`。`completed` 不表示程序没有动态行为,也不表示候选问题实际发生。
33
-
34
- # 索引与位置
35
-
36
- - targetId 使用 scope、namespace、分段路径和键类型生成。局部 Symbol 额外绑定分析实例,不与其他资源合并。
37
- - 同内容不同 URL 或上下文保留独立实例,循环只阻止重复分析,保留引用边。
38
- - 未绑定裸引用保留候选关系,不能直接认定为隐式全局属性。
39
- - 产物位置采用 UTF-16 偏移、从 1 开始的行、从 0 开始的列,Rust 内部 UTF-8 偏移在输出时转换。
40
- - 多写入、原型变更、DOM/CSS 操作均为 static-candidate。
41
- - 版本差异匹配资源、scope、模式、环境、目标和操作特征。匹配不唯一时返回新增和移除。相同类型的任意值变化不保证识别。
42
-
43
- # 运行预算
44
-
45
- 资源数、总字节、单资源字节、下载缓冲字节、并发、深度、时间、AST 访问、有限求值、候选数、摘要轮次和记录数都有上限。AST 在单资源分析后释放,缓存受字节预算限制。
46
-
47
- 这些上限控制输入、任务和结果规模,不是操作系统 RSS 硬限额。大型或不可信输入可由宿主进程附加内存限制。网络阻塞受请求超时限制,解析阶段不承诺即时抢占。
48
-
49
- JSONL 支持消费端背压到文件系统。返回标准报告与内存索引会占用与记录规模相关的内存。恢复从保存的入口重建图并重新读取资源,当前不跳过远程内容校验。
50
-
51
- 断点保留访问范围、资源映射和 source map 开关。认证请求头与代理参数不保存,恢复时重新传入。
52
-
53
- # 交付边界
54
-
55
- 不包含平台数据库、发布 Guard、浏览器探针或线上发布。没有新增单元测试套件。真实产物扫描与构建证据不能替代完整的业务标注集精确率和召回率验收。