All files lintAssemblyInstructions.ts

90% Statements 18/20
81.25% Branches 13/16
100% Functions 2/2
94.44% Lines 17/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                          8x   8x       8x   8x 7x   7x 2x 2x   2x   2x     7x 7x 8x   8x         8x 2x     7x    
import type { HydratedLintIssue } from './alphalib/assembly-linter.lang.en.ts'
import { hydrateLintIssues } from './alphalib/assembly-linter.lang.en.ts'
import { applyFix, parseAndLint } from './alphalib/assembly-linter.ts'
import type { AssemblyInstructionsInput, StepsInput } from './alphalib/types/template.ts'
import type { ResponseTemplateContent, TemplateContent } from './apiTypes.ts'
import { buildLintInput, unwrapStepsOnly } from './lintAssemblyInput.ts'
 
export type LintFatalLevel = 'error' | 'warning'
 
export interface LintAssemblyInstructionsInput {
  /**
   * Assembly Instructions as a JSON string, a full instructions object, or a steps-only object.
   */
  assemblyInstructions?: AssemblyInstructionsInput | StepsInput | string
  /**
   * Optional template content to merge with the provided instructions.
   */
  template?: TemplateContent | ResponseTemplateContent
  /**
   * Treat issues at this level or above as fatal. Defaults to "error".
   */
  fatal?: LintFatalLevel
  /**
   * Apply auto-fixes where possible and return the fixed JSON.
   */
  fix?: boolean
}
 
export interface LintAssemblyInstructionsResult {
  success: boolean
  issues: HydratedLintIssue[]
  fixedInstructions?: string
}
 
export async function lintAssemblyInstructions(
  options: LintAssemblyInstructionsInput,
): Promise<LintAssemblyInstructionsResult> {
  const { assemblyInstructions, template, fix = false, fatal = 'error' } = options
 
  Iif (assemblyInstructions == null && template == null) {
    throw new Error('Provide assemblyInstructions or template content to lint.')
  }
 
  const { lintContent, wasStepsOnly, indent } = buildLintInput(assemblyInstructions, template)
 
  let issues = await parseAndLint(lintContent)
  let fixedContent = lintContent
 
  if (fix) {
    for (const issue of issues) {
      Iif (!issue.fixId) continue
      // applyFix validates fixData against the fix schema for the fixId.
      fixedContent = applyFix(fixedContent, issue.fixId, issue.fixData as never)
    }
    issues = await parseAndLint(fixedContent)
  }
 
  const describedIssues = hydrateLintIssues(issues)
  const fatalTypes = fatal === 'warning' ? new Set(['warning', 'error']) : new Set(['error'])
  const success = !describedIssues.some((issue) => fatalTypes.has(issue.type))
 
  const result: LintAssemblyInstructionsResult = {
    success,
    issues: describedIssues,
  }
 
  if (fix) {
    result.fixedInstructions = wasStepsOnly ? unwrapStepsOnly(fixedContent, indent) : fixedContent
  }
 
  return result
}