Skip to content

Commit aeafa7d

Browse files
committed
Support export default class
1 parent 8797228 commit aeafa7d

File tree

7 files changed

+157
-5
lines changed

7 files changed

+157
-5
lines changed

packages/vscode-language-server-obsidian/server/src/dto/identifier.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Identifier as IdentifierNode, Node } from "ts-morph";
1+
import { Identifier as IdentifierNode, ImportClause, ImportDeclaration, ImportSpecifier, Node } from "ts-morph";
22
import { Import } from "./import";
33

44
export class Identifier {
@@ -10,8 +10,16 @@ export class Identifier {
1010

1111
public get import() {
1212
const declarations = this.node.getSymbol()?.getDeclarations();
13-
const declaration = declarations?.find(Node.isImportSpecifier);
14-
const importDeclaration = declaration?.getImportDeclaration();
13+
const declaration = declarations?.find(d => Node.isImportSpecifier(d) || Node.isImportClause(d));
14+
const importDeclaration = this.getImportDeclaration(declaration);
1515
return importDeclaration && new Import(importDeclaration);
1616
}
17+
18+
private getImportDeclaration(declaration: ImportSpecifier | ImportClause | undefined) {
19+
if (Node.isImportSpecifier(declaration)) {
20+
return declaration.getImportDeclaration();
21+
} else if (Node.isImportClause(declaration)) {
22+
return declaration.getParent() as ImportDeclaration;
23+
}
24+
}
1725
}

packages/vscode-language-server-obsidian/server/tests/integration/goToDefinition/goToDefinition.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { TextDocuments } from "vscode-languageserver/node";
22
import { DefinitionCommand } from "../../../src/commands/definition/definitionCommand";
33
import { StrategyFactory } from "../../../src/commands/definition/strategies/goToDefinitionStrategyFactory";
44
import { ProjectAdapter } from "../../../src/services/ast/projectAdapter";
5-
import { Logger } from "../../../src/services/logger";
65
import { TextDocument } from "vscode-languageserver-textdocument";
76
import { mockDeep, mock } from "jest-mock-extended";
87
import { when } from "jest-when";
@@ -14,13 +13,15 @@ import dependencyInSameGraph from "./dependencyInSameGraph";
1413
import dependencyInSubgraph from "./dependencyInSubgraph";
1514
import injectedClass from "./injectedClass";
1615
import injectedHookDifferentInjectedTypeName from "./injectedHookDifferentInjectedTypeName";
16+
import injectedExportDefaultClass from "./injectedExportDefaultClass";
1717

1818
const testCases: TestCase[] = [
1919
injectedHook,
2020
dependencyInSameGraph,
2121
dependencyInSubgraph,
2222
injectedClass,
23-
injectedHookDifferentInjectedTypeName
23+
injectedHookDifferentInjectedTypeName,
24+
injectedExportDefaultClass
2425
];
2526

2627
describe('GoToDefinition', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { TestCase } from "../..";
2+
import { entryGraphContent } from "./sourceCodes/entryGraph";
3+
import { entryPoint } from "./sourceCodes/entryPoint";
4+
import { gameGraph } from "./sourceCodes/gameGraph";
5+
import { gameModel } from "./sourceCodes/gameModel";
6+
7+
export default {
8+
entryPoint,
9+
additionalSourceCodes: [
10+
gameGraph,
11+
entryGraphContent,
12+
gameModel
13+
],
14+
position: {
15+
line: 10,
16+
character: 33
17+
},
18+
result: {
19+
uri: '/core/model/GameModel.ts',
20+
range: {
21+
start: {
22+
line: 7,
23+
character: 0
24+
},
25+
end: {
26+
line: 34,
27+
character: 1
28+
}
29+
}
30+
}
31+
} satisfies TestCase;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { SourceCode } from "../../..";
2+
3+
export const entryGraphContent: SourceCode = {
4+
path: './di/EntryGraph',
5+
content: `import { Graph, ObjectGraph, Provides } from 'react-obsidian';
6+
import { useEntryViewModel } from '../model/entryViewModel';
7+
import { GameGraph } from '../../../core/di/GameGraph';
8+
import { type Props } from '../Entry';
9+
import type GameModel from '../../../core/model/GameModel';
10+
11+
@Graph({ subgraphs: [GameGraph] })
12+
export class EntryGraph extends ObjectGraph {
13+
private index: number;
14+
15+
constructor(props: Props) {
16+
super(props);
17+
this.index = props.index;
18+
}
19+
20+
@Provides()
21+
useViewModel(model: GameModel) {
22+
return () => useEntryViewModel(this.index, model);
23+
}
24+
25+
@Provides()
26+
foo() {
27+
return 'foo';
28+
}
29+
}`};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SourceCode } from "../../..";
2+
3+
export const entryPoint: SourceCode = {
4+
path: 'entry.tsx',
5+
content: `import { type DependenciesOf, injectComponent } from 'react-obsidian';
6+
import { EntryGraph } from './di/EntryGraph';
7+
import type { GameGraph } from '../../core/di/GameGraph';
8+
9+
export type Props = {
10+
index: number
11+
};
12+
13+
type Injected = DependenciesOf<[EntryGraph, GameGraph], 'useViewModel' | 'foo' | 'model'>;
14+
15+
const Entry_ = ({ useViewModel, model }: Props & Injected) => {
16+
const { text, onClick } = useViewModel();
17+
18+
return (
19+
<li>
20+
<button onClick={onClick}>{text}</button>
21+
</li>
22+
);
23+
};
24+
25+
export const Entry = injectComponent<Props, Injected>(Entry_, EntryGraph);
26+
export const createEntry = (_: unknown, index: number) => <Entry index={index} />;
27+
`
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { SourceCode } from "../../..";
2+
3+
export const gameGraph: SourceCode = {
4+
path: '../../../core/di/GameGraph.ts',
5+
content: `import { Graph, ObjectGraph, Provides, Singleton } from 'react-obsidian';
6+
import GameModel from '../model/GameModel';
7+
import { CalculateWinnerUseCase } from '../usecases/CalculateWinnerUseCase';
8+
9+
@Singleton() @Graph()
10+
export class GameGraph extends ObjectGraph {
11+
@Provides()
12+
model(): GameModel {
13+
return new GameModel(new CalculateWinnerUseCase());
14+
}
15+
}`};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { SourceCode } from "../../..";
2+
3+
export const gameModel: SourceCode = {
4+
path: '../../../core/model/GameModel.ts',
5+
content: `import { MediatorObservable, Model, Observable } from 'react-obsidian';
6+
import { CurrentPlayer } from '../entities/CurrentPlayer';
7+
import { Squares } from '../entities/Squares';
8+
import { type CalculateWinnerUseCase } from '../usecases/CalculateWinnerUseCase';
9+
import { History } from '../entities/History';
10+
import { persist } from '../../persistency/persist.legacy';
11+
12+
export default class GameModel extends Model {
13+
@persist('CurrentPlayer') private readonly currentPlayer = new CurrentPlayer('X');
14+
@persist('Squares') private readonly squares = new Squares();
15+
@persist('History') private readonly history = new History(this.squares.value);
16+
@persist('Status') public readonly status = new MediatorObservable<string>();
17+
@persist('IsReady') public readonly isReady = new Observable<boolean>(false);
18+
19+
constructor(calculateWinnerUseCase: CalculateWinnerUseCase) {
20+
super();
21+
this.status.mapSource(this.currentPlayer, (player) => {
22+
const winner = calculateWinnerUseCase.calculate(this.squares.value);
23+
return winner ? \`Winner: \${winner}\` : \`Next player: \${player}\`;
24+
});
25+
}
26+
27+
public onSquareClick(index: number) {
28+
if (this.squares.value[index]) return;
29+
this.squares.mark(index, this.currentPlayer.value);
30+
this.currentPlayer.nextPlayer();
31+
this.history.add(this.squares.value, this.currentPlayer.value);
32+
}
33+
34+
public onHistoryEntryClick(index: number) {
35+
this.history.goTo(index);
36+
this.squares.value = this.history.value[index].squares;
37+
this.currentPlayer.value = this.history.value[index].currentPlayer;
38+
}
39+
}
40+
`};

0 commit comments

Comments
 (0)