Files
repomix-mirror/tests/core/treeSitter/parseFile.dart.test.ts
Kazuki Yamada d10814163d fix(core): Cover const and external constructors in Dart query
Three constructor variants were silently dropped during --compress:

- `const Foo(...);` and `const Foo.named(...) : ...;` parse as
  `(declaration (constant_constructor_signature ...))` — a node type the
  existing constructor query did not list.
- `const factory Foo() = Bar;` parses as
  `(redirecting_factory_constructor_signature (const_builtin) (identifier) ...)`
  whose first named child is `const_builtin`, so the leading-anchor
  `. (identifier)` pattern failed to match.
- `external factory Foo.make();` parses as
  `(declaration (factory_constructor_signature ...))` — bare under
  `declaration`, not wrapped in `method_signature`, so the existing
  factory query missed it.

Switch the constructor / factory / redirecting-factory queries to
capture the whole signature node as `@name.definition.method`. This
emits the same source line(s) DefaultParseStrategy already produces and
is robust across all body / external / const / redirecting variants.
2026-05-06 22:12:39 +09:00

288 lines
7.8 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { parseFile } from '../../../src/core/treeSitter/parseFile.js';
import { createMockConfig } from '../../../tests/testing/testUtils.js';
describe('parseFile for Dart', () => {
test('should parse Dart correctly', async () => {
const fileContent = `
/// A simple greeting class
class Greeter {
/// The name to greet
final String name;
/// Constructor
Greeter(this.name);
/// Prints a greeting message
void greet() {
print('Hello, $name!');
}
/// Returns a greeting message
String getMessage() {
return 'Hello, $name!';
}
}
/// Main entry point
void main() {
final greeter = Greeter('World');
greeter.greet();
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
'/// A simple greeting class',
'class Greeter {',
'/// The name to greet',
'/// Constructor',
'/// Prints a greeting message',
'void greet() {',
'/// Returns a greeting message',
'String getMessage() {',
'/// Main entry point',
'void main() {',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
test('should parse Dart with imports correctly', async () => {
const fileContent = `
import 'dart:async';
import 'package:flutter/material.dart';
/// A simple widget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();
}
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
"import 'dart:async';",
"import 'package:flutter/material.dart';",
'/// A simple widget',
'class MyWidget extends StatelessWidget {',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
test('should parse Dart with enum, extension, and constructor', async () => {
const fileContent = `
/// Status enum
enum Status {
pending,
active,
completed
}
/// String extension
extension StringExtension on String {
/// Capitalizes first letter
String capitalize() {
return this[0].toUpperCase() + substring(1);
}
}
/// User class
class User {
final String name;
final Status status;
/// User constructor
User(this.name, this.status);
/// Named constructor
User.guest() : name = 'Guest', status = Status.pending;
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
'/// Status enum',
'enum Status {',
'/// String extension',
'extension StringExtension on String {',
'/// Capitalizes first letter',
'String capitalize() {',
'/// User class',
'class User {',
'/// User constructor',
'/// Named constructor',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
test('should parse Dart mixin, typedef, getter, setter, and factory', async () => {
const fileContent = `
/// JSON map alias
typedef Json = Map<String, dynamic>;
/// Walker mixin
mixin Walker on Animal {
/// Walk action
void walk() {
print('walking');
}
}
/// Animal base class
class Animal {
final String _name;
Animal(this._name);
/// Animal name getter
String get name => _name;
/// Animal name setter
set nickname(String value) {
print('nickname is $value');
}
/// Factory constructor
factory Animal.guest() {
return Animal('Guest');
}
/// Redirecting factory
factory Animal.copy(Animal other) = Animal;
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
'/// JSON map alias',
'typedef Json = Map<String, dynamic>;',
'/// Walker mixin',
'mixin Walker on Animal {',
'/// Walk action',
'void walk() {',
'/// Animal name getter',
'String get name => _name;',
'/// Animal name setter',
'set nickname(String value) {',
'/// Factory constructor',
'factory Animal.guest() {',
'/// Redirecting factory',
'factory Animal.copy(Animal other) = Animal;',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
test('should parse Dart plain constructor and operator overloads', async () => {
const fileContent = `
/// Vector class with operators
class Vector {
final double x;
final double y;
/// Plain constructor
Vector(this.x, this.y);
/// Plus operator
Vector operator +(Vector other) => Vector(x + other.x, y + other.y);
/// Index operator
double operator [](int i) => i == 0 ? x : y;
/// Index assignment operator
void operator []=(int i, double v) {}
/// Equality operator
bool operator ==(Object other) => other is Vector && x == other.x && y == other.y;
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
'/// Plain constructor',
'Vector(this.x, this.y);',
'/// Plus operator',
'Vector operator +(Vector other) => Vector(x + other.x, y + other.y);',
'/// Index operator',
'double operator [](int i) => i == 0 ? x : y;',
'/// Index assignment operator',
'void operator []=(int i, double v) {}',
'/// Equality operator',
'bool operator ==(Object other) => other is Vector && x == other.x && y == other.y;',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
test('should parse Dart const and external constructors', async () => {
const fileContent = `
/// Point with const constructors
class Point {
final int x;
final int y;
/// Const plain constructor
const Point(this.x, this.y);
/// Const named constructor
const Point.zero() : x = 0, y = 0;
/// Const redirecting factory
const factory Point.alias() = Point.zero;
/// External factory
external factory Point.native();
}
`;
const filePath = 'dummy.dart';
const config = {};
const result = await parseFile(fileContent, filePath, createMockConfig(config));
expect(typeof result).toBe('string');
const expectContents = [
'/// Const plain constructor',
'const Point(this.x, this.y);',
'/// Const named constructor',
'const Point.zero() : x = 0, y = 0;',
'/// Const redirecting factory',
'const factory Point.alias() = Point.zero;',
'/// External factory',
'external factory Point.native();',
];
for (const expectContent of expectContents) {
expect(result).toContain(expectContent);
}
});
});