Skip to content

Commit feeb14c

Browse files
committed
Return statements of methods and functions can now also be broken up into expressions and resolved individually. A bit of refactoring.
1 parent 23ee928 commit feeb14c

File tree

11 files changed

+72
-113
lines changed

11 files changed

+72
-113
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ The LanguageService will not track any mutations for already-initialized variabl
100100

101101
## Changelog:
102102

103+
**v1.0.10**:
104+
105+
- Return statements of methods and functions can now also be broken up into expressions and resolved individually. A bit of refactoring.
106+
103107
**v1.0.9**:
104108

105109
- Added support for getting all identifiers and the values that they are initialized to in a map.

src/formatter/ConstructorFormatter.ts

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,22 @@ import {IModifiersFormatter} from "src/formatter/interface/IModifiersFormatter";
22
import {ConstructorDeclaration} from "typescript";
33
import {ISourceFilePropertiesGetter} from "../getter/interface/ISourceFilePropertiesGetter";
44
import {IMapper} from "../mapper/interface/IMapper";
5-
import {IConstructorDeclaration, IdentifierMapKind, INonNullableValueable} from "../service/interface/ICodeAnalyzer";
5+
import {IConstructorDeclaration, IdentifierMapKind} from "../service/interface/ICodeAnalyzer";
66
import {FunctionLikeFormatter} from "./FunctionLikeFormatter";
77
import {IConstructorFormatter} from "./interface/IConstructorFormatter";
88
import {IDecoratorsFormatter} from "./interface/IDecoratorsFormatter";
99
import {IParametersFormatter} from "./interface/IParametersFormatter";
10-
import {IValueExpressionGetter} from "../getter/interface/IValueExpressionGetter";
11-
import {ITracer} from "../tracer/interface/ITracer";
12-
import {IValueResolvedGetter} from "../getter/interface/IValueResolvedGetter";
10+
import {IValueableFormatter} from "./interface/IValueableFormatter";
1311

1412
export class ConstructorFormatter extends FunctionLikeFormatter implements IConstructorFormatter {
1513
constructor (private mapper: IMapper,
16-
private tracer: ITracer,
17-
private valueExpressionGetter: IValueExpressionGetter,
18-
private valueResolvedGetter: IValueResolvedGetter,
1914
sourceFilePropertiesGetter: ISourceFilePropertiesGetter,
2015
decoratorsFormatter: IDecoratorsFormatter,
2116
modifiersFormatter: IModifiersFormatter,
22-
parametersFormatter: IParametersFormatter) {
17+
parametersFormatter: IParametersFormatter,
18+
valueableFormatter: IValueableFormatter) {
2319

24-
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter);
20+
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter, valueableFormatter);
2521
}
2622

2723
/**
@@ -34,9 +30,6 @@ export class ConstructorFormatter extends FunctionLikeFormatter implements ICons
3430
const name = "constructor";
3531

3632
const filePath = this.sourceFilePropertiesGetter.getSourceFileProperties(declaration).filePath;
37-
const valueExpression = declaration.body == null ? null : this.valueExpressionGetter.getValueExpression(declaration.body);
38-
const that = this;
39-
const scope = this.tracer.traceThis(declaration);
4033

4134
const map: IConstructorDeclaration = {
4235
...this.formatFunctionLikeDeclaration(declaration),
@@ -45,25 +38,7 @@ export class ConstructorFormatter extends FunctionLikeFormatter implements ICons
4538
name,
4639
className,
4740
filePath,
48-
value: {
49-
expression: valueExpression,
50-
resolving: false,
51-
resolved: undefined,
52-
resolvedPrecompute: undefined,
53-
hasDoneFirstResolve () {
54-
return map.value.resolved !== undefined;
55-
},
56-
resolve (insideThisScope: boolean = false) {
57-
if (map.value.expression == null) {
58-
map.value.resolved = map.value.resolvedPrecompute = null;
59-
} else {
60-
const [computed, flattened] = that.valueResolvedGetter.getValueResolved(<INonNullableValueable>map.value, declaration, scope, undefined, insideThisScope);
61-
map.value.resolved = computed;
62-
map.value.resolvedPrecompute = flattened;
63-
}
64-
return map.value.resolved;
65-
}
66-
}
41+
value: this.valueableFormatter.format(declaration, undefined, declaration.body)
6742
}
6843
};
6944

src/formatter/FunctionFormatter.ts

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
11
import {IDecoratorsFormatter} from "src/formatter/interface/IDecoratorsFormatter";
22
import {ISourceFilePropertiesGetter} from "src/getter/interface/ISourceFilePropertiesGetter";
3-
import {IValueExpressionGetter} from "src/getter/interface/IValueExpressionGetter";
4-
import {IValueResolvedGetter} from "src/getter/interface/IValueResolvedGetter";
53
import {FunctionDeclaration} from "typescript";
64
import {ICache} from "../cache/interface/ICache";
75
import {INameGetter} from "../getter/interface/INameGetter";
86
import {IMapper} from "../mapper/interface/IMapper";
9-
import {IdentifierMapKind, IFunctionDeclaration, INonNullableValueable} from "../service/interface/ICodeAnalyzer";
7+
import {IdentifierMapKind, IFunctionDeclaration} from "../service/interface/ICodeAnalyzer";
108
import {Config} from "../static/Config";
11-
import {ITracer} from "../tracer/interface/ITracer";
129
import {FunctionLikeFormatter} from "./FunctionLikeFormatter";
1310
import {IFunctionFormatter} from "./interface/IFunctionFormatter";
1411
import {IModifiersFormatter} from "./interface/IModifiersFormatter";
1512
import {IParametersFormatter} from "./interface/IParametersFormatter";
13+
import {IValueableFormatter} from "./interface/IValueableFormatter";
1614

1715
export class FunctionFormatter extends FunctionLikeFormatter implements IFunctionFormatter {
1816

1917
constructor (private mapper: IMapper,
20-
private tracer: ITracer,
2118
private cache: ICache,
2219
private nameGetter: INameGetter,
23-
private valueExpressionGetter: IValueExpressionGetter,
24-
private valueResolvedGetter: IValueResolvedGetter,
2520
sourceFilePropertiesGetter: ISourceFilePropertiesGetter,
2621
decoratorsFormatter: IDecoratorsFormatter,
2722
modifiersFormatter: IModifiersFormatter,
28-
parametersFormatter: IParametersFormatter) {
29-
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter);
23+
parametersFormatter: IParametersFormatter,
24+
valueableFormatter: IValueableFormatter) {
25+
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter, valueableFormatter);
3026
}
3127

3228
/**
@@ -41,35 +37,13 @@ export class FunctionFormatter extends FunctionLikeFormatter implements IFunctio
4137
const cached = this.cache.getCachedFunction(filePath, name);
4238
if (cached != null && !this.cache.cachedFunctionNeedsUpdate(cached.content)) return cached.content;
4339

44-
const valueExpression = declaration.body == null ? null : this.valueExpressionGetter.getValueExpression(declaration.body);
45-
const that = this;
46-
const scope = this.tracer.traceThis(declaration);
47-
4840
const map: IFunctionDeclaration = {
4941
...this.formatFunctionLikeDeclaration(declaration),
5042
...{
5143
___kind: IdentifierMapKind.FUNCTION,
5244
name,
5345
filePath,
54-
value: {
55-
expression: valueExpression,
56-
resolving: false,
57-
resolved: undefined,
58-
resolvedPrecompute: undefined,
59-
hasDoneFirstResolve () {
60-
return map.value.resolved !== undefined;
61-
},
62-
resolve () {
63-
if (map.value.expression == null) {
64-
map.value.resolved = map.value.resolvedPrecompute = null;
65-
} else {
66-
const [computed, flattened] = that.valueResolvedGetter.getValueResolved(<INonNullableValueable>map.value, declaration, scope);
67-
map.value.resolved = computed;
68-
map.value.resolvedPrecompute = flattened;
69-
}
70-
return map.value.resolved;
71-
}
72-
}
46+
value: this.valueableFormatter.format(declaration, undefined, declaration.body)
7347
}
7448
};
7549

src/formatter/FunctionLikeFormatter.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import {ConstructorDeclaration, FunctionDeclaration, MethodDeclaration} from "typescript";
22
import {ISourceFilePropertiesGetter} from "../getter/interface/ISourceFilePropertiesGetter";
33
import {isReturnStatement} from "../predicate/PredicateFunctions";
4-
import {IFunctionLike, IMemberDeclaration, IParametersable} from "../service/interface/ICodeAnalyzer";
4+
import {IFunctionLike, IMemberDeclaration, IParametersable, IValueable} from "../service/interface/ICodeAnalyzer";
55
import {IDecoratorsFormatter} from "./interface/IDecoratorsFormatter";
66
import {IFunctionLikeFormatter} from "./interface/IFunctionLikeFormatter";
77
import {IModifiersFormatter} from "./interface/IModifiersFormatter";
88
import {IParametersFormatter} from "./interface/IParametersFormatter";
9+
import {IValueableFormatter} from "./interface/IValueableFormatter";
910

1011
export abstract class FunctionLikeFormatter implements IFunctionLikeFormatter {
1112

1213
constructor (protected sourceFilePropertiesGetter: ISourceFilePropertiesGetter,
13-
private decoratorsFormatter: IDecoratorsFormatter, private modifiersFormatter: IModifiersFormatter,
14-
private parametersFormatter: IParametersFormatter) {
14+
private decoratorsFormatter: IDecoratorsFormatter,
15+
private modifiersFormatter: IModifiersFormatter,
16+
private parametersFormatter: IParametersFormatter,
17+
protected valueableFormatter: IValueableFormatter) {
1518
}
1619

1720
/**
@@ -60,28 +63,31 @@ export abstract class FunctionLikeFormatter implements IFunctionLikeFormatter {
6063
let returnStatementStartsAt: number = -1;
6164
let returnStatementEndsAt: number = -1;
6265
let returnStatementContents: string|null = null;
66+
let value: IValueable|null = null;
6367

6468
if (declaration.body != null && declaration.body.statements != null) {
65-
declaration.body.statements.forEach(bodyStatement => {
66-
69+
for (const bodyStatement of declaration.body.statements) {
6770
if (isReturnStatement(bodyStatement)) {
6871
if (bodyStatement.expression != null) {
6972
returnStatementStartsAt = bodyStatement.expression.pos;
7073
returnStatementEndsAt = bodyStatement.expression.end;
7174
returnStatementContents = fileContents.slice(returnStatementStartsAt, returnStatementEndsAt);
75+
value = this.valueableFormatter.format(bodyStatement.expression);
76+
break;
7277
}
7378
}
74-
});
79+
}
7580
}
7681

7782
return {
7883
...this.formatCallableMemberDeclaration(declaration),
7984
...{
8085
modifiers: this.modifiersFormatter.format(declaration),
81-
returnStatement: {
86+
returnStatement: value == null ? null : {
8287
startsAt: returnStatementStartsAt,
8388
endsAt: returnStatementEndsAt,
84-
contents: returnStatementContents
89+
contents: returnStatementContents,
90+
value
8591
}
8692
}
8793
};

src/formatter/MethodFormatter.ts

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
import {MethodDeclaration} from "typescript";
22
import {INameGetter} from "../getter/interface/INameGetter";
33
import {ISourceFilePropertiesGetter} from "../getter/interface/ISourceFilePropertiesGetter";
4-
import {IValueExpressionGetter} from "../getter/interface/IValueExpressionGetter";
5-
import {IValueResolvedGetter} from "../getter/interface/IValueResolvedGetter";
64
import {isStaticKeyword} from "../predicate/PredicateFunctions";
7-
import {IdentifierMapKind, IMethodDeclaration, INonNullableValueable} from "../service/interface/ICodeAnalyzer";
8-
import {ITracer} from "../tracer/interface/ITracer";
5+
import {IdentifierMapKind, IMethodDeclaration} from "../service/interface/ICodeAnalyzer";
96
import {FunctionLikeFormatter} from "./FunctionLikeFormatter";
107
import {IDecoratorsFormatter} from "./interface/IDecoratorsFormatter";
118
import {IMethodFormatter} from "./interface/IMethodFormatter";
129
import {IModifiersFormatter} from "./interface/IModifiersFormatter";
1310
import {IParametersFormatter} from "./interface/IParametersFormatter";
11+
import {IValueableFormatter} from "./interface/IValueableFormatter";
1412

1513
export class MethodFormatter extends FunctionLikeFormatter implements IMethodFormatter {
1614

17-
constructor (private tracer: ITracer,
18-
private nameGetter: INameGetter,
19-
private valueExpressionGetter: IValueExpressionGetter,
20-
private valueResolvedGetter: IValueResolvedGetter,
15+
constructor (private nameGetter: INameGetter,
2116
sourceFilePropertiesGetter: ISourceFilePropertiesGetter,
2217
decoratorsFormatter: IDecoratorsFormatter,
2318
modifiersFormatter: IModifiersFormatter,
24-
parametersFormatter: IParametersFormatter) {
25-
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter);
19+
parametersFormatter: IParametersFormatter,
20+
valueableFormatter: IValueableFormatter) {
21+
super(sourceFilePropertiesGetter, decoratorsFormatter, modifiersFormatter, parametersFormatter, valueableFormatter);
2622
}
2723

2824
/**
@@ -36,9 +32,6 @@ export class MethodFormatter extends FunctionLikeFormatter implements IMethodFor
3632

3733
const isStatic = declaration.modifiers == null ? false : declaration.modifiers.find(modifier => isStaticKeyword(modifier)) != null;
3834
const filePath = this.sourceFilePropertiesGetter.getSourceFileProperties(declaration).filePath;
39-
const valueExpression = declaration.body == null ? null : this.valueExpressionGetter.getValueExpression(declaration.body);
40-
const that = this;
41-
const scope = this.tracer.traceThis(declaration);
4235

4336
const map: IMethodDeclaration = {
4437
...this.formatFunctionLikeDeclaration(declaration),
@@ -48,25 +41,7 @@ export class MethodFormatter extends FunctionLikeFormatter implements IMethodFor
4841
name,
4942
className,
5043
filePath,
51-
value: {
52-
expression: valueExpression,
53-
resolving: false,
54-
resolved: undefined,
55-
resolvedPrecompute: undefined,
56-
hasDoneFirstResolve () {
57-
return map.value.resolved !== undefined;
58-
},
59-
resolve (insideThisScope: boolean = false) {
60-
if (map.value.expression == null) {
61-
map.value.resolved = map.value.resolvedPrecompute = null;
62-
} else {
63-
const [computed, flattened] = that.valueResolvedGetter.getValueResolved(<INonNullableValueable>map.value, declaration, scope, undefined, insideThisScope);
64-
map.value.resolved = computed;
65-
map.value.resolvedPrecompute = flattened;
66-
}
67-
return map.value.resolved;
68-
}
69-
}
44+
value: this.valueableFormatter.format(declaration, undefined, declaration.body)
7045
}
7146
};
7247

src/formatter/ValueableFormatter.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ export class ValueableFormatter implements IValueableFormatter {
1616
* Formats the given Statement into an IValueable.
1717
* @param {Statement|Expression|Declaration|Node} statement
1818
* @param {string|number} [takeKey]
19+
* @param {Statement|Expression|Declaration|Node} [takeValueExpressionFrom]
1920
* @returns {IValueable}
2021
*/
21-
public format (statement: Statement|Expression|Declaration|Node|undefined, takeKey?: string|number): IValueable {
22+
public format (statement: Statement|Expression|Declaration|Node|undefined, takeKey?: string|number, takeValueExpressionFrom?: Statement|Expression|Declaration|Node): IValueable {
2223
const cached = ValueableFormatter.cachedValueables.get(statement);
2324
if (cached != null && takeKey == null) return cached;
2425

25-
const valueExpression = statement == null ? null : this.valueExpressionGetter.getValueExpression(statement);
26+
const valueExpression = statement == null ? null : this.valueExpressionGetter.getValueExpression(takeValueExpressionFrom || statement);
2627
const scope = statement == null ? null : this.tracer.traceThis(statement);
2728
const that = this;
2829
const value: IValueable = {
@@ -33,11 +34,11 @@ export class ValueableFormatter implements IValueableFormatter {
3334
return value.resolved !== undefined;
3435
},
3536
resolving: false,
36-
resolve () {
37+
resolve (insideThisScope: boolean = false) {
3738
if (statement == null || value.expression == null) {
3839
value.resolved = value.resolvedPrecompute = null;
3940
} else {
40-
const [computed, flattened] = that.valueResolvedGetter.getValueResolved(<INonNullableValueable>value, statement, scope, takeKey);
41+
const [computed, flattened] = that.valueResolvedGetter.getValueResolved(<INonNullableValueable>value, statement, scope, takeKey, insideThisScope);
4142
value.resolved = computed;
4243
value.resolvedPrecompute = flattened;
4344
}

src/formatter/interface/IValueableFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import {Declaration, Expression, Node, Statement} from "typescript";
22
import {IValueable} from "../../service/interface/ICodeAnalyzer";
33

44
export interface IValueableFormatter {
5-
format (declaration: Statement|Expression|Node|Declaration|undefined, takeKey?: string|number): IValueable;
5+
format (declaration: Statement|Expression|Node|Declaration|undefined, takeKey?: string|number, takeValueExpressionFrom?: Statement|Expression|Node|Declaration): IValueable;
66
}

src/serializer/IdentifierSerializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export class IdentifierSerializer implements IIdentifierSerializer {
182182
replacements[method.name] = <string>this.marshaller.marshal(resolvedMethodBody, "");
183183

184184
// If the method had a return statement before, but doesn't anymore after it has been resolved, re-add a return statement.
185-
str += !hasReturnStatement && method.returnStatement.startsAt >= 0 ? `return (${this.addPlaceholder(method.name)})` : `${this.addPlaceholder(method.name)}`;
185+
str += !hasReturnStatement && method.returnStatement != null ? `return (${this.addPlaceholder(method.name)})` : `${this.addPlaceholder(method.name)}`;
186186
}
187187
str += "}\n\n";
188188
}

src/service/CodeAnalyzer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ export class CodeAnalyzer implements ICodeAnalyzer {
147147
this.mutationFormatter = new MutationFormatter(this.mapper, this.tracer, this.valueableFormatter, this.nameGetter, this.valueExpressionGetter, this.valueResolvedGetter, this.sourceFilePropertiesGetter);
148148
this.parametersFormatter = new ParametersFormatter(this.mapper, this.tracer, this.nameGetter, this.sourceFilePropertiesGetter, this.typeExpressionGetter, this.valueResolvedGetter, this.valueExpressionGetter, this.tokenSerializer, this.typeUtil);
149149
this.argumentsFormatter = new ArgumentsFormatter(this.mapper, this.tracer, this.valueResolvedGetter, this.valueExpressionGetter);
150-
this.methodFormatter = new MethodFormatter(this.tracer, this.nameGetter, this.valueExpressionGetter, this.valueResolvedGetter, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter);
151-
this.constructorFormatter = new ConstructorFormatter(this.mapper, this.tracer, this.valueExpressionGetter, this.valueResolvedGetter, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter);
152-
this.functionFormatter = new FunctionFormatter(this.mapper, this.tracer, this.cache, this.nameGetter, this.valueExpressionGetter, this.valueResolvedGetter, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter);
150+
this.methodFormatter = new MethodFormatter(this.nameGetter, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter, this.valueableFormatter);
151+
this.constructorFormatter = new ConstructorFormatter(this.mapper, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter, this.valueableFormatter);
152+
this.functionFormatter = new FunctionFormatter(this.mapper, this.cache, this.nameGetter, this.sourceFilePropertiesGetter, this.decoratorsFormatter, this.modifiersFormatter, this.parametersFormatter, this.valueableFormatter);
153153
this.classFormatter = new ClassFormatter(this.mapper, this.cache, this.decoratorsFormatter, this.propFormatter, this.methodFormatter, this.constructorFormatter, this.modifiersFormatter, this.valueableFormatter, this.heritageClauseFormatter, this.sourceFilePropertiesGetter);
154154
this.callExpressionFormatter = new CallExpressionFormatter(this.mapper, this.argumentsFormatter, this.sourceFilePropertiesGetter, this.valueableFormatter, this.nameGetter, this.typeExpressionGetter, this.tokenSerializer, this.typeUtil);
155155
this.requireFormatter = new RequireFormatter(this, this.sourceFilePropertiesGetter, this.valueableFormatter, this.callExpressionFormatter, this.stringUtil, this.fileLoader);

src/service/interface/ICodeAnalyzer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export interface IArgumentsBody extends IPositionable {
105105
}
106106

107107
export interface IReturnStatementable {
108-
returnStatement: IPositionable&IContentsable;
108+
returnStatement: null|(IPositionable&IContentsable&{ value: IValueable });
109109
}
110110

111111
export interface IFunctionLike extends IParametersable, IMemberDeclaration, IReturnStatementable, IModifiersable {

0 commit comments

Comments
 (0)