All files lintAssemblyInstructions.ts

93.75% Statements 30/32
78.57% Branches 11/14
100% Functions 1/1
93.75% Lines 30/32

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  1x 1x     1x                                                         8x 8x 8x 8x   8x       8x   8x 7x   8x 2x 2x   2x 2x 2x 2x   7x 8x 8x   8x 8x 8x 8x   8x 2x 2x   7x 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
 
  if (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) {
      if (!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
}