<commit_before>import { DocumentSymbol, Range, SymbolKind } from 'vscode-languageserver';
import { SyntaxNode } from 'web-tree-sitter';
import Position from './Position';

const SYMBOLKINDS = {
	singleton_method: SymbolKind.Method,
	method: SymbolKind.Method,
	class: SymbolKind.Class,
	module: SymbolKind.Module,
	assignment: SymbolKind.Constant,
	method_call: SymbolKind.Property,
};

const IDENTIFIER_NODES = {
	module: 'constant',
	class: 'constant',
	method: 'identifier',
	singleton_method: 'identifier',
	assignment: 'constant',
	method_call: 'identifier',
};

export function isWrapper(node: SyntaxNode): boolean {
	return IDENTIFIER_NODES.hasOwnProperty(node.type);
}

const RubyDocumentSymbol = {
	build(node: SyntaxNode): DocumentSymbol | DocumentSymbol[] | void {
		const symbolKind = SYMBOLKINDS[node.type];
		if (!symbolKind) return;

		const symbol = new DocumentSymbol();
		symbol.range = Range.create(
			Position.fromTSPosition(node.startPosition).toVSPosition(),
			Position.fromTSPosition(node.endPosition).toVSPosition()
		);
		symbol.kind = symbolKind;

		if (isWrapper(node)) {
			if (!node.childCount) return;
			// Handle foo = Foo::Bar::Baz.bam showing Foo in the outline
			if (node.type === 'assignment' && node.firstChild.type === 'identifier') return;
			const identifierNode = node.descendantsOfType(IDENTIFIER_NODES[node.type])[0];
			if (identifierNode) {
				symbol.children = [];
				symbol.name = identifierNode.text;

				// Prepend self. to class methods
				if (node.type === 'singleton_method') {
					symbol.name = `self.${identifierNode.text}`;
				}

				// Override constructor type
				if (symbol.name === 'initialize') {
					symbol.kind = SymbolKind.Constructor;
				}

				// detect attr_ method calls
				if (symbol.name.indexOf('attr_') === 0) {
					const argumentList = node.descendantsOfType('argument_list')[0];
					const symbols = [];
					for (const child of argumentList.children) {
						if (!child.isNamed) continue;
						const newSymbol = {
							...symbol,
						};
						newSymbol.name = child.text[0] === ':' ? child.text.substring(1) : child.text;
						newSymbol.selectionRange = Range.create(
							Position.fromTSPosition(child.startPosition).toVSPosition(),
							Position.fromTSPosition(child.endPosition).toVSPosition()
						);

						symbols.push(newSymbol);
					}

					return symbols;
				} else if (node.type !== 'method_call') {
					symbol.selectionRange = Range.create(
						Position.fromTSPosition(identifierNode.startPosition).toVSPosition(),
						Position.fromTSPosition(identifierNode.endPosition).toVSPosition()
					);
				} else {
					return;
				}
			} else {
				return;
			}
		} else {
			symbol.selectionRange = symbol.range;
			symbol.name = node.text;
		}

		return symbol;
	},
};

export default RubyDocumentSymbol;
<commit_msg>Fix incorrect parsing of attr_ calls with multiple arguments<commit_after>import { DocumentSymbol, Range, SymbolKind } from 'vscode-languageserver';
import { SyntaxNode } from 'web-tree-sitter';
import Position from './Position';

const SYMBOLKINDS = {
	singleton_method: SymbolKind.Method,
	method: SymbolKind.Method,
	class: SymbolKind.Class,
	module: SymbolKind.Module,
	assignment: SymbolKind.Constant,
	method_call: SymbolKind.Property,
};

const IDENTIFIER_NODES = {
	module: 'constant',
	class: 'constant',
	method: 'identifier',
	singleton_method: 'identifier',
	assignment: 'constant',
	method_call: 'identifier',
};

export function isWrapper(node: SyntaxNode): boolean {
	return IDENTIFIER_NODES.hasOwnProperty(node.type);
}

const RubyDocumentSymbol = {
	build(node: SyntaxNode): DocumentSymbol | DocumentSymbol[] | void {
		const symbolKind = SYMBOLKINDS[node.type];
		if (!symbolKind) return;

		const symbol = new DocumentSymbol();
		symbol.range = Range.create(
			Position.fromTSPosition(node.startPosition).toVSPosition(),
			Position.fromTSPosition(node.endPosition).toVSPosition()
		);
		symbol.kind = symbolKind;

		if (isWrapper(node)) {
			if (!node.childCount) return;
			// Handle foo = Foo::Bar::Baz.bam showing Foo in the outline
			if (node.type === 'assignment' && node.firstChild.type === 'identifier') return;
			const identifierNode = node.descendantsOfType(IDENTIFIER_NODES[node.type])[0];
			if (identifierNode) {
				symbol.children = [];
				symbol.name = identifierNode.text;

				// Prepend self. to class methods
				if (node.type === 'singleton_method') {
					symbol.name = `self.${identifierNode.text}`;
				}

				// Override constructor type
				if (symbol.name === 'initialize') {
					symbol.kind = SymbolKind.Constructor;
				}

				// detect attr_ method calls
				if (symbol.name.indexOf('attr_') === 0) {
					const argumentList = node.descendantsOfType('argument_list')[0];
					const symbols = [];
					for (const child of argumentList.namedChildren) {
						const newSymbol = {
							...symbol,
						};
						newSymbol.name = child.text[0] === ':' ? child.text.substring(1) : child.text;
						newSymbol.selectionRange = Range.create(
							Position.fromTSPosition(child.startPosition).toVSPosition(),
							Position.fromTSPosition(child.endPosition).toVSPosition()
						);

						symbols.push(newSymbol);
					}

					return symbols;
				} else if (node.type !== 'method_call') {
					symbol.selectionRange = Range.create(
						Position.fromTSPosition(identifierNode.startPosition).toVSPosition(),
						Position.fromTSPosition(identifierNode.endPosition).toVSPosition()
					);
				} else {
					return;
				}
			} else {
				return;
			}
		} else {
			symbol.selectionRange = symbol.range;
			symbol.name = node.text;
		}

		return symbol;
	},
};

export default RubyDocumentSymbol;

{'fraction_non_alphanumeric': 0.13130066972153684, 'fraction_numerical': 0.0017624250969333803, 'mean_word_length': 3.7489539748953975, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6077607', 'n_tokens_mistral': 2094, 'n_tokens_neox': 1751, 'n_words': 351}