diff --git a/docs/AST.md b/docs/AST.md index 02c280c..ed10d47 100644 --- a/docs/AST.md +++ b/docs/AST.md @@ -217,7 +217,7 @@ interface YAMLDocument extends Node { directives: YAMLDirective[] content: YAMLMapping | YAMLSequence | YAMLScalar | YAMLAlias | YAMLWithMeta | null parent: YAMLProgram - anchors: { [key: string]: YAMLAnchor } + anchors: { [key: string]: YAMLAnchor[] } } ``` diff --git a/src/ast.ts b/src/ast.ts index 1855f85..8e386b3 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -64,7 +64,7 @@ export interface YAMLDocument extends BaseYAMLNode { directives: YAMLDirective[] content: YAMLContent | YAMLWithMeta | null parent: YAMLProgram - anchors: { [key: string]: YAMLAnchor } + anchors: { [key: string]: YAMLAnchor[] } } export interface YAMLDirective extends BaseYAMLNode { diff --git a/src/convert.ts b/src/convert.ts index 6d7743c..ac6749a 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -930,7 +930,8 @@ function convertAnchor( ...loc, } - doc.anchors[value] = ast + const anchors = doc.anchors[value] || (doc.anchors[value] = []) + anchors.push(ast) const text = code.slice(...loc.range) if (text.startsWith("&")) { diff --git a/src/utils.ts b/src/utils.ts index 937058f..2800a84 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -146,7 +146,26 @@ function findAnchor(node: YAMLAlias): YAMLAnchor | null { } p = p.parent } - return doc!.anchors[node.name] || null + const anchors = doc!.anchors[node.name] + if (!anchors) { + return null + } + let target: { anchor: null | YAMLAnchor; distance: number } = { + anchor: null, + distance: Infinity, + } + for (const anchor of anchors) { + if (anchor.range[0] < node.range[0]) { + const distance = node.range[0] - anchor.range[0] + if (target.distance >= distance) { + target = { + anchor, + distance, + } + } + } + } + return target.anchor } /** diff --git a/tests/fixtures/parser/yaml-test-suite/3GZX-value.json b/tests/fixtures/parser/yaml-test-suite/3GZX-value.json index abb6c58..14de930 100644 --- a/tests/fixtures/parser/yaml-test-suite/3GZX-value.json +++ b/tests/fixtures/parser/yaml-test-suite/3GZX-value.json @@ -1,6 +1,6 @@ { "First occurrence": "Foo", - "Second occurrence": "Bar", + "Second occurrence": "Foo", "Override anchor": "Bar", "Reuse anchor": "Bar" } \ No newline at end of file diff --git a/tests/src/parser/eslint.ts b/tests/src/parser/eslint.ts new file mode 100644 index 0000000..9609f86 --- /dev/null +++ b/tests/src/parser/eslint.ts @@ -0,0 +1,44 @@ +import { Linter } from "eslint" +import assert from "assert" +import * as parser from "../../../src/index" + +function createLinter() { + const linter = new Linter() + + linter.defineParser("yaml-eslint-parser", parser as any) + linter.defineRule("test", { + create(context) { + return { + YAMLDocument(node: any) { + context.report({ + node, + message: "test", + }) + }, + } + }, + }) + + return linter +} + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +describe("eslint custom parser", () => { + it("should work with eslint.", () => { + const code = `Hello!` + + const linter = createLinter() + const messages = linter.verify(code, { + parser: "yaml-eslint-parser", + rules: { + test: "error", + }, + }) + + assert.strictEqual(messages.length, 1) + assert.strictEqual(messages[0].message, "test") + }) +}) diff --git a/tests/src/parser/parser.ts b/tests/src/parser/parser.ts index cbf42b1..a584f1b 100644 --- a/tests/src/parser/parser.ts +++ b/tests/src/parser/parser.ts @@ -2,11 +2,11 @@ import assert from "assert" import path from "path" import fs from "fs" -import { parseForESLint } from "../../../src/parser" import { KEYS } from "../../../src/visitor-keys" import { traverseNodes, getKeys } from "../../../src/traverse" import { getStaticYAMLValue } from "../../../src/utils" import type { YAMLProgram } from "../../../src/ast" +import { parseYAML } from "../../../src" const AST_FIXTURE_ROOT = path.resolve(__dirname, "../../fixtures/parser/ast") const SUITE_FIXTURE_ROOT = path.resolve( @@ -32,7 +32,7 @@ function replacer(key: string, value: any) { } function parse(code: string) { - return parseForESLint(code, {}) + return parseYAML(code) } describe("Check for AST.", () => { @@ -51,7 +51,7 @@ describe("Check for AST.", () => { ) const input = fs.readFileSync(inputFileName, "utf8") - const ast = parse(input).ast + const ast = parse(input) const astJson = JSON.stringify(ast, replacer, 2) const output = fs.readFileSync(outputFileName, "utf8") assert.strictEqual(astJson, output) @@ -91,7 +91,7 @@ describe("yaml-test-suite.", () => { let ast try { - ast = parse(input).ast + ast = parse(input) } catch (e) { if ( typeof e.lineNumber === "number" &&