Skip to content

Commit 08da29a

Browse files
Field Access Report: show access paths for all reachable types, including direct root field return types (#109)
* Field Access Report: show access paths for all reachable types, including direct root field return types - Fix bug: direct return types (e.g. Query.employee: Employee) now show access paths - Unified color coding for access paths (red/yellow/green/gray) - Improved UI grouping and badge logic for both root and custom types - Updated docs to reflect new logic and bug fix Tested: All types now display correct access paths and color coding. Lint and type checks pass. * fixed unused exports
1 parent 89846e1 commit 08da29a

39 files changed

+13078
-5
lines changed

docs/architecture.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ The StepZen VS Code extension follows a layered architecture with clear separati
7979
- **SDL Linking**: Traverse `@sdl(files: [...])` directives safely
8080
- **AST Processing**: Parse and analyze GraphQL documents
8181

82+
> **Note:**
83+
> The logic for traversing the schema graph to determine all access paths to a type (used in the Field Access Report) is currently implemented as a utility in the report service. In the future, this may be refactored into the SchemaIndexer or a dedicated schema traversal service for broader reuse and testability. (TODO)
84+
8285
#### 4. VS Code API Layer
8386

8487
- **Integration Points**: Commands, CodeLens, WebViews, Diagnostics

docs/field-policies-feature.md

Lines changed: 574 additions & 0 deletions
Large diffs are not rendered by default.

generate-reports.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright IBM Corp. 2025
3+
* Assisted by CursorAI
4+
*/
5+
6+
const fs = require('fs');
7+
const path = require('path');
8+
9+
// Import the compiled services
10+
const { SchemaIndexService } = require('./out/services/SchemaIndexService');
11+
const { FieldPolicyParser } = require('./out/services/fieldPolicyParser');
12+
const { generateFieldAccessReportData } = require('./out/services/fieldAccessReport');
13+
14+
async function generateReports() {
15+
const fixturesDir = path.join(__dirname, 'src/test/fixtures/field-policies');
16+
const schemaDir = path.join(__dirname, 'src/test/fixtures/schema-sample');
17+
18+
// Set up schema index
19+
const schemaIndex = new SchemaIndexService();
20+
const schemaEntry = path.join(schemaDir, 'index.graphql');
21+
await schemaIndex.scan(schemaEntry);
22+
23+
const policyParser = new FieldPolicyParser();
24+
25+
// Get all YAML fixture files
26+
const fixtureFiles = fs.readdirSync(fixturesDir)
27+
.filter(file => file.endsWith('.yaml'))
28+
.map(file => file.replace('.yaml', ''));
29+
30+
console.log('\n=== FIELD ACCESS REPORT GENERATION ===\n');
31+
32+
for (const fixtureName of fixtureFiles) {
33+
const configPath = path.join(fixturesDir, `${fixtureName}.yaml`);
34+
const configContent = fs.readFileSync(configPath, 'utf8');
35+
36+
console.log(`\n--- ${fixtureName} ---`);
37+
console.log(`Policy Config:`);
38+
console.log(configContent);
39+
40+
try {
41+
const report = await generateFieldAccessReportData(schemaIndex, policyParser, configContent);
42+
43+
console.log(`\nGenerated Report:`);
44+
console.log(JSON.stringify(report, null, 2));
45+
46+
// Check if there's an existing expected report
47+
const expectedReportPath = path.join(fixturesDir, `${fixtureName}.report.json`);
48+
if (fs.existsSync(expectedReportPath)) {
49+
const expectedReport = JSON.parse(fs.readFileSync(expectedReportPath, 'utf8'));
50+
console.log(`\nExisting Expected Report:`);
51+
console.log(JSON.stringify(expectedReport, null, 2));
52+
53+
console.log(`\nMatch: ${JSON.stringify(report) === JSON.stringify(expectedReport) ? 'YES' : 'NO'}`);
54+
} else {
55+
console.log(`\nNo existing expected report found for ${fixtureName}`);
56+
}
57+
58+
} catch (error) {
59+
console.error(`\nError generating report: ${error}`);
60+
}
61+
62+
console.log(`\n${'='.repeat(50)}`);
63+
}
64+
65+
console.log('\n=== END OF REPORT GENERATION ===\n');
66+
}
67+
68+
generateReports().catch(console.error);

package-lock.json

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@
101101
"category": "StepZen"
102102
},
103103
{
104+
"command": "stepzen.createFieldPolicy",
105+
"title": "Create Field Policy",
106+
"category": "StepZen"
107+
},
108+
{
109+
"command": "stepzen.fieldAccessReport",
110+
"title": "Generate Field Access Report",
111+
"category": "StepZen"
112+
},
113+
{
114+
"command": "stepzen.openPolicyEditor",
115+
"title": "Open Policy Editor",
116+
"category": "StepZen"
117+
},
118+
{
119+
"command": "stepzen.createFieldPolicyFromPattern",
120+
"title": "Create Field Policy from Pattern",
104121
"command": "stepzen.lintGraphql",
105122
"title": "Lint GraphQL Schema",
106123
"category": "StepZen"
@@ -250,6 +267,8 @@
250267
}
251268
},
252269
"dependencies": {
253-
"graphql": "^16.11.0"
270+
"@types/js-yaml": "^4.0.9",
271+
"graphql": "^16.11.0",
272+
"js-yaml": "^4.1.0"
254273
}
255274
}

0 commit comments

Comments
 (0)