@getfoyer/review-core 0.1.0 → 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.
@@ -0,0 +1,14 @@
1
+ import type { PlanRepoContext } from '@getfoyer/client';
2
+ export declare const PATH_BACKTICK_RE: RegExp;
3
+ export declare const SYMBOL_BACKTICK_RE: RegExp;
4
+ export declare const NOISE_PATH_PREFIXES: string[];
5
+ export declare const EXTENSIONLESS_TOP_LEVEL: Set<string>;
6
+ export declare const STOP_WORDS: Set<string>;
7
+ export declare function buildRepoContext(planText: string, cwd: string): Promise<PlanRepoContext>;
8
+ export declare function extractReferencedPaths(text: string): string[];
9
+ export declare function extractReferencedSymbols(text: string): string[];
10
+ export declare function fileExists(absPath: string): Promise<boolean>;
11
+ export declare function gitGrepExists(needle: string, cwd: string): boolean;
12
+ export declare function collectNearbyTests(paths: string[], cwd: string): string[];
13
+ export declare function detectLanguages(cwd: string): string[];
14
+ //# sourceMappingURL=plan-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-context.d.ts","sourceRoot":"","sources":["../src/plan-context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,eAAO,MAAM,gBAAgB,QAAkO,CAAC;AAChQ,eAAO,MAAM,kBAAkB,QAAkD,CAAC;AAElF,eAAO,MAAM,mBAAmB,UAA4C,CAAC;AAE7E,eAAO,MAAM,uBAAuB,aAGlC,CAAC;AAEH,eAAO,MAAM,UAAU,aAGrB,CAAC;AAEH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAsB9F;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAe7D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAa/D;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAUlE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBzE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBrD"}
@@ -0,0 +1,133 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { access } from 'node:fs/promises';
4
+ import { dirname, join, relative, resolve } from 'node:path';
5
+ export const PATH_BACKTICK_RE = /`((?:[./A-Za-z0-9_\-]+\.[A-Za-z0-9]{1,8})|(?:[./A-Za-z0-9_\-]*\/[A-Za-z0-9_.\-]+)|(?:Dockerfile|Makefile|Rakefile|Gemfile|Procfile|LICENSE|README|CHANGELOG|NOTICE|AUTHORS|CONTRIBUTORS|VERSION|\.[A-Za-z][A-Za-z0-9_\-]*))`/g;
6
+ export const SYMBOL_BACKTICK_RE = /`([A-Za-z_][A-Za-z0-9_]{2,})(?:\([^`)]*\))?`/g;
7
+ export const NOISE_PATH_PREFIXES = ['http://', 'https://', '/', './', '../'];
8
+ export const EXTENSIONLESS_TOP_LEVEL = new Set([
9
+ 'Dockerfile', 'Makefile', 'Rakefile', 'Gemfile', 'Procfile',
10
+ 'LICENSE', 'README', 'CHANGELOG', 'NOTICE', 'AUTHORS', 'CONTRIBUTORS', 'VERSION',
11
+ ]);
12
+ export const STOP_WORDS = new Set([
13
+ 'and', 'the', 'for', 'with', 'this', 'that', 'from', 'into', 'onto',
14
+ 'json', 'null', 'true', 'false', 'TODO', 'FIXME', 'NOTE',
15
+ ]);
16
+ export async function buildRepoContext(planText, cwd) {
17
+ const referencedPaths = extractReferencedPaths(planText);
18
+ const referencedSymbols = extractReferencedSymbols(planText);
19
+ const files = await Promise.all(referencedPaths.map(async (path) => ({
20
+ path,
21
+ exists: await fileExists(resolve(cwd, path)),
22
+ })));
23
+ const symbols = await Promise.all(referencedSymbols.map(async (name) => ({
24
+ name,
25
+ foundInRepo: gitGrepExists(name, cwd),
26
+ })));
27
+ const nearbyTests = collectNearbyTests(referencedPaths, cwd);
28
+ const languages = detectLanguages(cwd);
29
+ return { files, symbols, nearbyTests, languages };
30
+ }
31
+ export function extractReferencedPaths(text) {
32
+ const seen = new Set();
33
+ PATH_BACKTICK_RE.lastIndex = 0;
34
+ let m;
35
+ while ((m = PATH_BACKTICK_RE.exec(text)) !== null) {
36
+ const raw = m[1];
37
+ if (NOISE_PATH_PREFIXES.some((p) => raw.startsWith(p)))
38
+ continue;
39
+ const hasSlash = raw.includes('/');
40
+ const looksLikeVersion = /^\d+\.\d+(\.\d+)?$/.test(raw);
41
+ const isKnownTopLevel = EXTENSIONLESS_TOP_LEVEL.has(raw) || raw.startsWith('.');
42
+ if ((!hasSlash && !isKnownTopLevel) || looksLikeVersion)
43
+ continue;
44
+ seen.add(raw);
45
+ if (seen.size >= 50)
46
+ break;
47
+ }
48
+ return Array.from(seen);
49
+ }
50
+ export function extractReferencedSymbols(text) {
51
+ const seen = new Set();
52
+ SYMBOL_BACKTICK_RE.lastIndex = 0;
53
+ let m;
54
+ while ((m = SYMBOL_BACKTICK_RE.exec(text)) !== null) {
55
+ const raw = m[1];
56
+ if (raw.includes('/') || raw.includes('.'))
57
+ continue;
58
+ if (raw.length < 3 || raw.length > 64)
59
+ continue;
60
+ if (STOP_WORDS.has(raw))
61
+ continue;
62
+ seen.add(raw);
63
+ if (seen.size >= 50)
64
+ break;
65
+ }
66
+ return Array.from(seen);
67
+ }
68
+ export async function fileExists(absPath) {
69
+ try {
70
+ await access(absPath);
71
+ return true;
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
77
+ export function gitGrepExists(needle, cwd) {
78
+ try {
79
+ execSync(`git grep -l --fixed-strings --word-regexp -- ${JSON.stringify(needle)}`, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
80
+ return true;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ }
86
+ export function collectNearbyTests(paths, cwd) {
87
+ const seen = new Set();
88
+ for (const path of paths) {
89
+ const dir = dirname(resolve(cwd, path));
90
+ for (const candidate of [join(dir, '__tests__'), dir]) {
91
+ let entries;
92
+ try {
93
+ entries = readdirSync(candidate, { withFileTypes: true, encoding: 'utf8' });
94
+ }
95
+ catch {
96
+ continue;
97
+ }
98
+ for (const entry of entries) {
99
+ if (!entry.isFile())
100
+ continue;
101
+ if (!/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(entry.name))
102
+ continue;
103
+ const rel = relative(cwd, join(candidate, entry.name));
104
+ seen.add(rel);
105
+ if (seen.size >= 30)
106
+ return Array.from(seen);
107
+ }
108
+ }
109
+ }
110
+ return Array.from(seen);
111
+ }
112
+ export function detectLanguages(cwd) {
113
+ const langs = [];
114
+ for (const [file, lang] of [
115
+ ['package.json', 'JavaScript/TypeScript'],
116
+ ['tsconfig.json', 'TypeScript'],
117
+ ['pyproject.toml', 'Python'],
118
+ ['requirements.txt', 'Python'],
119
+ ['go.mod', 'Go'],
120
+ ['Cargo.toml', 'Rust'],
121
+ ['Gemfile', 'Ruby'],
122
+ ['composer.json', 'PHP'],
123
+ ]) {
124
+ if (existsSync(join(cwd, file)))
125
+ langs.push(lang);
126
+ }
127
+ const unique = [];
128
+ for (const l of langs)
129
+ if (!unique.includes(l))
130
+ unique.push(l);
131
+ return unique;
132
+ }
133
+ //# sourceMappingURL=plan-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-context.js","sourceRoot":"","sources":["../src/plan-context.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getfoyer/review-core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Frozen contract for Foyer run artifacts (RunArtifact v0.1) — the shared shape consumed by the GitHub App, the CLI, the hosted report, and PR-comment writers.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,6 +13,10 @@
13
13
  "./types": {
14
14
  "types": "./dist/types.d.ts",
15
15
  "import": "./dist/types.js"
16
+ },
17
+ "./plan-context": {
18
+ "types": "./dist/plan-context.d.ts",
19
+ "import": "./dist/plan-context.js"
16
20
  }
17
21
  },
18
22
  "files": [
@@ -28,7 +32,11 @@
28
32
  "build": "tsc",
29
33
  "typecheck": "tsc --noEmit"
30
34
  },
35
+ "dependencies": {
36
+ "@getfoyer/client": "0.1.3"
37
+ },
31
38
  "devDependencies": {
39
+ "@types/node": "^22.0.0",
32
40
  "typescript": "^5.5.0"
33
41
  }
34
42
  }