npm package: @jrc03c/gtlint
Description: A linter and formatter for the GuidedTrack language
Author: jrc03c
Latest version: 0.15.2

# GTLint ✨

**GTLint** is a linter, formatter, and syntax highlighter for the [GuidedTrack](https://guidedtrack.com) language, inspired by ESLint and Prettier. It can be used at the command line or installed as a VSCode extension.

- [Overview](#overview)
- [Disclaimer](#disclaimer)
- [VSCode extension](#vscode-extension)
  - [Installation](#installation)
  - [Usage](#usage)
- [Command line](#command-line)
  - [Installation](#installation-1)
  - [Usage](#usage-1)
- [Behavior](#behavior)
  - [Linter](#lint-rules)
  - [Formatter](#formatter)
- [Configuration](#configuration) (i.e., project-wide settings)
- [Directives](#directives) (i.e., inline settings)
- [Tests](#tests)
- [License](#license)

![VSCode extension](https://github.com/user-attachments/assets/71fc166f-1980-4e2d-a84f-41188f6e0dbe)

![CLI tool](https://github.com/user-attachments/assets/06734d44-794c-475c-b5e2-c389a5f5a34c)

# Overview

GTLint's **linter** flags these things:

- unrecognized keywords
- invalid sub-keywords
- invalid keyword arguments
- missing required sub-keywords
- empty blocks (e.g., `*if: 0 < 1` without a body)
- undefined variables
- unused variables
- nonexistent labels
- duplicate labels
- unused labels
- unreachable code
- unclosed strings
- unclosed brackets
- stray colons in expressions (e.g., `*if: 0 < 1:`)
- single quotes instead of double quotes around string literals
- spaces instead of tabs for indentation
- incorrect indentation levels

GTLint's **formatter** does these things:

- trims trailing whitespace (per-line)
- collapses consecutive empty lines
- adds spaces around operators (e.g., `+`, `=`, `>`, etc.)
- adds spaces around arrows (`->`) in associations
- adds spaces after commas in collections and associations
- normalizes spacing immediately inside braces, brackets, and parens
- normalizes `>>` to be followed by a single space
- collapses runs of whitespace in expressions

Virtually all of these behaviors can be modified by using a [configuration](#configuration) file and/or inline [directives](#directives).

# Disclaimer

This tool was written almost exclusively by [Claude Code](https://claude.com/product/claude-code). [Josh Castle](https://github.com/jrc03c) directed Claude Code and made a few small changes to `CLAUDE.md`, `README.md`, and the GuidedTrack files in the `samples` directory; but virtually everything else was written by Claude Code.

# VSCode extension

## Installation

(1) Download the `.vsix` file from here:

[https://github.com/jrc03c/gtlint/releases/latest/download/gtlint.vsix](https://github.com/jrc03c/gtlint/releases/latest/download/gtlint.vsix)

(2) In VSCode, open the command palette and search for "vsix":

![](https://github.com/user-attachments/assets/03128194-04c5-4991-9acd-e9efb3e38ec9)

Select "Extensions: Install from VSIX...".

(3) Select the `gtlint.vsix` file that you downloaded in the first step.

## Usage

The linter works while you write code in `.gt` files and will show errors as soon as it detects them. The formatter will format code in `.gt` files on save.

### Auto-complete

The extension provides context-aware auto-complete:

- **Keywords** — Type `*` at the start of a line to see available keywords. When indented under a parent keyword (e.g., `*question`), the sub-keywords for that parent are shown first (e.g., `*type`, `*save`, `*shuffle`), followed by all top-level keywords.
- **Methods** — Type `.` after a variable name to see all built-in GuidedTrack methods (e.g., `.size`, `.uppercase`, `.add()`). Methods are shown with their applicable type(s) and snippets with tab stops for parameters.

See the [Configuration](#configuration) section below for more info about how to control the extension's behavior.

# Command Line

## Installation

> **NOTE:** Requires [Node](https://nodejs.org/en).

In a specific project:

```bash
npm install --save-dev @jrc03c/gtlint
```

Or globally:

```bash
npm install -g @jrc03c/gtlint
```

## Usage

> **NOTE:** When installed in a specific project, GTLint must be invoked with `npx gtlint`. When installed globally, it can be invoked with just `gtlint`. The examples below assume that it has been installed in a specific project.

**Syntax:**

```
# lint:
npx gtlint lint [options] [files]

# format:
npx gtlint format [options] [files]
```

**Show help:**

```bash
npx gtlint
```

**Lint:**

```bash
# show errors and warnings in a particular file
npx gtlint lint path/to/some-file.gt

# show all errors and warnings in all *.gt files in a directory (recursive)
npx gtlint lint path/to/some-dir
```

**Format:**

```bash
# format a specific file
npx gtlint format path/to/some-file.gt

# format all *.gt files in a directory (recursive)
npx gtlint format path/to/some-dir
```

See the [Configuration](#configuration) section below for more info about how to control the command line tool's behavior.

# Configuration

The linter's and formatter's default behaviors can be controlled by settings in a `gtlint.config.js` file at the root of a repository. Here's a sample configuration file containing all of the default values:

```js
export default {
  // files to ignore (glob patterns, relative to project root)
  ignore: [
    "**/node_modules/**", // ignored by default
    "**/dist/**",         // ignored by default
    "path/to/some-file.gt",
    "**/scratch/**",
  ],

  // formatter settings
  format: {
    insertFinalNewline: true,
    spaceAfterComma: true,
    spaceAroundArrow: true,
    spaceAroundOperators: true,
    spaceInsideBraces: 0,
    spaceInsideBrackets: 0,
    spaceInsideParens: 0,
    trimTrailingWhitespace: true,
  },

  // linter settings
  lint: {
    correctIndentation: "error",
    gotoNeedsResetInEvents: "warn",
    indentStyle: "error",
    noDuplicateLabels: "error",
    noEmptyBlocks: "error",
    noInlineArgument: "error",
    noInvalidGoto: "error",
    noSingleQuotes: "error",
    noStrayColon: "error",
    noUnclosedBracket: "error",
    noUnclosedString: "error",
    noUndefinedVars: "error",
    noUnreachableCode: "warn",
    noUnusedLabels: "warn",
    noUnusedVars: "warn",
    purchaseSubkeywordConstraints: "error",
    requiredSubkeywords: "error",
    validKeyword: "error",
    validSubKeyword: "error",
    validSubkeywordValue: "error",
  },
}
```

When `ignore` is not specified, `**/node_modules/**` and `**/dist/**` are ignored by default. Specifying `ignore` replaces these defaults, so include them explicitly if you still want them ignored. Ignore patterns apply to both `lint` and `format` commands.

Lint rules can have these values:

- `"off"` or `0` - Disable the rule
- `"warn"` or `1` - Show as warning (doesn't fail linting)
- `"error"` or `2` - Show as error (fails linting)

# Directives

The linter's and formatter's behaviors can also be overridden by inline _directives_ written directly into `.gt` files. Directives are always commented out. For example:

```
-- @to-child: email_address
>> email_address = "someone@example.com"
*program: Add to Mailing List
```

Here are the available directives and what they do:

**Combined (lint + format):**

- **`@gt-disable`**<br>
  Disable lint + format until `@gt-enable` or EOF

- **`@gt-enable`**<br>
  Re-enable lint + format

- **`@gt-disable-next-line`**<br>
  Disable lint + format for next line only

- **`@gt-disable-next-line rule1, rule2`**<br>
  Disable specific lint rules + format for next line

**Lint-only:**

- **`@gtlint-disable`**<br>
  Disable all lint rules until `@gtlint-enable` or EOF

- **`@gtlint-disable rule1, rule2`**<br>
  Disable specific lint rules

- **`@gtlint-enable`**<br>
  Re-enable all lint rules

- **`@gtlint-enable rule1`**<br>
  Re-enable specific lint rule

- **`@gtlint-disable-next-line`**<br>
  Disable all lint rules for next line

- **`@gtlint-disable-next-line rule1, rule2`**<br>
  Disable specific rules for next line

- **`@from-child: var1, var2, ...`**<br>
  Do not mark listed variables as undefined (because they are defined in a child program); warns if a listed variable is never used

- **`@from-parent: var1, var2, ...`**<br>
  Do not mark listed variables as undefined (because they are defined in a parent program); warns if a listed variable is never used or if its value is overwritten before being read

- **`@from-url: var1, var2, ...`**<br>
  Do not mark listed variables as undefined (because they are defined in URL query string parameters); warns if a listed variable is never used or if its value is overwritten before being read

- **`@to-child: var1, var2, ...`**<br>
  Do not mark listed variables as unused (because they will be used in a child program)

- **`@to-parent: var1, var2, ...`**<br>
  Do not mark listed variables as unused (because they will be used in a parent program)

- **`@to-csv: var1, var2, ...`**<br>
  Do not mark listed variables as unused (because they will be saved in the root program's CSV)

> **NOTE:** Inline directive rule names always use kebab-case (e.g., `no-unused-vars`), even though config files use camelCase.

**Format-only:**

- **`@gtformat-disable`**<br>
  Disable formatting until `@gtformat-enable` or EOF

- **`@gtformat-enable`**<br>
  Re-enable formatting

> **NOTE:** `@gtformat-*` directives don't support rule lists since formatting isn't rule-based.

# Tests

```bash
pnpm test
```

The test suite includes integration tests that exercise real GuidedTrack programs from a git submodule (`submodules/gt-lib`). This submodule points to a private repository and is optional. If it's not initialized, those tests are skipped automatically. All other tests will run normally.

# Feedback

If you run into bugs or have feature requests, please [open an issue](https://github.com/jrc03c/gtlint/issues).

# License

MIT