# fluent-errors-parsing — Methods Reference

## addResource() Error Return

### Signature

```typescript
// @fluent/bundle — FluentBundle method
addResource(
  res: FluentResource,
  options?: { allowOverrides?: boolean }
): Array<Error>
```

### Behavior

- Returns an `Array<Error>` — one error per message/term that had a syntax error
- Valid messages in the same resource are still added to the bundle
- Syntax errors are per-entry, non-blocking — the bundle remains usable
- If `allowOverrides` is `false` (default), duplicate message IDs also produce errors

### Error Array Contents

Each `Error` in the returned array is a standard JavaScript `Error` object with a `message` string describing the parse failure. The error messages are generated by the runtime parser in `@fluent/bundle` and are less detailed than those from `@fluent/syntax`.

### Example

```typescript
import { FluentBundle, FluentResource } from "@fluent/bundle";

const bundle = new FluentBundle("en-US");

const resource = new FluentResource(`
good-message = This parses fine.
bad-message =
	Tab indented — will fail.
another-good = This also parses fine.
duplicate = First definition.
`);

const errors = bundle.addResource(resource);
// errors contains Error for "bad-message"

// Adding a resource with a duplicate
const resource2 = new FluentResource(`duplicate = Second definition.`);
const errors2 = bundle.addResource(resource2);
// errors2 contains Error for duplicate "duplicate" ID

// With allowOverrides
const errors3 = bundle.addResource(resource2, { allowOverrides: true });
// errors3 is empty — override accepted
```

---

## FluentResource Constructor

### Signature

```typescript
// @fluent/bundle
class FluentResource {
  body: Array<Message | Term>;
  constructor(source: string);
}
```

### Parser Characteristics

- Purpose-built runtime parser — smaller and faster than `@fluent/syntax`
- Does NOT produce a full AST — only the minimal structure needed for formatting
- Minimizes false negatives: accepts valid messages with near-perfect accuracy
- May accept some technically invalid structures (false positives)
- Parsing errors produce inaccessible entries — no Junk nodes in `body`

---

## FluentParser (from @fluent/syntax)

### Signature

```typescript
// @fluent/syntax
interface FluentParserOptions {
  withSpans?: boolean; // default: true
}

class FluentParser {
  constructor(options?: FluentParserOptions);
  parse(source: string): Resource;
  parseEntry(source: string): Entry;
}
```

### parse() Method

- Parses a complete FTL document into a `Resource` AST node
- `Resource.body` is `Array<Entry>` where `Entry` is one of: `Message`, `Term`, `Comment`, `GroupComment`, `ResourceComment`, or `Junk`
- Invalid entries become `Junk` nodes with `annotations` array
- With `withSpans: true`, every AST node includes a `Span` with `start` and `end` byte offsets

### parseEntry() Method

- Parses only the first entry from the input string
- Returns `Junk` on failure
- Useful for validating individual messages without parsing an entire file

### Example

```typescript
import { FluentParser } from "@fluent/syntax";

const parser = new FluentParser({ withSpans: true });

// Parse entire file
const resource = parser.parse(ftlSource);

// Parse single entry
const entry = parser.parseEntry("hello = Hello, world!");
// entry.type === "Message"
// entry.id.name === "hello"

const badEntry = parser.parseEntry("123bad = Invalid identifier");
// badEntry.type === "Junk"
```

---

## Junk Type (from @fluent/syntax AST)

### Definition

```typescript
// @fluent/syntax — AST types
class Junk extends Entry {
  type: "Junk";
  content: string;           // The raw text that could not be parsed
  annotations: Annotation[]; // Detailed error information
}
```

### Junk Recovery Rules

From the EBNF grammar:
```
Junk      ::= junk_line (junk_line - "#" - "-" - [a-zA-Z])*
junk_line ::= /[^\n]*/ ("\u000A" | EOF)
```

Junk consumes lines until it encounters a line starting with:
- `#` — potential comment
- `-` — potential term
- A letter `[a-zA-Z]` — potential message

This means the parser recovers at the next valid entry boundary.

---

## Annotation Type (from @fluent/syntax AST)

### Definition

```typescript
// @fluent/syntax — AST types
class Annotation extends SyntaxNode {
  type: "Annotation";
  code: string;              // Error code (e.g., "E0003")
  arguments: Array<unknown>; // Additional error context
  message: string;           // Human-readable error description
  span?: Span;               // Exact position in the source
}
```

### Common Annotation Error Codes

| Code | Meaning |
|------|---------|
| E0003 | Expected token (e.g., missing `=` after identifier) |
| E0004 | Expected character (e.g., missing closing `}`) |
| E0005 | Expected message field (value or attributes) |
| E0006 | Expected term field |
| E0007 | Keyword cannot be used as identifier |
| E0008 | Missing default variant |
| E0012 | Missing value for term |
| E0014 | Expected character in string expression |

### Using Annotations for Diagnostics

```typescript
import { FluentParser } from "@fluent/syntax";

const parser = new FluentParser({ withSpans: true });
const resource = parser.parse(ftlSource);

const diagnostics = [];
for (const entry of resource.body) {
  if (entry.type === "Junk") {
    for (const annotation of entry.annotations) {
      diagnostics.push({
        code: annotation.code,
        message: annotation.message,
        start: annotation.span?.start,
        end: annotation.span?.end,
        content: entry.content.trim(),
      });
    }
  }
}
```

---

## Span Type (from @fluent/syntax AST)

### Definition

```typescript
// @fluent/syntax — AST types
class Span extends BaseNode {
  type: "Span";
  start: number; // Byte offset from start of source
  end: number;   // Byte offset from start of source
}
```

### Usage

Spans are attached to every AST node when `withSpans: true` is set on `FluentParser`. They enable:
- Exact error position reporting in editors
- Source mapping for linting output
- Highlighting the specific character range that caused a parse failure

```typescript
const parser = new FluentParser({ withSpans: true });
const resource = parser.parse(source);

for (const entry of resource.body) {
  if (entry.type === "Junk" && entry.annotations.length > 0) {
    const ann = entry.annotations[0];
    const errorLine = source.substring(0, ann.span!.start).split("\n").length;
    console.error(`Line ${errorLine}: ${ann.message}`);
  }
}
```
