Skip to content

Commit fd004ee

Browse files
committed
Refactored most logic into separate classes and modules to break the logic out into different pieces of abstraction
1 parent 0269a90 commit fd004ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+3957
-3027
lines changed

src/SimpleLanguageService.ts

Lines changed: 221 additions & 3005 deletions
Large diffs are not rendered by default.

src/Util.ts

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
import {BinaryOperator, NodeFlags, SyntaxKind, TypeNode} from "typescript";
22
import {BindingIdentifier} from "./BindingIdentifier";
33
import {IBindingIdentifier} from "./interface/IBindingIdentifier";
4-
import {ArbitraryValue} from "./interface/ISimpleLanguageService";
4+
import {ArbitraryValue, ITypeBinding, TypeExpression} from "./interface/ISimpleLanguageService";
5+
import {isTypeBinding} from "./PredicateFunctions";
6+
7+
/**
8+
* Formats and returns a string representation of a type.
9+
* @param {TypeExpression} expression
10+
* @returns {string}
11+
*/
12+
export function serializeTypeExpression (expression: TypeExpression): string {
13+
let statement: string = "";
14+
expression.forEach(token => {
15+
if (isTypeBinding(token)) {
16+
statement += token.name;
17+
if (token.typeArguments != null) {
18+
statement += `<${serializeTypeExpression(token.typeArguments)}>`;
19+
}
20+
} else {
21+
statement += `${token}`;
22+
}
23+
});
24+
return statement;
25+
}
26+
527
/**
628
* Checks the token and returns the appropriate native version if possible, otherwise it returns the serialized version.
729
* @param {SyntaxKind} token
@@ -52,7 +74,7 @@ export function isTokenLike (item: ArbitraryValue): boolean {
5274
* @param {ArbitraryValue} item
5375
* @returns {boolean}
5476
*/
55-
export function throwsIfPrimitive(item: ArbitraryValue): boolean {
77+
export function throwsIfPrimitive (item: ArbitraryValue): boolean {
5678
switch (item == null ? "" : item.toString()) {
5779
case "=":
5880
case "++":
@@ -494,4 +516,66 @@ export function serializeToken (token: SyntaxKind | TypeNode): string | IBinding
494516
default:
495517
throw new TypeError(`${serializeToken.name} could not serialize a token of kind ${SyntaxKind[<SyntaxKind>token]}`);
496518
}
519+
}
520+
521+
function isQuote (content: string): boolean {
522+
return /["'`]/.test(content);
523+
}
524+
525+
export function stripQuotesIfNecessary (content: ArbitraryValue): ArbitraryValue {
526+
if (!(typeof content === "string")) return content;
527+
const trimmed = content;
528+
const firstChar = trimmed[0];
529+
const lastChar = trimmed[trimmed.length - 1];
530+
const startsWithQuote = isQuote(firstChar);
531+
const endsWithQuote = isQuote(lastChar);
532+
const startOffset = startsWithQuote ? 1 : 0;
533+
const endOffset = endsWithQuote ? 1 : 0;
534+
return trimmed.slice(startOffset, trimmed.length - endOffset);
535+
}
536+
537+
export function quoteIfNecessary (content: ArbitraryValue): ArbitraryValue {
538+
if (!(typeof content === "string")) return content;
539+
const REPLACEMENT_CHAR = "`";
540+
const trimmed = content;
541+
const firstChar = trimmed[0];
542+
const lastChar = trimmed[trimmed.length - 1];
543+
let str = REPLACEMENT_CHAR;
544+
const startsWithClashingQuote = firstChar === REPLACEMENT_CHAR;
545+
const endsWithClashingQuote = lastChar === REPLACEMENT_CHAR;
546+
547+
if (startsWithClashingQuote && endsWithClashingQuote) {
548+
const insideQuotes = trimmed.match(new RegExp(`^${REPLACEMENT_CHAR}([^${REPLACEMENT_CHAR}]*)${REPLACEMENT_CHAR}`));
549+
// If there are nothing but whitespace inside the quotes, just return them.
550+
if (insideQuotes != null && isWhitespace(insideQuotes[1])) return content;
551+
}
552+
553+
const startOffset = startsWithClashingQuote ? 1 : 0;
554+
const endOffset = endsWithClashingQuote ? 1 : 0;
555+
if (startsWithClashingQuote) str += `\\${REPLACEMENT_CHAR}`;
556+
str += trimmed.slice(startOffset, trimmed.length - endOffset);
557+
if (endsWithClashingQuote) str += `\\${REPLACEMENT_CHAR}`;
558+
str += REPLACEMENT_CHAR;
559+
return str;
560+
}
561+
562+
/**
563+
* Takes all ITypeBindings from a TypeExpression and returns an array of them.
564+
* @param {TypeExpression} expression
565+
* @param {boolean} [deep=false]
566+
* @returns {ITypeBinding[]}
567+
*/
568+
export function takeTypeBindings (expression: TypeExpression, deep: boolean = false): ITypeBinding[] {
569+
const bindings: ITypeBinding[] = [];
570+
571+
expression.forEach(token => {
572+
if (isTypeBinding(token)) {
573+
bindings.push(token);
574+
575+
if (token.typeArguments != null && deep) {
576+
takeTypeBindings(token.typeArguments, deep).forEach(typeBinding => bindings.push(typeBinding));
577+
}
578+
}
579+
});
580+
return bindings;
497581
}

src/cache/Cache.ts

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import {ICache} from "./interface/ICache";
2+
import {ICachedContent, IFunctionDeclaration, IVariableAssignment, IEnumDeclaration, IPropDeclaration, IClassDeclaration, FunctionIndexer, IImportDeclaration, ClassIndexer, EnumIndexer, VariableIndexer, ISimpleLanguageService} from "../interface/ISimpleLanguageService";
3+
4+
export class Cache implements ICache {
5+
private cache: Map<string, ICachedContent<{}>> = new Map();
6+
7+
constructor (private languageService: ISimpleLanguageService) {}
8+
9+
public getCachedPropName (fileName: string, className: string, propName: string): string {
10+
return `prop.${fileName}.${className}.${propName}`;
11+
}
12+
13+
public getCachedVariableName (fileName: string, variableName: string): string {
14+
return `variable.${fileName}.${variableName}`;
15+
}
16+
17+
public getCachedEnumName (fileName: string, enumName: string): string {
18+
return `enum.${fileName}.${enumName}`;
19+
}
20+
21+
public getCachedClassName (fileName: string, className: string): string {
22+
return `class.${fileName}.${className}`;
23+
}
24+
25+
public getCachedFunctionName (fileName: string, className: string): string {
26+
return `function.${fileName}.${className}`;
27+
}
28+
29+
public getCachedClassIndexerName (fileName: string): string {
30+
return `classIndexer.${fileName}`;
31+
}
32+
33+
public getCachedModuleDependenciesName (fileName: string): string {
34+
return `moduleDependencies.${fileName}`;
35+
}
36+
37+
public getCachedFunctionIndexerName (fileName: string): string {
38+
return `functionIndexer.${fileName}`;
39+
}
40+
41+
public getCachedVariableIndexerName (fileName: string): string {
42+
return `variableIndexer.${fileName}`;
43+
}
44+
45+
public getCachedEnumIndexerName (fileName: string): string {
46+
return `enumIndexer.${fileName}`;
47+
}
48+
49+
public getFromCache<T> (key: string): ICachedContent<T> | null {
50+
const record = this.cache.get(key);
51+
return record == null ? null : <ICachedContent<T>>record;
52+
}
53+
54+
public getCachedVariable (fileName: string, variableName: string): ICachedContent<IVariableAssignment> | null {
55+
return this.getFromCache<IVariableAssignment>(this.getCachedVariableName(fileName, variableName));
56+
}
57+
58+
public getCachedFunction (fileName: string, functionName: string): ICachedContent<IFunctionDeclaration> | null {
59+
return this.getFromCache<IFunctionDeclaration>(this.getCachedFunctionName(fileName, functionName));
60+
}
61+
62+
public getCachedEnum (fileName: string, enumName: string): ICachedContent<IEnumDeclaration> | null {
63+
return this.getFromCache<IEnumDeclaration>(this.getCachedEnumName(fileName, enumName));
64+
}
65+
66+
public getCachedProp (fileName: string, className: string, propName: string): ICachedContent<IPropDeclaration> | null {
67+
return this.getFromCache<IPropDeclaration>(this.getCachedPropName(fileName, className, propName));
68+
}
69+
70+
public getCachedClass (fileName: string, className: string): ICachedContent<IClassDeclaration> | null {
71+
return this.getFromCache<IClassDeclaration>(this.getCachedClassName(fileName, className));
72+
}
73+
74+
public getCachedFunctionIndexer (fileName: string): ICachedContent<FunctionIndexer> | null {
75+
return this.getFromCache<FunctionIndexer>(this.getCachedFunctionIndexerName(fileName));
76+
}
77+
78+
public getCachedModuleDependencies (fileName: string): ICachedContent<IImportDeclaration[]> | null {
79+
return this.getFromCache<IImportDeclaration[]>(this.getCachedModuleDependenciesName(fileName));
80+
}
81+
82+
public getCachedClassIndexer (fileName: string): ICachedContent<ClassIndexer> | null {
83+
return this.getFromCache<ClassIndexer>(this.getCachedClassIndexerName(fileName));
84+
}
85+
86+
public getCachedEnumIndexer (fileName: string): ICachedContent<EnumIndexer> | null {
87+
return this.getFromCache<EnumIndexer>(this.getCachedEnumIndexerName(fileName));
88+
}
89+
90+
public getCachedVariableIndexer (fileName: string): ICachedContent<VariableIndexer> | null {
91+
return this.getFromCache<VariableIndexer>(this.getCachedVariableIndexerName(fileName));
92+
}
93+
94+
public setCachedProp (fileName: string, content: IPropDeclaration): void {
95+
const version = this.languageService.getFileVersion(fileName);
96+
this.cache.set(this.getCachedPropName(fileName, content.className, content.name), {content, version});
97+
}
98+
99+
public setCachedVariable (fileName: string, content: IVariableAssignment): void {
100+
const version = this.languageService.getFileVersion(fileName);
101+
this.cache.set(this.getCachedVariableName(fileName, content.name), {content, version});
102+
}
103+
104+
public setCachedEnum (fileName: string, content: IEnumDeclaration): void {
105+
const version = this.languageService.getFileVersion(fileName);
106+
this.cache.set(this.getCachedEnumName(fileName, content.name), {content, version});
107+
}
108+
109+
public setCachedClass (fileName: string, content: IClassDeclaration): void {
110+
const version = this.languageService.getFileVersion(fileName);
111+
this.cache.set(this.getCachedClassName(fileName, content.name), {version, content});
112+
}
113+
114+
public setCachedFunction (fileName: string, content: IFunctionDeclaration): void {
115+
const version = this.languageService.getFileVersion(fileName);
116+
this.cache.set(this.getCachedFunctionName(fileName, content.name), {version, content});
117+
}
118+
119+
public setCachedClassIndexer (fileName: string, content: ClassIndexer): void {
120+
const version = this.languageService.getFileVersion(fileName);
121+
this.cache.set(this.getCachedClassIndexerName(fileName), {version, content});
122+
}
123+
124+
public setCachedFunctionIndexer (fileName: string, content: FunctionIndexer): void {
125+
const version = this.languageService.getFileVersion(fileName);
126+
this.cache.set(this.getCachedFunctionIndexerName(fileName), {version, content});
127+
}
128+
129+
public setCachedModuleDependencies (fileName: string, content: IImportDeclaration[]): void {
130+
const version = this.languageService.getFileVersion(fileName);
131+
this.cache.set(this.getCachedModuleDependenciesName(fileName), {version, content});
132+
}
133+
134+
public setCachedEnumIndexer (fileName: string, content: EnumIndexer): void {
135+
const version = this.languageService.getFileVersion(fileName);
136+
this.cache.set(this.getCachedEnumIndexerName(fileName), {version, content});
137+
}
138+
139+
public setCachedVariableIndexer (fileName: string, content: VariableIndexer): void {
140+
const version = this.languageService.getFileVersion(fileName);
141+
this.cache.set(this.getCachedVariableIndexerName(fileName), {version, content});
142+
}
143+
144+
public cachedVariableNeedsUpdate (variable: IVariableAssignment): boolean {
145+
const cache = this.getCachedVariable(variable.filePath, variable.name);
146+
if (cache == null) return true;
147+
148+
const version = this.languageService.getFileVersion(variable.filePath);
149+
return version > cache.version;
150+
}
151+
152+
public cachedEnumNeedsUpdate (enumDeclaration: IEnumDeclaration): boolean {
153+
const cache = this.getCachedEnum(enumDeclaration.filePath, enumDeclaration.name);
154+
if (cache == null) return true;
155+
156+
const version = this.languageService.getFileVersion(enumDeclaration.filePath);
157+
return version > cache.version;
158+
}
159+
160+
public cachedFunctionNeedsUpdate (functionDeclaration: IFunctionDeclaration): boolean {
161+
const cache = this.getCachedFunction(functionDeclaration.filePath, functionDeclaration.name);
162+
if (cache == null) return true;
163+
164+
const version = this.languageService.getFileVersion(functionDeclaration.filePath);
165+
return version > cache.version;
166+
}
167+
168+
public cachedPropNeedsUpdate (prop: IPropDeclaration): boolean {
169+
const cache = this.getCachedProp(prop.filePath, prop.className, prop.name);
170+
if (cache == null) return true;
171+
172+
const version = this.languageService.getFileVersion(prop.filePath);
173+
return version > cache.version;
174+
}
175+
176+
public cachedClassNeedsUpdate (classDeclaration: IClassDeclaration): boolean {
177+
const cache = this.getCachedClass(classDeclaration.filePath, classDeclaration.name);
178+
if (cache == null) return true;
179+
180+
const version = this.languageService.getFileVersion(classDeclaration.filePath);
181+
return version > cache.version;
182+
}
183+
184+
public cachedFunctionIndexerNeedsUpdate (filePath: string): boolean {
185+
const cache = this.getCachedFunctionIndexer(this.getCachedFunctionIndexerName(filePath));
186+
if (cache == null) return true;
187+
188+
const version = this.languageService.getFileVersion(filePath);
189+
return version > cache.version;
190+
}
191+
192+
public cachedModuleDependenciesNeedsUpdate (filePath: string): boolean {
193+
const cache = this.getCachedModuleDependencies(this.getCachedModuleDependenciesName(filePath));
194+
if (cache == null) return true;
195+
196+
const version = this.languageService.getFileVersion(filePath);
197+
return version > cache.version;
198+
}
199+
200+
public cachedClassIndexerNeedsUpdate (filePath: string): boolean {
201+
const cache = this.getCachedClassIndexer(this.getCachedClassIndexerName(filePath));
202+
if (cache == null) return true;
203+
204+
const version = this.languageService.getFileVersion(filePath);
205+
return version > cache.version;
206+
}
207+
208+
public cachedEnumIndexerNeedsUpdate (filePath: string): boolean {
209+
const cache = this.getCachedEnumIndexer(this.getCachedEnumIndexerName(filePath));
210+
if (cache == null) return true;
211+
212+
const version = this.languageService.getFileVersion(filePath);
213+
return version > cache.version;
214+
}
215+
216+
public cachedVariableIndexerNeedsUpdate (filePath: string): boolean {
217+
const cache = this.getCachedVariableIndexer(this.getCachedVariableIndexerName(filePath));
218+
if (cache == null) return true;
219+
220+
const version = this.languageService.getFileVersion(filePath);
221+
return version > cache.version;
222+
}
223+
}

src/cache/interface/ICache.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {ClassIndexer, EnumIndexer, FunctionIndexer, ICachedContent, IClassDeclaration, IEnumDeclaration, IFunctionDeclaration, IImportDeclaration, IPropDeclaration, IVariableAssignment, VariableIndexer} from "../../interface/ISimpleLanguageService";
2+
3+
export interface ICache {
4+
getCachedPropName (fileName: string, className: string, propName: string): string;
5+
getCachedVariableName (fileName: string, variableName: string): string;
6+
getCachedEnumName (fileName: string, enumName: string): string;
7+
getCachedClassName (fileName: string, className: string): string;
8+
getCachedFunctionName (fileName: string, className: string): string;
9+
getCachedClassIndexerName (fileName: string): string;
10+
getCachedModuleDependenciesName (fileName: string): string;
11+
getCachedFunctionIndexerName (fileName: string): string;
12+
getCachedVariableIndexerName (fileName: string): string;
13+
getCachedEnumIndexerName (fileName: string): string;
14+
getFromCache<T> (key: string): ICachedContent<T> | null;
15+
getCachedVariable (fileName: string, variableName: string): ICachedContent<IVariableAssignment> | null;
16+
getCachedFunction (fileName: string, functionName: string): ICachedContent<IFunctionDeclaration> | null;
17+
getCachedEnum (fileName: string, enumName: string): ICachedContent<IEnumDeclaration> | null;
18+
getCachedProp (fileName: string, className: string, propName: string): ICachedContent<IPropDeclaration> | null;
19+
getCachedClass (fileName: string, className: string): ICachedContent<IClassDeclaration> | null;
20+
getCachedFunctionIndexer (fileName: string): ICachedContent<FunctionIndexer> | null;
21+
getCachedModuleDependencies (fileName: string): ICachedContent<IImportDeclaration[]> | null;
22+
getCachedClassIndexer (fileName: string): ICachedContent<ClassIndexer> | null;
23+
getCachedEnumIndexer (fileName: string): ICachedContent<EnumIndexer> | null;
24+
getCachedVariableIndexer (fileName: string): ICachedContent<VariableIndexer> | null;
25+
setCachedProp (fileName: string, content: IPropDeclaration): void;
26+
setCachedVariable (fileName: string, content: IVariableAssignment): void;
27+
setCachedEnum (fileName: string, content: IEnumDeclaration): void;
28+
setCachedClass (fileName: string, content: IClassDeclaration): void;
29+
setCachedFunction (fileName: string, content: IFunctionDeclaration): void;
30+
setCachedClassIndexer (fileName: string, content: ClassIndexer): void;
31+
setCachedFunctionIndexer (fileName: string, content: FunctionIndexer): void;
32+
setCachedModuleDependencies (fileName: string, content: IImportDeclaration[]): void;
33+
setCachedEnumIndexer (fileName: string, content: EnumIndexer): void;
34+
setCachedVariableIndexer (fileName: string, content: VariableIndexer): void;
35+
cachedVariableNeedsUpdate (variable: IVariableAssignment): boolean;
36+
cachedEnumNeedsUpdate (enumDeclaration: IEnumDeclaration): boolean;
37+
cachedFunctionNeedsUpdate (functionDeclaration: IFunctionDeclaration): boolean;
38+
cachedPropNeedsUpdate (prop: IPropDeclaration): boolean;
39+
cachedClassNeedsUpdate (classDeclaration: IClassDeclaration): boolean;
40+
cachedFunctionIndexerNeedsUpdate (filePath: string): boolean;
41+
cachedModuleDependenciesNeedsUpdate (filePath: string): boolean;
42+
cachedClassIndexerNeedsUpdate (filePath: string): boolean;
43+
cachedEnumIndexerNeedsUpdate (filePath: string): boolean;
44+
cachedVariableIndexerNeedsUpdate (filePath: string): boolean;
45+
}

0 commit comments

Comments
 (0)