@ohos-rs/oxk 0.6.0 → 0.7.1
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/bin/format.js +4 -232
- package/bin/oxk.js +14 -0
- package/configuration_schema.json +2530 -16
- package/format.d.ts +12 -0
- package/format.js +24 -2
- package/index.d.ts +13 -0
- package/index.js +236 -76
- package/oxlint-runtime/js_config.cjs +6 -6
- package/oxlint-runtime/plugins.cjs +8 -8
- package/package.json +23 -16
package/bin/format.js
CHANGED
|
@@ -1,236 +1,8 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const path = require('node:path')
|
|
3
|
-
const { glob } = require('glob')
|
|
1
|
+
const { formatFiles: nativeFormatFiles } = require('../format.js')
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const RECOVERABLE_ERROR_PATTERNS = [
|
|
9
|
-
'Unsupported file type',
|
|
10
|
-
'requires external formatter support',
|
|
11
|
-
'External formatter is required',
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
function stripJsonComments(text) {
|
|
15
|
-
let result = ''
|
|
16
|
-
let inString = false
|
|
17
|
-
let stringQuote = ''
|
|
18
|
-
let isEscaped = false
|
|
19
|
-
let inLineComment = false
|
|
20
|
-
let inBlockComment = false
|
|
21
|
-
|
|
22
|
-
for (let index = 0; index < text.length; index += 1) {
|
|
23
|
-
const char = text[index]
|
|
24
|
-
const next = text[index + 1]
|
|
25
|
-
|
|
26
|
-
if (inLineComment) {
|
|
27
|
-
if (char === '\n') {
|
|
28
|
-
inLineComment = false
|
|
29
|
-
result += char
|
|
30
|
-
}
|
|
31
|
-
continue
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (inBlockComment) {
|
|
35
|
-
if (char === '*' && next === '/') {
|
|
36
|
-
inBlockComment = false
|
|
37
|
-
index += 1
|
|
38
|
-
}
|
|
39
|
-
continue
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (inString) {
|
|
43
|
-
result += char
|
|
44
|
-
if (isEscaped) {
|
|
45
|
-
isEscaped = false
|
|
46
|
-
} else if (char === '\\') {
|
|
47
|
-
isEscaped = true
|
|
48
|
-
} else if (char === stringQuote) {
|
|
49
|
-
inString = false
|
|
50
|
-
stringQuote = ''
|
|
51
|
-
}
|
|
52
|
-
continue
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (char === '"' || char === "'") {
|
|
56
|
-
inString = true
|
|
57
|
-
stringQuote = char
|
|
58
|
-
result += char
|
|
59
|
-
continue
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (char === '/' && next === '/') {
|
|
63
|
-
inLineComment = true
|
|
64
|
-
index += 1
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (char === '/' && next === '*') {
|
|
69
|
-
inBlockComment = true
|
|
70
|
-
index += 1
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
result += char
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return result
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function resolveConfigPath(cwd, explicitPath) {
|
|
81
|
-
if (explicitPath) {
|
|
82
|
-
const resolved = path.resolve(cwd, explicitPath)
|
|
83
|
-
if (!existsSync(resolved)) {
|
|
84
|
-
throw new Error(`Failed to read ${resolved}: File not found`)
|
|
85
|
-
}
|
|
86
|
-
return resolved
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let current = cwd
|
|
90
|
-
for (;;) {
|
|
91
|
-
for (const filename of CONFIG_FILES) {
|
|
92
|
-
const candidate = path.join(current, filename)
|
|
93
|
-
if (existsSync(candidate)) {
|
|
94
|
-
return candidate
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const parent = path.dirname(current)
|
|
99
|
-
if (parent === current) {
|
|
100
|
-
return undefined
|
|
101
|
-
}
|
|
102
|
-
current = parent
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function loadConfig(cwd, explicitPath) {
|
|
107
|
-
const configPath = resolveConfigPath(cwd, explicitPath)
|
|
108
|
-
if (!configPath) {
|
|
109
|
-
return { config: {}, ignorePatterns: [] }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const raw = readFileSync(configPath, 'utf8')
|
|
113
|
-
const parsed = JSON.parse(stripJsonComments(raw))
|
|
114
|
-
const ignorePatterns = Array.isArray(parsed.ignorePatterns) ? parsed.ignorePatterns : []
|
|
115
|
-
return { config: parsed, ignorePatterns }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function mergeConfig(baseConfig, cliOptions) {
|
|
119
|
-
return { ...baseConfig, ...cliOptions }
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async function expandPatterns(patterns, cwd) {
|
|
123
|
-
const results = new Set()
|
|
124
|
-
|
|
125
|
-
for (const pattern of patterns) {
|
|
126
|
-
const absolutePattern = path.resolve(cwd, pattern)
|
|
127
|
-
const matches = await glob(absolutePattern, {
|
|
128
|
-
absolute: true,
|
|
129
|
-
dot: true,
|
|
130
|
-
nodir: true,
|
|
131
|
-
follow: false,
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
for (const match of matches) {
|
|
135
|
-
results.add(path.resolve(match))
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return results
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function isRecoverableError(errors) {
|
|
143
|
-
return errors.every((error) => RECOVERABLE_ERROR_PATTERNS.some((pattern) => error.includes(pattern)))
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function runWithConcurrency(items, limit, worker) {
|
|
147
|
-
let index = 0
|
|
148
|
-
const workers = Array.from({ length: Math.max(1, Math.min(limit, items.length || 1)) }, async () => {
|
|
149
|
-
for (;;) {
|
|
150
|
-
const current = index
|
|
151
|
-
index += 1
|
|
152
|
-
if (current >= items.length) {
|
|
153
|
-
return
|
|
154
|
-
}
|
|
155
|
-
await worker(items[current])
|
|
156
|
-
}
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
await Promise.all(workers)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function printErrors(filePath, errors, prefix) {
|
|
163
|
-
console.error(`${prefix} ${filePath}:`)
|
|
164
|
-
for (const error of errors) {
|
|
165
|
-
console.error(` ${error}`)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async function formatFiles({ patterns, configPath, excludes, threadCount, cliOptions }) {
|
|
170
|
-
const cwd = process.cwd()
|
|
171
|
-
|
|
172
|
-
if (patterns.length === 0) {
|
|
173
|
-
throw new Error('Missing file pattern')
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const { config, ignorePatterns } = loadConfig(cwd, configPath)
|
|
177
|
-
const mergedConfig = mergeConfig(config, cliOptions)
|
|
178
|
-
const allExcludes = excludes.concat(ignorePatterns)
|
|
179
|
-
|
|
180
|
-
const files = await expandPatterns(patterns, cwd)
|
|
181
|
-
if (allExcludes.length > 0) {
|
|
182
|
-
const excludedFiles = await expandPatterns(allExcludes, cwd)
|
|
183
|
-
for (const excluded of excludedFiles) {
|
|
184
|
-
files.delete(excluded)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const sortedFiles = Array.from(files).sort()
|
|
189
|
-
if (sortedFiles.length === 0) {
|
|
190
|
-
throw new Error('No files matched the provided patterns (after excludes)')
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
let formattedCount = 0
|
|
194
|
-
let hasRecoverableErrors = false
|
|
195
|
-
let fatalError = null
|
|
196
|
-
|
|
197
|
-
await runWithConcurrency(sortedFiles, threadCount, async (filePath) => {
|
|
198
|
-
if (fatalError) {
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const sourceText = readFileSync(filePath, 'utf8')
|
|
203
|
-
if (sourceText.length === 0) {
|
|
204
|
-
return
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const displayPath = path.relative(cwd, filePath) || filePath
|
|
208
|
-
const result = await format(displayPath, sourceText, mergedConfig)
|
|
209
|
-
|
|
210
|
-
if (result.errors.length === 0) {
|
|
211
|
-
writeFileSync(filePath, result.code, 'utf8')
|
|
212
|
-
console.log(`Formatted: ${displayPath}`)
|
|
213
|
-
formattedCount += 1
|
|
214
|
-
return
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (isRecoverableError(result.errors)) {
|
|
218
|
-
printErrors(displayPath, result.errors, 'Warning formatting')
|
|
219
|
-
hasRecoverableErrors = true
|
|
220
|
-
return
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
fatalError = { filePath: displayPath, errors: result.errors }
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
if (fatalError) {
|
|
227
|
-
printErrors(fatalError.filePath, fatalError.errors, 'Error formatting')
|
|
228
|
-
process.exitCode = 1
|
|
229
|
-
return
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
console.log(`\nFormatted ${formattedCount} file(s)`)
|
|
233
|
-
if (hasRecoverableErrors) {
|
|
3
|
+
async function formatFiles(args) {
|
|
4
|
+
const success = await nativeFormatFiles(args)
|
|
5
|
+
if (!success) {
|
|
234
6
|
process.exitCode = 1
|
|
235
7
|
}
|
|
236
8
|
}
|
package/bin/oxk.js
CHANGED
|
@@ -60,6 +60,8 @@ Format Options:
|
|
|
60
60
|
--config PATH
|
|
61
61
|
--thread, -t THREAD
|
|
62
62
|
--exclude PATTERN
|
|
63
|
+
--ignore-path PATH
|
|
64
|
+
--with-node-modules
|
|
63
65
|
--indent-style STYLE
|
|
64
66
|
--indent-width WIDTH
|
|
65
67
|
--line-ending ENDING
|
|
@@ -94,6 +96,8 @@ function parseFormatArgs(args) {
|
|
|
94
96
|
const formatArgs = {
|
|
95
97
|
patterns: [],
|
|
96
98
|
excludes: [],
|
|
99
|
+
ignorePaths: [],
|
|
100
|
+
withNodeModules: false,
|
|
97
101
|
threadCount: 1,
|
|
98
102
|
configPath: undefined,
|
|
99
103
|
lsp: false,
|
|
@@ -136,6 +140,16 @@ function parseFormatArgs(args) {
|
|
|
136
140
|
index = nextIndex
|
|
137
141
|
break
|
|
138
142
|
}
|
|
143
|
+
case '--ignore-path': {
|
|
144
|
+
const { value, nextIndex } = parseOptionValue(args, index, token)
|
|
145
|
+
formatArgs.ignorePaths.push(value)
|
|
146
|
+
index = nextIndex
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
case '--with-node-modules': {
|
|
150
|
+
formatArgs.withNodeModules = true
|
|
151
|
+
break
|
|
152
|
+
}
|
|
139
153
|
case '--indent-style': {
|
|
140
154
|
const { value, nextIndex } = parseOptionValue(args, index, token)
|
|
141
155
|
if (value !== 'tab' && value !== 'space') {
|