-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck-ascii-docs.ts
More file actions
120 lines (96 loc) · 3.17 KB
/
check-ascii-docs.ts
File metadata and controls
120 lines (96 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env tsx
/**
* ASCII Doc Checker
*
* Cursor Notes:
* - Created 2025-11-13 per Codex collaboration prompt
* - Walks docs/ directory and flags non-ASCII characters
* - Helps maintain ASCII-only documentation per collaboration requirements
*
* Usage:
* npx tsx scripts/check-ascii-docs.ts
*
* Output:
* Prints filename:line for each non-ASCII character found
*/
import { readdirSync, readFileSync, statSync } from 'fs'
import { join } from 'path'
function isASCII(str: string): boolean {
return /^[\x00-\x7F]*$/.test(str)
}
function walkDirectory(dirPath: string, fileList: string[] = []): string[] {
const entries = readdirSync(dirPath)
for (const entry of entries) {
const fullPath = join(dirPath, entry)
const stat = statSync(fullPath)
if (stat.isDirectory()) {
// Skip node_modules, .git, etc.
if (!entry.startsWith('.') && entry !== 'node_modules') {
walkDirectory(fullPath, fileList)
}
} else if (stat.isFile() && entry.endsWith('.md')) {
fileList.push(fullPath)
}
}
return fileList
}
function checkFile(filePath: string): Array<{ line: number; snippet: string }> {
const issues: Array<{ line: number; snippet: string }> = []
try {
const content = readFileSync(filePath, 'utf-8')
const lines = content.split('\n')
lines.forEach((line, index) => {
if (!isASCII(line)) {
// Find non-ASCII characters and create snippet
const nonAsciiChars: string[] = []
for (let i = 0; i < line.length; i++) {
if (line.charCodeAt(i) > 127) {
nonAsciiChars.push(line[i])
}
}
// Create snippet (first 80 chars, truncate if longer)
const snippet = line.length > 80 ? line.substring(0, 77) + '...' : line
issues.push({
line: index + 1,
snippet: snippet.trim(),
})
}
})
} catch (error) {
console.error(`Error reading ${filePath}: ${error instanceof Error ? error.message : String(error)}`)
}
return issues
}
function main() {
const docsPath = join(process.cwd(), 'docs')
const files = walkDirectory(docsPath)
console.log(`Checking ${files.length} markdown files in docs/ for non-ASCII characters...`)
console.log('')
let totalIssues = 0
let filesWithIssues = 0
for (const filePath of files) {
const issues = checkFile(filePath)
if (issues.length > 0) {
filesWithIssues++
totalIssues += issues.length
const relativePath = filePath.replace(process.cwd() + '\\', '').replace(process.cwd() + '/', '')
console.log(`${relativePath}:`)
issues.forEach(({ line, snippet }) => {
console.log(` Line ${line}: ${snippet}`)
})
console.log('')
}
}
console.log('='.repeat(80))
console.log(`Files checked: ${files.length}`)
console.log(`Files with non-ASCII: ${filesWithIssues}`)
console.log(`Total issues: ${totalIssues}`)
if (totalIssues === 0) {
console.log('✓ All documentation files are ASCII-only')
process.exit(0)
} else {
console.log(`⚠ Found ${totalIssues} line(s) with non-ASCII characters`)
process.exit(1)
}
}
main()