@keithadler/frostjs 0.1.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.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +568 -0
  3. package/dist/baseline.d.ts +18 -0
  4. package/dist/baseline.d.ts.map +1 -0
  5. package/dist/baseline.js +56 -0
  6. package/dist/baseline.js.map +1 -0
  7. package/dist/changed.d.ts +15 -0
  8. package/dist/changed.d.ts.map +1 -0
  9. package/dist/changed.js +93 -0
  10. package/dist/changed.js.map +1 -0
  11. package/dist/cli/args.d.ts +37 -0
  12. package/dist/cli/args.d.ts.map +1 -0
  13. package/dist/cli/args.js +200 -0
  14. package/dist/cli/args.js.map +1 -0
  15. package/dist/cli/main.d.ts +3 -0
  16. package/dist/cli/main.d.ts.map +1 -0
  17. package/dist/cli/main.js +8 -0
  18. package/dist/cli/main.js.map +1 -0
  19. package/dist/cli/run.d.ts +9 -0
  20. package/dist/cli/run.d.ts.map +1 -0
  21. package/dist/cli/run.js +404 -0
  22. package/dist/cli/run.js.map +1 -0
  23. package/dist/discover/index.d.ts +15 -0
  24. package/dist/discover/index.d.ts.map +1 -0
  25. package/dist/discover/index.js +70 -0
  26. package/dist/discover/index.js.map +1 -0
  27. package/dist/eslint.d.ts +103 -0
  28. package/dist/eslint.d.ts.map +1 -0
  29. package/dist/eslint.js +111 -0
  30. package/dist/eslint.js.map +1 -0
  31. package/dist/extract/annotations.d.ts +5 -0
  32. package/dist/extract/annotations.d.ts.map +1 -0
  33. package/dist/extract/annotations.js +5 -0
  34. package/dist/extract/annotations.js.map +1 -0
  35. package/dist/extract/ast.d.ts +45 -0
  36. package/dist/extract/ast.d.ts.map +1 -0
  37. package/dist/extract/ast.js +60 -0
  38. package/dist/extract/ast.js.map +1 -0
  39. package/dist/extract/capability.d.ts +22 -0
  40. package/dist/extract/capability.d.ts.map +1 -0
  41. package/dist/extract/capability.js +2 -0
  42. package/dist/extract/capability.js.map +1 -0
  43. package/dist/extract/html.d.ts +15 -0
  44. package/dist/extract/html.d.ts.map +1 -0
  45. package/dist/extract/html.js +69 -0
  46. package/dist/extract/html.js.map +1 -0
  47. package/dist/extract/index.d.ts +9 -0
  48. package/dist/extract/index.d.ts.map +1 -0
  49. package/dist/extract/index.js +95 -0
  50. package/dist/extract/index.js.map +1 -0
  51. package/dist/extract/recognizers/codegen.d.ts +10 -0
  52. package/dist/extract/recognizers/codegen.d.ts.map +1 -0
  53. package/dist/extract/recognizers/codegen.js +39 -0
  54. package/dist/extract/recognizers/codegen.js.map +1 -0
  55. package/dist/extract/recognizers/dom-escape.d.ts +11 -0
  56. package/dist/extract/recognizers/dom-escape.d.ts.map +1 -0
  57. package/dist/extract/recognizers/dom-escape.js +58 -0
  58. package/dist/extract/recognizers/dom-escape.js.map +1 -0
  59. package/dist/extract/recognizers/globals.d.ts +9 -0
  60. package/dist/extract/recognizers/globals.d.ts.map +1 -0
  61. package/dist/extract/recognizers/globals.js +121 -0
  62. package/dist/extract/recognizers/globals.js.map +1 -0
  63. package/dist/extract/recognizers/identity.d.ts +10 -0
  64. package/dist/extract/recognizers/identity.d.ts.map +1 -0
  65. package/dist/extract/recognizers/identity.js +79 -0
  66. package/dist/extract/recognizers/identity.js.map +1 -0
  67. package/dist/extract/recognizers/navigation.d.ts +12 -0
  68. package/dist/extract/recognizers/navigation.d.ts.map +1 -0
  69. package/dist/extract/recognizers/navigation.js +110 -0
  70. package/dist/extract/recognizers/navigation.js.map +1 -0
  71. package/dist/extract/recognizers/network.d.ts +11 -0
  72. package/dist/extract/recognizers/network.d.ts.map +1 -0
  73. package/dist/extract/recognizers/network.js +41 -0
  74. package/dist/extract/recognizers/network.js.map +1 -0
  75. package/dist/extract/recognizers/resolve.d.ts +37 -0
  76. package/dist/extract/recognizers/resolve.d.ts.map +1 -0
  77. package/dist/extract/recognizers/resolve.js +72 -0
  78. package/dist/extract/recognizers/resolve.js.map +1 -0
  79. package/dist/extract/recognizers/storage.d.ts +9 -0
  80. package/dist/extract/recognizers/storage.d.ts.map +1 -0
  81. package/dist/extract/recognizers/storage.js +37 -0
  82. package/dist/extract/recognizers/storage.js.map +1 -0
  83. package/dist/extract/recognizers/types.d.ts +38 -0
  84. package/dist/extract/recognizers/types.d.ts.map +1 -0
  85. package/dist/extract/recognizers/types.js +25 -0
  86. package/dist/extract/recognizers/types.js.map +1 -0
  87. package/dist/extract/recognizers/worker.d.ts +11 -0
  88. package/dist/extract/recognizers/worker.d.ts.map +1 -0
  89. package/dist/extract/recognizers/worker.js +41 -0
  90. package/dist/extract/recognizers/worker.js.map +1 -0
  91. package/dist/extract/scope.d.ts +23 -0
  92. package/dist/extract/scope.d.ts.map +1 -0
  93. package/dist/extract/scope.js +299 -0
  94. package/dist/extract/scope.js.map +1 -0
  95. package/dist/extract/suppress.d.ts +21 -0
  96. package/dist/extract/suppress.d.ts.map +1 -0
  97. package/dist/extract/suppress.js +42 -0
  98. package/dist/extract/suppress.js.map +1 -0
  99. package/dist/extract/target.d.ts +34 -0
  100. package/dist/extract/target.d.ts.map +1 -0
  101. package/dist/extract/target.js +81 -0
  102. package/dist/extract/target.js.map +1 -0
  103. package/dist/extract/typescript.d.ts +12 -0
  104. package/dist/extract/typescript.d.ts.map +1 -0
  105. package/dist/extract/typescript.js +56 -0
  106. package/dist/extract/typescript.js.map +1 -0
  107. package/dist/extract/walk.d.ts +14 -0
  108. package/dist/extract/walk.d.ts.map +1 -0
  109. package/dist/extract/walk.js +70 -0
  110. package/dist/extract/walk.js.map +1 -0
  111. package/dist/index.d.ts +4 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +4 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/init.d.ts +10 -0
  116. package/dist/init.d.ts.map +1 -0
  117. package/dist/init.js +79 -0
  118. package/dist/init.js.map +1 -0
  119. package/dist/policy/compile.d.ts +56 -0
  120. package/dist/policy/compile.d.ts.map +1 -0
  121. package/dist/policy/compile.js +78 -0
  122. package/dist/policy/compile.js.map +1 -0
  123. package/dist/policy/config.d.ts +18 -0
  124. package/dist/policy/config.d.ts.map +1 -0
  125. package/dist/policy/config.js +70 -0
  126. package/dist/policy/config.js.map +1 -0
  127. package/dist/policy/csp.d.ts +19 -0
  128. package/dist/policy/csp.d.ts.map +1 -0
  129. package/dist/policy/csp.js +47 -0
  130. package/dist/policy/csp.js.map +1 -0
  131. package/dist/policy/glob.d.ts +12 -0
  132. package/dist/policy/glob.d.ts.map +1 -0
  133. package/dist/policy/glob.js +63 -0
  134. package/dist/policy/glob.js.map +1 -0
  135. package/dist/policy/index.d.ts +47 -0
  136. package/dist/policy/index.d.ts.map +1 -0
  137. package/dist/policy/index.js +34 -0
  138. package/dist/policy/index.js.map +1 -0
  139. package/dist/policy/parse.d.ts +51 -0
  140. package/dist/policy/parse.d.ts.map +1 -0
  141. package/dist/policy/parse.js +352 -0
  142. package/dist/policy/parse.js.map +1 -0
  143. package/dist/policy/vocabulary.d.ts +15 -0
  144. package/dist/policy/vocabulary.d.ts.map +1 -0
  145. package/dist/policy/vocabulary.js +99 -0
  146. package/dist/policy/vocabulary.js.map +1 -0
  147. package/dist/registry.d.ts +45 -0
  148. package/dist/registry.d.ts.map +1 -0
  149. package/dist/registry.js +85 -0
  150. package/dist/registry.js.map +1 -0
  151. package/dist/report/github.d.ts +10 -0
  152. package/dist/report/github.d.ts.map +1 -0
  153. package/dist/report/github.js +31 -0
  154. package/dist/report/github.js.map +1 -0
  155. package/dist/report/json.d.ts +44 -0
  156. package/dist/report/json.d.ts.map +1 -0
  157. package/dist/report/json.js +40 -0
  158. package/dist/report/json.js.map +1 -0
  159. package/dist/report/sarif.d.ts +10 -0
  160. package/dist/report/sarif.d.ts.map +1 -0
  161. package/dist/report/sarif.js +64 -0
  162. package/dist/report/sarif.js.map +1 -0
  163. package/dist/report/summary.d.ts +9 -0
  164. package/dist/report/summary.d.ts.map +1 -0
  165. package/dist/report/summary.js +67 -0
  166. package/dist/report/summary.js.map +1 -0
  167. package/dist/report/text.d.ts +37 -0
  168. package/dist/report/text.d.ts.map +1 -0
  169. package/dist/report/text.js +81 -0
  170. package/dist/report/text.js.map +1 -0
  171. package/dist/sync.d.ts +19 -0
  172. package/dist/sync.d.ts.map +1 -0
  173. package/dist/sync.js +131 -0
  174. package/dist/sync.js.map +1 -0
  175. package/dist/version.d.ts +2 -0
  176. package/dist/version.d.ts.map +1 -0
  177. package/dist/version.js +6 -0
  178. package/dist/version.js.map +1 -0
  179. package/package.json +88 -0
package/dist/eslint.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * ESLint plugin. One rule, `frostjs/capability`, runs the same engine the
3
+ * CLI does on each file ESLint hands it: frostjs's own parse, extraction,
4
+ * policy discovery (nearest frostjs.policy above the file) and decision.
5
+ * Reports are ESLint problems at the use's position, so they show in
6
+ * editors and `eslint-disable` comments work alongside `frostjs: ignore`.
7
+ *
8
+ * import frostjs from "@keithadler/frostjs/eslint";
9
+ * export default [{ plugins: { frostjs }, rules: { "frostjs/capability": "error" } }];
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import { parseSource } from "./extract/ast.js";
14
+ import { extract } from "./extract/index.js";
15
+ import { compilePolicyFile, decide, findPolicyFile, isoToday, matchesGlob, DENY_ALL, PolicyError, } from "./policy/index.js";
16
+ import { denialText, describeUse } from "./report/text.js";
17
+ import { VERSION } from "./version.js";
18
+ const cache = new Map();
19
+ /** The policy for a file, cached by mtime so edits are picked up without restarting ESLint. */
20
+ function loadPolicy(file, today, explicit) {
21
+ const policyFile = explicit ? path.resolve(explicit) : findPolicyFile(path.dirname(file));
22
+ if (policyFile === null)
23
+ return { policy: DENY_ALL, dir: path.dirname(file) };
24
+ const dir = path.dirname(policyFile);
25
+ let mtimeMs;
26
+ try {
27
+ mtimeMs = fs.statSync(policyFile).mtimeMs;
28
+ }
29
+ catch {
30
+ return { policy: DENY_ALL, dir, error: `cannot read policy ${policyFile}` };
31
+ }
32
+ const hit = cache.get(policyFile);
33
+ if (hit && hit.mtimeMs === mtimeMs && hit.policy.today === today)
34
+ return { policy: hit.policy, dir };
35
+ try {
36
+ const policy = compilePolicyFile(policyFile, today);
37
+ cache.set(policyFile, { policy, mtimeMs });
38
+ return { policy, dir };
39
+ }
40
+ catch (e) {
41
+ if (e instanceof PolicyError || e instanceof Error)
42
+ return { policy: DENY_ALL, dir, error: e.message };
43
+ throw e;
44
+ }
45
+ }
46
+ /** The `frostjs/capability` rule. See RuleOptions. */
47
+ export const capabilityRule = {
48
+ meta: {
49
+ type: "problem",
50
+ docs: { description: "Deny capability uses the frostjs policy has not granted", recommended: true },
51
+ schema: [
52
+ {
53
+ type: "object",
54
+ properties: {
55
+ policy: { type: "string" },
56
+ minConfidence: { enum: ["certain", "probable", "possible"] },
57
+ reportUnknown: { type: "boolean" },
58
+ today: { type: "string" },
59
+ },
60
+ additionalProperties: false,
61
+ },
62
+ ],
63
+ },
64
+ create(context) {
65
+ return {
66
+ Program() {
67
+ const filename = context.filename ?? context.getFilename?.() ?? "<input>";
68
+ const text = context.sourceCode?.text ?? context.getSourceCode?.().text ?? "";
69
+ const opts = (context.options[0] ?? {});
70
+ const today = opts.today ?? isoToday();
71
+ const file = path.resolve(filename);
72
+ const { policy, dir, error } = loadPolicy(file, today, opts.policy);
73
+ if (error) {
74
+ context.report({ message: `frostjs: ${error.split("\n")[0]}`, loc: { line: 1, column: 0 } });
75
+ return;
76
+ }
77
+ if (policy.ignore.some((g) => matchesGlob(g, path.relative(dir, file))))
78
+ return;
79
+ const parsed = parseSource(file, text);
80
+ if (parsed.errors.length > 0)
81
+ return; // ESLint's own parser will have complained already
82
+ const decisions = decide(extract(parsed), policy, {
83
+ scopePath: (u) => path.relative(dir, u.file),
84
+ ...(opts.minConfidence ? { minConfidence: opts.minConfidence } : {}),
85
+ });
86
+ for (const d of decisions) {
87
+ const { use } = d;
88
+ const loc = { line: use.line, column: use.column - 1 };
89
+ const subject = describeUse(use.capability, use.target);
90
+ if (d.verdict === "denied") {
91
+ context.report({ message: `${subject} ${denialText(d)}`, loc });
92
+ }
93
+ else if (d.verdict === "unknown" && opts.reportUnknown) {
94
+ context.report({ message: `${subject} ${use.confidence} (not failing the build)`, loc });
95
+ }
96
+ }
97
+ },
98
+ };
99
+ },
100
+ };
101
+ const plugin = {
102
+ meta: { name: "frostjs", version: VERSION },
103
+ rules: { capability: capabilityRule },
104
+ configs: {},
105
+ };
106
+ plugin.configs["recommended"] = {
107
+ plugins: { frostjs: plugin },
108
+ rules: { "frostjs/capability": "error" },
109
+ };
110
+ export default plugin;
111
+ //# sourceMappingURL=eslint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.js","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Annotation keys the scope analysis writes onto identifier nodes for the recognizers to read. */
2
+ export declare const FOLDED = "$frostjsFolded";
3
+ export declare const FREE = "$frostjsFree";
4
+ export declare const AMBIGUOUS = "$frostjsAmbiguous";
5
+ //# sourceMappingURL=annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/extract/annotations.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,eAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,eAAO,MAAM,IAAI,iBAAiB,CAAC;AACnC,eAAO,MAAM,SAAS,sBAAsB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /** Annotation keys the scope analysis writes onto identifier nodes for the recognizers to read. */
2
+ export const FOLDED = "$frostjsFolded";
3
+ export const FREE = "$frostjsFree";
4
+ export const AMBIGUOUS = "$frostjsAmbiguous";
5
+ //# sourceMappingURL=annotations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.js","sourceRoot":"","sources":["../../src/extract/annotations.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAgB,CAAC;AACvC,MAAM,CAAC,MAAM,IAAI,GAAG,cAAc,CAAC;AACnC,MAAM,CAAC,MAAM,SAAS,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { Program, Node } from "oxc-parser";
2
+ export type { Program, Node };
3
+ /** An AST node with its fields open for inspection. oxc's typed tree is narrower than the walkers need. */
4
+ export type AnyNode = Node & Record<string, unknown>;
5
+ export declare const isNode: (v: unknown) => v is AnyNode;
6
+ export interface ParseError {
7
+ file: string;
8
+ line: number;
9
+ column: number;
10
+ message: string;
11
+ }
12
+ export interface Comment {
13
+ type: "Line" | "Block";
14
+ value: string;
15
+ start: number;
16
+ end: number;
17
+ }
18
+ export interface ParsedFile {
19
+ file: string;
20
+ source: string;
21
+ program: Program;
22
+ comments: Comment[];
23
+ errors: ParseError[];
24
+ lines: LineIndex;
25
+ }
26
+ /** Offsets of the first character of each line. */
27
+ export type LineIndex = readonly number[];
28
+ /** Offsets of the first character of each line, for mapping byte offsets to positions. */
29
+ export declare function lineIndex(source: string): LineIndex;
30
+ /** Map a character offset to a 1-based line and column. */
31
+ export declare function positionAt(lines: LineIndex, offset: number): {
32
+ line: number;
33
+ column: number;
34
+ };
35
+ /**
36
+ * Parse source text. `.mjs`/`.mts` are modules, `.cjs`/`.cts` are scripts,
37
+ * anything else is detected from the content. The language comes from the
38
+ * extension (oxc handles .ts/.tsx/.jsx natively). A `.js` file that does
39
+ * not parse is retried as JSX, since React and Docusaurus projects put JSX
40
+ * in `.js` files as a matter of course.
41
+ */
42
+ export declare function parseSource(file: string, source: string): ParsedFile;
43
+ /** Read and parse a file from disk. */
44
+ export declare function parseFile(file: string): ParsedFile;
45
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/extract/ast.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEhD,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAE9B,2GAA2G;AAC3G,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErD,eAAO,MAAM,MAAM,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,OACkD,CAAC;AAE5F,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,MAAM,SAAS,GAAG,SAAS,MAAM,EAAE,CAAC;AAE1C,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAMnD;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAS7F;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAgBpE;AAED,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAElD"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Adapter over oxc-parser. Everything downstream imports AST types and the
3
+ * parse entry points from here, never from oxc-parser directly, so a change
4
+ * in oxc's AST shape is absorbed in one file.
5
+ */
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import { parseSync } from "oxc-parser";
9
+ export const isNode = (v) => typeof v === "object" && v !== null && typeof v.type === "string";
10
+ /** Offsets of the first character of each line, for mapping byte offsets to positions. */
11
+ export function lineIndex(source) {
12
+ const starts = [0];
13
+ for (let i = 0; i < source.length; i++) {
14
+ if (source.charCodeAt(i) === 10)
15
+ starts.push(i + 1);
16
+ }
17
+ return starts;
18
+ }
19
+ /** Map a character offset to a 1-based line and column. */
20
+ export function positionAt(lines, offset) {
21
+ let lo = 0;
22
+ let hi = lines.length - 1;
23
+ while (lo < hi) {
24
+ const mid = (lo + hi + 1) >> 1;
25
+ if (lines[mid] <= offset)
26
+ lo = mid;
27
+ else
28
+ hi = mid - 1;
29
+ }
30
+ return { line: lo + 1, column: offset - lines[lo] + 1 };
31
+ }
32
+ /**
33
+ * Parse source text. `.mjs`/`.mts` are modules, `.cjs`/`.cts` are scripts,
34
+ * anything else is detected from the content. The language comes from the
35
+ * extension (oxc handles .ts/.tsx/.jsx natively). A `.js` file that does
36
+ * not parse is retried as JSX, since React and Docusaurus projects put JSX
37
+ * in `.js` files as a matter of course.
38
+ */
39
+ export function parseSource(file, source) {
40
+ const ext = path.extname(file).toLowerCase();
41
+ const sourceType = ext === ".mjs" || ext === ".mts" ? "module" : ext === ".cjs" || ext === ".cts" ? "script" : "unambiguous";
42
+ let result = parseSync(file, source, { sourceType });
43
+ if (result.errors.length > 0 && (ext === ".js" || ext === ".mjs" || ext === ".cjs")) {
44
+ const asJsx = parseSync(file, source, { sourceType, lang: "jsx" });
45
+ if (asJsx.errors.length === 0)
46
+ result = asJsx;
47
+ }
48
+ const lines = lineIndex(source);
49
+ const errors = result.errors.map((e) => {
50
+ const offset = e.labels?.[0]?.start ?? 0;
51
+ const pos = positionAt(lines, offset);
52
+ return { file, line: pos.line, column: pos.column, message: e.message };
53
+ });
54
+ return { file, source, program: result.program, comments: result.comments, errors, lines };
55
+ }
56
+ /** Read and parse a file from disk. */
57
+ export function parseFile(file) {
58
+ return parseSource(file, fs.readFileSync(file, "utf8"));
59
+ }
60
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/extract/ast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** How sure the extractor is that this use is real. See REQUIREMENTS 6.1. */
2
+ export type Confidence = "certain" | "probable" | "possible";
3
+ /** Where a use came from: the project's own code, a vendored file admitted by the registry, or a script block in HTML. */
4
+ export type Origin = "first-party" | "vendored" | "inline-html";
5
+ export interface CapabilityUse {
6
+ /** Stable code, e.g. "storage.local", "network.fetch". */
7
+ capability: string;
8
+ /** Resolved URL or host if statically knowable, else null. */
9
+ target: string | null;
10
+ file: string;
11
+ /** 1-based. */
12
+ line: number;
13
+ /** 1-based. */
14
+ column: number;
15
+ /** Source text of the enclosing expression. */
16
+ expression: string;
17
+ confidence: Confidence;
18
+ origin: Origin;
19
+ /** An inline `frostjs: ignore` comment covers this use. */
20
+ suppressed: boolean;
21
+ }
22
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/extract/capability.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAE7D,0HAA0H;AAC1H,MAAM,MAAM,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,UAAU,EAAE,OAAO,CAAC;CACrB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../../src/extract/capability.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import { type ParsedFile } from "./ast.js";
2
+ export interface ScriptBlock {
3
+ /** Offset of the first character of the block's content. */
4
+ start: number;
5
+ /** Offset just past the last character of the content. */
6
+ end: number;
7
+ module: boolean;
8
+ }
9
+ /** Offsets of every inline JavaScript block: no `src`, a JavaScript (or no) `type`, and some content. */
10
+ export declare function scriptBlocks(html: string): ScriptBlock[];
11
+ /** Replace every character outside [start, end) with a space, keeping newlines. */
12
+ export declare function mask(source: string, start: number, end: number): string;
13
+ /** Parse each inline script block of an HTML file as its own ParsedFile positioned in the HTML. */
14
+ export declare function parseHtml(file: string, source: string): ParsedFile[];
15
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/extract/html.ts"],"names":[],"mappings":"AAWA,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAEhF,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;CACjB;AAiBD,yGAAyG;AACzG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAgBxD;AAED,mFAAmF;AACnF,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAcpE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Inline <script> blocks in HTML. Each block is parsed as JavaScript with
3
+ * everything outside it masked to whitespace (newlines kept), so every
4
+ * offset, line and column already refers to the HTML file and expression
5
+ * text slices straight out of it. No HTML parser: a regular expression
6
+ * finds script elements, which is adequate for the markup people write by
7
+ * hand and wrong only for markup designed to confuse it, which the threat
8
+ * model already excludes.
9
+ */
10
+ import path from "node:path";
11
+ import { parseSync } from "oxc-parser";
12
+ import { lineIndex, positionAt } from "./ast.js";
13
+ const SCRIPT = /<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi;
14
+ const ATTR = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
15
+ /** Script types that carry JavaScript. Anything else (json, importmap, templates) is data. */
16
+ const JS_TYPES = new Set([
17
+ "",
18
+ "text/javascript",
19
+ "application/javascript",
20
+ "text/ecmascript",
21
+ "application/ecmascript",
22
+ "module",
23
+ "text/jsx",
24
+ "text/babel",
25
+ ]);
26
+ /** Offsets of every inline JavaScript block: no `src`, a JavaScript (or no) `type`, and some content. */
27
+ export function scriptBlocks(html) {
28
+ const out = [];
29
+ for (const m of html.matchAll(SCRIPT)) {
30
+ const attrs = new Map();
31
+ for (const a of (m[1] ?? "").matchAll(ATTR)) {
32
+ attrs.set(a[1].toLowerCase(), (a[2] ?? a[3] ?? a[4] ?? "").trim().toLowerCase());
33
+ }
34
+ if (attrs.has("src"))
35
+ continue;
36
+ const type = attrs.get("type") ?? "";
37
+ if (!JS_TYPES.has(type))
38
+ continue;
39
+ const content = m[2] ?? "";
40
+ if (content.trim() === "")
41
+ continue;
42
+ const open = m.index + m[0].indexOf(">") + 1;
43
+ out.push({ start: open, end: open + content.length, module: type === "module" });
44
+ }
45
+ return out;
46
+ }
47
+ /** Replace every character outside [start, end) with a space, keeping newlines. */
48
+ export function mask(source, start, end) {
49
+ const before = source.slice(0, start).replace(/[^\n]/g, " ");
50
+ const after = source.slice(end).replace(/[^\n]/g, " ");
51
+ return before + source.slice(start, end) + after;
52
+ }
53
+ /** Parse each inline script block of an HTML file as its own ParsedFile positioned in the HTML. */
54
+ export function parseHtml(file, source) {
55
+ const lines = lineIndex(source);
56
+ return scriptBlocks(source).map((block) => {
57
+ const masked = mask(source, block.start, block.end);
58
+ const result = parseSync(path.basename(file) + ".js", masked, {
59
+ lang: "js",
60
+ sourceType: block.module ? "module" : "unambiguous",
61
+ });
62
+ const errors = result.errors.map((e) => {
63
+ const pos = positionAt(lines, e.labels?.[0]?.start ?? block.start);
64
+ return { file, line: pos.line, column: pos.column, message: e.message };
65
+ });
66
+ return { file, source: masked, program: result.program, comments: result.comments, errors, lines };
67
+ });
68
+ }
69
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/extract/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ParsedFile } from "./ast.js";
2
+ import type { CapabilityUse, Origin } from "./capability.js";
3
+ export interface ExtractOptions {
4
+ /** Where the file came from; stamped on every use. Defaults to first-party. */
5
+ origin?: Origin;
6
+ }
7
+ /** Run every recognizer over every node and return the flat list of uses. */
8
+ export declare function extract(parsed: ParsedFile, opts?: ExtractOptions): CapabilityUse[];
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA4B7D,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE,cAAmB,GAAG,aAAa,EAAE,CAmCtF"}
@@ -0,0 +1,95 @@
1
+ import { positionAt } from "./ast.js";
2
+ import { walk } from "./walk.js";
3
+ import { analyzeScopes } from "./scope.js";
4
+ import { AMBIGUOUS, FOLDED, FREE } from "./annotations.js";
5
+ import { isFoldedMember } from "./recognizers/resolve.js";
6
+ import { suppressions, isSuppressed } from "./suppress.js";
7
+ import { storage } from "./recognizers/storage.js";
8
+ import { network } from "./recognizers/network.js";
9
+ import { codegen } from "./recognizers/codegen.js";
10
+ import { domEscape } from "./recognizers/dom-escape.js";
11
+ import { identity } from "./recognizers/identity.js";
12
+ import { navigation } from "./recognizers/navigation.js";
13
+ import { globals } from "./recognizers/globals.js";
14
+ import { worker } from "./recognizers/worker.js";
15
+ /** One recognizer per capability family. */
16
+ const RECOGNIZERS = [
17
+ storage,
18
+ network,
19
+ codegen,
20
+ domEscape,
21
+ identity,
22
+ navigation,
23
+ globals,
24
+ worker,
25
+ ];
26
+ /** Run every recognizer over every node and return the flat list of uses. */
27
+ export function extract(parsed, opts = {}) {
28
+ const origin = opts.origin ?? "first-party";
29
+ annotate(parsed.program);
30
+ const ignores = suppressions(parsed);
31
+ const out = [];
32
+ walk(parsed.program, (visit) => {
33
+ for (const recognize of RECOGNIZERS) {
34
+ const m = recognize(visit);
35
+ if (!m)
36
+ continue;
37
+ // The identifier the match rests on must be a free reference, i.e. the
38
+ // global. A local of the same name is not a use of the capability at
39
+ // all. Inside `with` nothing resolves, so the use is only possible.
40
+ let confidence = m.confidence;
41
+ if (m.via !== null) {
42
+ const via = m.via;
43
+ if (via[AMBIGUOUS])
44
+ confidence = "possible";
45
+ else if (!via[FREE])
46
+ continue;
47
+ }
48
+ if (isFoldedMember(m.node) && confidence === "certain")
49
+ confidence = "probable";
50
+ const expr = enclosingExpression(m.node, visit.ancestors);
51
+ const pos = positionAt(parsed.lines, expr.start);
52
+ out.push({
53
+ capability: m.capability,
54
+ target: m.target,
55
+ file: parsed.file,
56
+ line: pos.line,
57
+ column: pos.column,
58
+ expression: parsed.source.slice(expr.start, expr.end),
59
+ confidence,
60
+ origin,
61
+ suppressed: isSuppressed(ignores.get(pos.line), m.capability),
62
+ });
63
+ }
64
+ });
65
+ return out;
66
+ }
67
+ /** Run the scope analysis and write its answers onto the identifier nodes for the recognizers to read. */
68
+ function annotate(program) {
69
+ const info = analyzeScopes(program);
70
+ for (const n of info.free)
71
+ n[FREE] = true;
72
+ for (const n of info.ambiguous)
73
+ n[AMBIGUOUS] = true;
74
+ for (const [n, v] of info.constants)
75
+ n[FOLDED] = v;
76
+ }
77
+ /**
78
+ * Grow outward from the matched node through the member/call chain it heads,
79
+ * so `localStorage` inside `localStorage.getItem('k').trim()` reports the
80
+ * whole chain.
81
+ */
82
+ function enclosingExpression(node, ancestors) {
83
+ let current = node;
84
+ for (const parent of ancestors) {
85
+ const continues = (parent.type === "MemberExpression" && parent["object"] === current) ||
86
+ (parent.type === "CallExpression" && parent["callee"] === current) ||
87
+ (parent.type === "NewExpression" && parent["callee"] === current) ||
88
+ (parent.type === "ChainExpression" && parent["expression"] === current);
89
+ if (!continues)
90
+ break;
91
+ current = parent;
92
+ }
93
+ return current;
94
+ }
95
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type Recognizer } from "./types.js";
2
+ /**
3
+ * Turning strings into code: eval (direct, indirect, or via the global
4
+ * object), Function only when it is actually called or constructed (a bare
5
+ * `Function` reference such as `instanceof Function` is everywhere and is
6
+ * not codegen), timers only when the first argument is string-valued, and
7
+ * document.write.
8
+ */
9
+ export declare const codegen: Recognizer;
10
+ //# sourceMappingURL=codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../../src/extract/recognizers/codegen.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAM9D;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,UA0BrB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { callArgs, match } from "./types.js";
2
+ import { asGlobalIn, asNamedGlobal, memberName } from "./resolve.js";
3
+ import { leadingLiteral } from "../target.js";
4
+ const CODEGEN_NAMES = new Set(["eval", "Function", "setTimeout", "setInterval"]);
5
+ /**
6
+ * Turning strings into code: eval (direct, indirect, or via the global
7
+ * object), Function only when it is actually called or constructed (a bare
8
+ * `Function` reference such as `instanceof Function` is everywhere and is
9
+ * not codegen), timers only when the first argument is string-valued, and
10
+ * document.write.
11
+ */
12
+ export const codegen = ({ node, ancestors, binding }) => {
13
+ if (binding)
14
+ return null;
15
+ const n = node;
16
+ const parent = ancestors[0];
17
+ if (n.type === "MemberExpression") {
18
+ const prop = memberName(n);
19
+ if (prop === "write" || prop === "writeln") {
20
+ const r = asNamedGlobal(n["object"], "document");
21
+ return r && callArgs(node, parent) ? match("codegen.write", r, node) : null;
22
+ }
23
+ }
24
+ const g = asGlobalIn(n, CODEGEN_NAMES);
25
+ if (!g)
26
+ return null;
27
+ const args = callArgs(node, parent, true);
28
+ switch (g.name) {
29
+ case "eval":
30
+ return match("codegen.eval", g.r, node);
31
+ case "Function":
32
+ return args ? match("codegen.function", g.r, node) : null;
33
+ default: {
34
+ const first = args?.[0];
35
+ return first && leadingLiteral(first) !== null ? match("codegen.timer", g.r, node) : null;
36
+ }
37
+ }
38
+ };
39
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../../src/extract/recognizers/codegen.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAmB,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;AAEtG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAe,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;IAClE,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,CAAC,GAAG,IAAe,CAAC;IAC1B,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAwB,CAAC;IAEnD,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3C,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAY,EAAE,UAAU,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1C,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACxB,OAAO,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5F,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type Recognizer } from "./types.js";
2
+ /**
3
+ * DOM escape hatches: anything that turns a string into markup or creates
4
+ * an element that runs code. The object is not checked - `el.innerHTML = x`
5
+ * is injection whatever `el` is - but only writes and calls count; reading
6
+ * innerHTML is not injection. In JSX, `dangerouslySetInnerHTML` and
7
+ * `srcdoc` attributes and intrinsic `<script>` / `<iframe>` elements count;
8
+ * component names do not.
9
+ */
10
+ export declare const domEscape: Recognizer;
11
+ //# sourceMappingURL=dom-escape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-escape.d.ts","sourceRoot":"","sources":["../../../src/extract/recognizers/dom-escape.ts"],"names":[],"mappings":"AACA,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAelF;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,UAmCvB,CAAC"}