@astrale-os/sdk 0.4.18 → 0.4.19

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 (48) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/run.d.ts.map +1 -1
  3. package/dist/cli/run.js +22 -1
  4. package/dist/cli/run.js.map +1 -1
  5. package/dist/domain/define.d.ts.map +1 -1
  6. package/dist/domain/define.js +2 -1
  7. package/dist/domain/define.js.map +1 -1
  8. package/dist/linter/diagnostic.d.ts +7 -1
  9. package/dist/linter/diagnostic.d.ts.map +1 -1
  10. package/dist/linter/diagnostic.js +3 -1
  11. package/dist/linter/diagnostic.js.map +1 -1
  12. package/dist/linter/index.d.ts +1 -1
  13. package/dist/linter/index.d.ts.map +1 -1
  14. package/dist/linter/index.js.map +1 -1
  15. package/dist/linter/lint.d.ts +2 -0
  16. package/dist/linter/lint.d.ts.map +1 -1
  17. package/dist/linter/lint.js +1 -1
  18. package/dist/linter/lint.js.map +1 -1
  19. package/dist/linter/oxlint/config.d.ts +1 -0
  20. package/dist/linter/oxlint/config.d.ts.map +1 -1
  21. package/dist/linter/oxlint/config.js +5 -0
  22. package/dist/linter/oxlint/config.js.map +1 -1
  23. package/dist/linter/oxlint/ignore-patterns.d.ts +9 -0
  24. package/dist/linter/oxlint/ignore-patterns.d.ts.map +1 -0
  25. package/dist/linter/oxlint/ignore-patterns.js +18 -0
  26. package/dist/linter/oxlint/ignore-patterns.js.map +1 -0
  27. package/dist/linter/oxlint/process.d.ts +19 -0
  28. package/dist/linter/oxlint/process.d.ts.map +1 -0
  29. package/dist/linter/oxlint/process.js +170 -0
  30. package/dist/linter/oxlint/process.js.map +1 -0
  31. package/dist/linter/oxlint/run.d.ts +2 -1
  32. package/dist/linter/oxlint/run.d.ts.map +1 -1
  33. package/dist/linter/oxlint/run.js +36 -26
  34. package/dist/linter/oxlint/run.js.map +1 -1
  35. package/dist/linter/preflight.d.ts.map +1 -1
  36. package/dist/linter/preflight.js +1 -1
  37. package/dist/linter/preflight.js.map +1 -1
  38. package/package.json +12 -5
  39. package/src/cli/run.ts +21 -1
  40. package/src/domain/define.ts +2 -1
  41. package/src/linter/diagnostic.ts +18 -1
  42. package/src/linter/index.ts +1 -0
  43. package/src/linter/lint.ts +3 -1
  44. package/src/linter/oxlint/config.ts +5 -0
  45. package/src/linter/oxlint/ignore-patterns.ts +17 -0
  46. package/src/linter/oxlint/process.ts +219 -0
  47. package/src/linter/oxlint/run.ts +42 -29
  48. package/src/linter/preflight.ts +1 -0
@@ -1,4 +1,3 @@
1
- import { spawn } from 'node:child_process'
2
1
  import { existsSync } from 'node:fs'
3
2
  import { createRequire } from 'node:module'
4
3
  import { dirname, join, relative, resolve, sep } from 'node:path'
@@ -6,6 +5,8 @@ import { fileURLToPath } from 'node:url'
6
5
 
7
6
  import { LinterToolError, type DiagnosticSeverity, type LintDiagnostic } from '../diagnostic.js'
8
7
  import { ruleInfo } from '../rules/catalog.js'
8
+ import { DOMAIN_OXLINT_IGNORE_PATTERNS } from './ignore-patterns.js'
9
+ import { runOxlintProcess, type OxlintProcessOptions } from './process.js'
9
10
 
10
11
  type OxlintOutput = {
11
12
  diagnostics?: OxlintDiagnostic[]
@@ -29,49 +30,46 @@ export type OxlintResult = {
29
30
  files: number
30
31
  }
31
32
 
32
- export async function runOxlint(root: string, fix: boolean): Promise<OxlintResult> {
33
+ export async function runOxlint(
34
+ root: string,
35
+ fix: boolean,
36
+ options: OxlintProcessOptions = {},
37
+ ): Promise<OxlintResult> {
33
38
  const packageJson = join(root, 'package.json')
34
39
  const projectRequire = createRequire(packageJson)
35
40
  const sdkRequire = createRequire(import.meta.url)
36
41
  const oxlintPackage = resolvePackage('oxlint/package.json', projectRequire, sdkRequire)
37
42
  const bin = join(dirname(oxlintPackage), 'bin', 'oxlint')
38
43
  const config = projectConfig(root) ?? internalConfigPath()
39
- const args = [bin, '.', '--format=json', '--no-error-on-unmatched-pattern', '--config', config]
44
+ const args = ['.', '--format=json', '--no-error-on-unmatched-pattern', '--config', config]
45
+ // Config-file ignores are rooted at the config's own directory. Enforce the
46
+ // SDK's traversal boundary at the target process as well so the internal
47
+ // fallback config and imported presets cannot discover dependency/build trees.
48
+ for (const pattern of DOMAIN_OXLINT_IGNORE_PATTERNS) args.push('--ignore-pattern', pattern)
40
49
  if (fix) args.push('--fix')
41
50
 
42
- const child = spawn(process.execPath, args, {
43
- cwd: root,
44
- env: process.env,
45
- stdio: ['ignore', 'pipe', 'pipe'],
46
- })
47
- let stdout = ''
48
- let stderr = ''
49
- child.stdout.setEncoding('utf8')
50
- child.stderr.setEncoding('utf8')
51
- child.stdout.on('data', (chunk: string) => (stdout += chunk))
52
- child.stderr.on('data', (chunk: string) => (stderr += chunk))
53
- const status = await new Promise<number | null>((resolveStatus, reject) => {
54
- child.once('error', reject)
55
- child.once('close', resolveStatus)
56
- }).catch((error: unknown) => {
57
- throw new LinterToolError(`Could not start Oxlint at ${bin}.`, { cause: error })
58
- })
51
+ const { status, signal, stdout, stderr } = await runOxlintProcess(bin, args, root, options)
52
+
53
+ if (status !== 0 && status !== 1) {
54
+ const outcome = signal ? `signal ${signal}` : `status ${status ?? 'unknown'}`
55
+ const detail = failureDetail(stderr, stdout)
56
+ throw new LinterToolError(`Oxlint failed with ${outcome}.${detail ? `\n${detail}` : ''}`, {
57
+ code: 'OXLINT_FAILED',
58
+ })
59
+ }
59
60
 
60
61
  let output: OxlintOutput
61
62
  try {
62
- output = JSON.parse(stdout) as OxlintOutput
63
+ const parsed: unknown = JSON.parse(stdout)
64
+ if (!isOxlintOutput(parsed)) throw new TypeError('Unexpected Oxlint report shape.')
65
+ output = parsed
63
66
  } catch (error) {
64
- const detail =
65
- stderr.trim() || stdout.trim() || `Oxlint exited with status ${status ?? 'unknown'}`
67
+ const detail = failureDetail(stderr, stdout) || `Oxlint exited with status ${status}`
66
68
  throw new LinterToolError(`Oxlint did not produce a diagnostic report.\n${detail}`, {
69
+ code: 'OXLINT_INVALID_OUTPUT',
67
70
  cause: error,
68
71
  })
69
72
  }
70
- if (status !== 0 && status !== 1) {
71
- throw new LinterToolError(
72
- `Oxlint failed with status ${status ?? 'unknown'}.${stderr.trim() ? `\n${stderr.trim()}` : ''}`,
73
- )
74
- }
75
73
 
76
74
  return {
77
75
  diagnostics: (output.diagnostics ?? []).map((diagnostic) =>
@@ -94,12 +92,27 @@ function resolvePackage(
94
92
  } catch {
95
93
  throw new LinterToolError(
96
94
  'Oxlint is not installed. Add the scaffolded Oxlint dev dependency and run your package manager install.',
97
- { cause: projectError },
95
+ { code: 'OXLINT_NOT_INSTALLED', cause: projectError },
98
96
  )
99
97
  }
100
98
  }
101
99
  }
102
100
 
101
+ function isOxlintOutput(value: unknown): value is OxlintOutput {
102
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false
103
+ const output = value as OxlintOutput
104
+ return (
105
+ (output.diagnostics === undefined || Array.isArray(output.diagnostics)) &&
106
+ (output.number_of_files === undefined || typeof output.number_of_files === 'number')
107
+ )
108
+ }
109
+
110
+ function failureDetail(stderr: string, stdout: string): string {
111
+ const detail = stderr.trim() || stdout.trim()
112
+ const limit = 4_000
113
+ return detail.length <= limit ? detail : `…${detail.slice(-limit)}`
114
+ }
115
+
103
116
  function projectConfig(root: string): string | undefined {
104
117
  for (const name of [
105
118
  'oxlint.config.ts',
@@ -45,6 +45,7 @@ export async function assertSingleTypeUniverse(root: string): Promise<void> {
45
45
  throw new LinterToolError(
46
46
  `Multiple physical installations of ${packageName} would create incompatible Astrale types.\n` +
47
47
  `${detail}\nReinstall the workspace so every member resolves one compatible package instance.`,
48
+ { code: 'LINTER_PREFLIGHT_FAILED' },
48
49
  )
49
50
  }
50
51
  }