Files
inav/docs/javascript_programming/api_maintenance_guide.md
admin dac37fd077
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s
Sync inav to Gitea
2026-08-03 16:37:40 +08:00

8.9 KiB

API Definition Maintenance Guide

Single Source of Truth

All INAV JavaScript API definitions are centralized in:

js/transpiler/api/definitions/

When adding new INAV features, you only need to edit files in this directory.

Directory Structure

js/transpiler/api/definitions/
├── index.js           # Exports all definitions
├── events.js          # Event handlers (timer, whenChanged, etc.)
├── flight.js          # Flight parameters (read-only)
├── gvar.js            # Global variables (read/write)
├── helpers.js         # Math & utility functions
├── override.js        # Override settings (writable)
├── pid.js             # Programming PID controllers
├── rc.js              # RC channels (read/write)
└── waypoint.js        # Waypoint navigation

Definition Format

Each definition file exports objects following this structure:

module.exports = {
  propertyName: {
    type: 'number' | 'boolean' | 'string' | 'object' | 'function',
    desc: 'Human-readable description',
    unit: 'Unit of measurement (optional)',
    readonly: true | false,
    range: [min, max], // Optional: valid value range
    inavOperand: {
      type: 2,    // OPERAND_TYPE constant
      value: 1    // Operand value for INAV
    },
    inavOperation: 27, // Optional: OPERATION constant
  },
  
  // Nested objects
  nestedObject: {
    type: 'object',
    desc: 'Description',
    properties: {
      subProperty: {
        type: 'number',
        desc: 'Sub-property description',
        // ... same structure as above
      }
    }
  }
};

What Uses These Definitions

1. Semantic Analyzer (analyzer.js)

  • Validates property access
  • Checks writable properties
  • Validates value ranges
  • Auto-updates when definitions change

2. Type Definitions (types.js)

  • Generates TypeScript definitions for Monaco Editor
  • Provides IntelliSense autocomplete
  • Auto-generates from definitions

3. Code Generator (codegen.js)

  • Maps JavaScript to INAV operands
  • Uses inavOperand and inavOperation fields
  • Requires manual update for new operations

4. Decompiler (decompiler.js)

  • Reverse maps INAV to JavaScript
  • Uses operand mappings from API definitions
  • Auto-updates when definitions change

Adding a New Property

Example: Adding flight.compassHeading

1. Edit js/transpiler/api/definitions/flight.js:

module.exports = {
  // ... existing properties ...
  
  compassHeading: {
    type: 'number',
    unit: '°',
    desc: 'Compass heading in degrees (0-359)',
    readonly: true,
    range: [0, 359],
    inavOperand: {
      type: 2,    // OPERAND_TYPE.FLIGHT
      value: 40   // FLIGHT_PARAM.COMPASS_HEADING
    }
  }
};

2. Update inav_constants.js (if needed):

Only if adding a completely new INAV firmware feature:

const FLIGHT_PARAM = {
  // ... existing params ...
  COMPASS_HEADING: 40
};

const FLIGHT_PARAM_NAMES = {
  // ... existing names ...
  [FLIGHT_PARAM.COMPASS_HEADING]: 'compassHeading'
};

3. That's it!

The following automatically update:

  • Semantic analyzer validates flight.compassHeading
  • TypeScript definitions show in autocomplete
  • Range checking works automatically
  • Decompiler recognizes the property

Adding a New Writable Property

Example: Adding override.vtx.frequency

1. Edit js/transpiler/api/definitions/override.js:

module.exports = {
  // ... existing properties ...
  
  vtx: {
    type: 'object',
    desc: 'VTX control',
    properties: {
      power: { /* ... */ },
      band: { /* ... */ },
      channel: { /* ... */ },
      
      // NEW PROPERTY
      frequency: {
        type: 'number',
        unit: 'MHz',
        desc: 'VTX frequency in MHz',
        readonly: false,  // Writable!
        range: [5000, 6000],
        inavOperation: 50  // New operation code
      }
    }
  }
};

2. Update inav_constants.js:

const OPERATION = {
  // ... existing operations ...
  OVERRIDE_VTX_FREQUENCY: 50
};

3. Update codegen.js (manual):

Add code generation logic:

// In generateAction() method
if (stmt.target === 'inav.override.vtx.frequency') {
  return this.pushLogicCommand(
    OPERATION.OVERRIDE_VTX_FREQUENCY,
    { type: OPERAND_TYPE.VALUE, value: 0 },
    this.valueOperand(stmt.value),
    activatorId
  );
}

Adding a New Top-Level API Object

Example: Adding inav.sensors

1. Create js/transpiler/api/definitions/sensors.js:

'use strict';

module.exports = {
  acc: {
    type: 'boolean',
    desc: 'Accelerometer sensor detected',
    readonly: true,
    inavOperand: {
      type: 2,  // FLIGHT
      value: 50 // New param ID
    }
  },
  
  mag: {
    type: 'boolean',
    desc: 'Magnetometer sensor detected',
    readonly: true,
    inavOperand: {
      type: 2,
      value: 51
    }
  }
  
  // ... more sensors
};

2. Update js/transpiler/api/definitions/index.js:

'use strict';

module.exports = {
  flight: require('./inav.flight.js'),
  override: require('./inav.override.js'),
  rc: require('./rc.js'),
  gvar: require('./gvar.js'),
  waypoint: require('./inav.waypoint.js'),
  pid: require('./pid.js'),
  helpers: require('./helpers.js'),
  events: require('./events.js'),
  sensors: require('./sensors.js')  // ADD THIS
};

3. Update TypeScript types in types.js generation:

The type generator should automatically pick it up, but verify:

// In generateTypeDefinitions()
dts += generateInterfaceFromDefinition('sensors', apiDefinitions.sensors);

Validation Checklist

When adding/modifying API definitions:

  • Property has correct type
  • Has descriptive desc
  • Has unit if applicable
  • readonly flag is correct
  • range is specified for numeric values
  • inavOperand maps to correct INAV constant
  • inavOperation specified for writable properties
  • Updated index.js if new file
  • Updated inav_constants.js if new INAV feature
  • Updated codegen.js for new writable properties
  • Tested with sample code
  • TypeScript definitions generate correctly

Testing Changes

After modifying definitions:

// 1. Test semantic analysis
const code = `
if (sensors.acc) {
  // ...
}
`;

const transpiler = new Transpiler();
const result = transpiler.transpile(code);
// Should not have errors

// 2. Test type generation
const { generateTypeDefinitions } = require('./api/types.js');
const dts = generateTypeDefinitions(apiDefinitions);
// Should include new properties

// 3. Test in Monaco Editor
// Open configurator, verify autocomplete shows new properties

Common Mistakes

Wrong: Editing analyzer.js directly

// DON'T DO THIS in analyzer.js:
this.inavAPI = {
  'flight': {
    properties: ['homeDistance', 'newProperty']  // Hard-coded!
  }
};

Right: Edit definition file

// DO THIS in inav.flight.js:
module.exports = {
  newProperty: {
    type: 'number',
    desc: 'New property',
    // ...
  }
};

Wrong: Duplicating definitions

// DON'T duplicate in multiple files
// decompiler.js - NO!
const FLIGHT_PARAMS = {
  1: 'homeDistance'
};

// analyzer.js - NO!
properties: ['homeDistance']

Right: Use centralized definitions

// DO THIS - import from definitions
const apiDefinitions = require('./../api/definitions/index.js');
const flightDef = apiDefinitions.flight;

File Dependencies

js/transpiler/api/definitions/
  ├── index.js
  ├── events.js
  ├── flight.js
  ├── gvar.js
  ├── helpers.js
  ├── override.js
  ├── pid.js
  ├── rc.js
  └── waypoint.js
       ↓
       Used by:
       ├── analyzer.js (validation)
       ├── types.js (TypeScript generation)
       ├── codegen.js (code generation)
       └── decompiler.js (via inav_constants.js)

Migration from Hardcoded Values

If you find hardcoded API definitions elsewhere in the code:

  1. Identify the hardcoded values
  2. Check if they exist in api/definitions/
  3. If not, add them to appropriate definition file
  4. Replace hardcoded values with imports
  5. Test thoroughly
  6. Remove old hardcoded definitions

Example:

// Before (hardcoded in analyzer.js)
this.inavAPI = {
  'flight': {
    properties: ['homeDistance', 'altitude']
  }
};

// After (using definitions)
const apiDefinitions = require('./../api/definitions/index.js');
this.inavAPI = this.buildAPIStructure(apiDefinitions);

Summary

One Rule: Edit only js/transpiler/api/definitions/*.js

Everything else updates automatically (except codegen.js which requires manual updates for new operations).

This ensures:

  • Single source of truth
  • No duplication
  • Easy maintenance
  • Fewer bugs
  • Automatic validation
  • Automatic type generation