Skip to content

Commit d752f1e

Browse files
committed
Refactored import/export payloads for consistency by adding an ILiteralValue IIdentifier kind
1 parent f947520 commit d752f1e

File tree

15 files changed

+359
-105
lines changed

15 files changed

+359
-105
lines changed

src/formatter/ExportFormatter.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {ModuleFormatter} from "./ModuleFormatter";
1515
import {IMutationFormatter} from "./interface/IMutationFormatter";
1616
import {ICallExpressionFormatter} from "./interface/ICallExpressionFormatter";
1717
import {IValueableFormatter} from "./interface/IValueableFormatter";
18-
import {IMarshaller} from "@wessberg/marshaller";
1918
import {IRequireFormatter} from "./interface/IRequireFormatter";
2019

2120
export class ExportFormatter extends ModuleFormatter implements IExportFormatter {
@@ -32,10 +31,9 @@ export class ExportFormatter extends ModuleFormatter implements IExportFormatter
3231
private functionFormatter: IFunctionFormatter,
3332
private nameGetter: INameGetter,
3433
private tracer: ITracer,
35-
marshaller: IMarshaller,
3634
stringUtil: IStringUtil,
3735
fileLoader: IFileLoader) {
38-
super(stringUtil, marshaller, fileLoader);
36+
super(stringUtil, fileLoader);
3937
}
4038

4139
public format (statement: ExportDeclaration|VariableStatement|ExportAssignment|FunctionDeclaration|ClassDeclaration|ExpressionStatement|BinaryExpression|CallExpression): IExportDeclaration|null {
@@ -114,11 +112,16 @@ export class ExportFormatter extends ModuleFormatter implements IExportFormatter
114112

115113
if (isLiteralExpression(statement.expression)) {
116114
const value = this.valueableFormatter.format(statement.expression);
117-
return value.hasDoneFirstResolve() ? value.resolved : value.resolve();
115+
return {
116+
___kind: IdentifierMapKind.LITERAL,
117+
startsAt: statement.expression.pos,
118+
endsAt: statement.expression.end,
119+
value: () => value.hasDoneFirstResolve() ? value.resolved : value.resolve()
120+
}
118121
} else {
119122
const identifier = this.nameGetter.getName(statement.expression);
120123
const scope = this.tracer.traceThis(statement);
121-
return identifier == null ? null : this.tracer.traceIdentifier(identifier, statement, scope);
124+
return this.tracer.traceIdentifier(identifier, statement, scope);
122125
}
123126
};
124127

@@ -164,7 +167,14 @@ export class ExportFormatter extends ModuleFormatter implements IExportFormatter
164167
const isCandidate = formatted.property === "exports" && formatted.identifier !== "undefined" && formatted.identifier !== undefined;
165168
if (!isCandidate) return null;
166169

167-
const payload = () => formatted.value.hasDoneFirstResolve() ? formatted.value.resolved : formatted.value.resolve();
170+
const payload = () => {
171+
return {
172+
___kind: IdentifierMapKind.LITERAL,
173+
startsAt: statement.pos,
174+
endsAt: statement.end,
175+
value: () => formatted.value.hasDoneFirstResolve() ? formatted.value.resolved : formatted.value.resolve()
176+
}
177+
};
168178
const sourceFileProperties = this.sourceFilePropertiesGetter.getSourceFileProperties(statement);
169179
const filePath = sourceFileProperties.filePath;
170180

@@ -387,7 +397,12 @@ export class ExportFormatter extends ModuleFormatter implements IExportFormatter
387397
if (clause == null) {
388398
const payload = () => {
389399
const path = modulePath();
390-
return this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true));
400+
return {
401+
___kind: IdentifierMapKind.LITERAL,
402+
startsAt: statement.pos,
403+
endsAt: statement.end,
404+
value: () => this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true))
405+
}
391406
};
392407

393408
indexer[NAMESPACE_NAME] = {
@@ -403,12 +418,15 @@ export class ExportFormatter extends ModuleFormatter implements IExportFormatter
403418
clause.elements.forEach(element => {
404419

405420
const payload = () => {
421+
const path = modulePath();
406422
const block = this.tracer.traceBlockScopeName(clause);
407-
const clojure = this.tracer.traceClojure(modulePath());
408-
409-
return typeof clojure === "string"
410-
? clojure
411-
: this.tracer.findNearestMatchingIdentifier(element, block, element.name.text, clojure);
423+
const clojure = this.tracer.traceClojure(path);
424+
return clojure == null ? {
425+
___kind: IdentifierMapKind.LITERAL,
426+
startsAt: element.pos,
427+
endsAt: element.end,
428+
value: () => path
429+
} : this.tracer.findNearestMatchingIdentifier(element, block, element.name.text, clojure);
412430
};
413431

414432
indexer[element.name.text] = {

src/formatter/ImportFormatter.ts

Lines changed: 79 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import {INameGetter} from "../getter/interface/INameGetter";
44
import {ISourceFilePropertiesGetter} from "../getter/interface/ISourceFilePropertiesGetter";
55
import {IMapper} from "../mapper/interface/IMapper";
66
import {IBindingIdentifier} from "../model/interface/IBindingIdentifier";
7-
import {isCallExpression, isExternalModuleReference, isIdentifierObject, isImportDeclaration, isImportEqualsDeclaration, isNamedImports, isNamespaceImport, isVariableDeclaration, isVariableDeclarationList, isVariableStatement} from "../predicate/PredicateFunctions";
7+
import {isArrayBindingPattern, isCallExpression, isExternalModuleReference, isIdentifierObject, isImportDeclaration, isImportEqualsDeclaration, isNamedImports, isNamespaceImport, isObjectBindingPattern, isOmittedExpression, isVariableDeclaration, isVariableDeclarationList, isVariableStatement} from "../predicate/PredicateFunctions";
88
import {ICodeAnalyzer, IdentifierMapKind, IImportDeclaration, ImportExportIndexer, ImportExportKind, IRequire, ModuleDependencyKind, NAMESPACE_NAME} from "../service/interface/ICodeAnalyzer";
99
import {ITracer} from "../tracer/interface/ITracer";
1010
import {IStringUtil} from "../util/interface/IStringUtil";
1111
import {IImportFormatter} from "./interface/IImportFormatter";
1212
import {ModuleFormatter} from "./ModuleFormatter";
1313
import {IRequireFormatter} from "./interface/IRequireFormatter";
14-
import {IMarshaller} from "@wessberg/marshaller";
1514

1615
export class ImportFormatter extends ModuleFormatter implements IImportFormatter {
1716
constructor (private languageService: ICodeAnalyzer,
@@ -20,10 +19,9 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
2019
private requireFormatter: IRequireFormatter,
2120
private mapper: IMapper,
2221
private tracer: ITracer,
23-
marshaller: IMarshaller,
2422
stringUtil: IStringUtil,
2523
fileLoader: IFileLoader) {
26-
super(stringUtil, marshaller, fileLoader);
24+
super(stringUtil, fileLoader);
2725
}
2826

2927
public format (statement: ImportDeclaration|ImportEqualsDeclaration|VariableStatement|CallExpression): IImportDeclaration|null {
@@ -123,7 +121,12 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
123121
const clojure = this.tracer.traceClojure(statement);
124122

125123
const payload = () => {
126-
return typeof clojure === "string" ? clojure : this.tracer.findNearestMatchingIdentifier(statement, block, source.toString(), clojure);
124+
return clojure == null ? {
125+
___kind: IdentifierMapKind.LITERAL,
126+
startsAt: statement.moduleReference.pos,
127+
endsAt: statement.moduleReference.end,
128+
value: () => clojure
129+
} : this.tracer.findNearestMatchingIdentifier(statement, block, source.toString(), clojure);
127130
};
128131

129132
const map: IImportDeclaration = {
@@ -169,15 +172,59 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
169172
}
170173

171174
private formatVariableDeclaration (statement: VariableDeclaration): IImportDeclaration|null {
172-
const name = this.nameGetter.getName(statement.name);
173-
return this.formatCallExpression(statement, name == null ? undefined : name);
175+
return this.formatCallExpression(statement);
174176
}
175177

176-
private formatCallExpression (statement: CallExpression|VariableStatement|VariableDeclaration|VariableDeclarationList, name: string = NAMESPACE_NAME): IImportDeclaration|null {
178+
private formatCallExpression (statement: CallExpression|VariableDeclaration): IImportDeclaration|null {
177179
const requireCall = this.requireFormatter.format(statement);
178180
if (requireCall == null) return null;
179181
const {startsAt, endsAt, relativePath, fullPath, filePath, payload} = requireCall;
180182

183+
let bindings: ImportExportIndexer = {};
184+
const name: (string|undefined)[] = [];
185+
let kind: ImportExportKind;
186+
187+
if (isCallExpression(statement)) {
188+
name.push(NAMESPACE_NAME);
189+
kind = ImportExportKind.NAMESPACE;
190+
} else {
191+
192+
if (isObjectBindingPattern(statement.name)) {
193+
statement.name.elements.forEach(binding => {
194+
name.push(<string>this.nameGetter.getName(binding));
195+
kind = ImportExportKind.NAMED;
196+
});
197+
}
198+
199+
else if (isArrayBindingPattern(statement.name)) {
200+
statement.name.elements.forEach((binding) => {
201+
if (isOmittedExpression(binding)) name.push(undefined);
202+
name.push(<string>this.nameGetter.getName(binding));
203+
kind = ImportExportKind.NAMED;
204+
});
205+
}
206+
207+
else {
208+
name.push(<string>this.nameGetter.getNameOfMember(statement.name, false, true));
209+
kind = ImportExportKind.NAMESPACE;
210+
}
211+
}
212+
213+
name.forEach(part => {
214+
// TODO: Respect ArrayBindingPatterns or ObjectBindingPatterns.
215+
if (part == null) return;
216+
217+
bindings[part] = {
218+
startsAt: requireCall.arguments.startsAt,
219+
endsAt: requireCall.arguments.endsAt,
220+
___kind: IdentifierMapKind.IMPORT_EXPORT_BINDING,
221+
name: part,
222+
payload,
223+
kind
224+
};
225+
this.mapper.set(bindings[part], statement);
226+
});
227+
181228
const map: IImportDeclaration = {
182229
___kind: IdentifierMapKind.IMPORT,
183230
startsAt,
@@ -188,18 +235,9 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
188235
fullPath
189236
},
190237
filePath,
191-
bindings: {
192-
[name]: {
193-
startsAt: requireCall.arguments.startsAt,
194-
endsAt: requireCall.arguments.endsAt,
195-
___kind: IdentifierMapKind.IMPORT_EXPORT_BINDING,
196-
name,
197-
payload,
198-
kind: ImportExportKind.NAMESPACE
199-
}
200-
}
238+
bindings
201239
};
202-
this.mapper.set(map.bindings[name], statement);
240+
203241
// Make the kind non-enumerable.
204242
Object.defineProperty(map, "___kind", {
205243
value: IdentifierMapKind.IMPORT,
@@ -219,30 +257,41 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
219257
private formatImportClause (clause: ImportClause, modulePath: () => string): ImportExportIndexer {
220258
const indexer: ImportExportIndexer = {};
221259

222-
if (clause.namedBindings != null && isNamespaceImport(clause.namedBindings)) {
260+
const namedBindings = clause.namedBindings;
261+
if (namedBindings != null && isNamespaceImport(namedBindings)) {
223262
const payload = () => {
224263
const path = modulePath();
225-
return this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true));
264+
return {
265+
___kind: IdentifierMapKind.LITERAL,
266+
startsAt: namedBindings.pos,
267+
endsAt: namedBindings.end,
268+
value: () => this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true))
269+
};
226270
};
227271

228-
indexer[clause.namedBindings.name.text] = {
229-
startsAt: clause.namedBindings.name.pos,
230-
endsAt: clause.namedBindings.name.end,
272+
indexer[namedBindings.name.text] = {
273+
startsAt: namedBindings.name.pos,
274+
endsAt: namedBindings.name.end,
231275
___kind: IdentifierMapKind.IMPORT_EXPORT_BINDING,
232-
name: clause.namedBindings.name.text,
276+
name: namedBindings.name.text,
233277
payload,
234278
kind: ImportExportKind.NAMESPACE
235279
};
236-
this.mapper.set(indexer[clause.namedBindings.name.text], clause.namedBindings);
280+
this.mapper.set(indexer[namedBindings.name.text], namedBindings);
237281
}
238282

239-
else if (clause.namedBindings != null && isNamedImports(clause.namedBindings)) {
240-
clause.namedBindings.elements.forEach(element => {
283+
else if (namedBindings != null && isNamedImports(namedBindings)) {
284+
namedBindings.elements.forEach(element => {
241285
const block = this.tracer.traceBlockScopeName(clause);
242286
const payload = () => {
243287
const path = modulePath();
244288
const clojure = this.tracer.traceClojure(path);
245-
return typeof clojure === "string" ? clojure : this.tracer.findNearestMatchingIdentifier(element, block, element.name.text, clojure);
289+
return clojure == null ? {
290+
___kind: IdentifierMapKind.LITERAL,
291+
startsAt: element.pos,
292+
endsAt: element.end,
293+
value: () => path
294+
} : this.tracer.findNearestMatchingIdentifier(element, block, element.name.text, clojure);
246295
};
247296

248297
indexer[element.name.text] = {
@@ -263,7 +312,7 @@ export class ImportFormatter extends ModuleFormatter implements IImportFormatter
263312
const fileExports = this.languageService.getExportDeclarationsForFile(path, true);
264313
const match = fileExports.find(exportDeclaration => exportDeclaration.bindings["default"] != null);
265314
if (match == null) throw new ReferenceError(`${this.formatImportClause.name} could not extract a default export from ${modulePath}! The module doesn't contain a default export.`);
266-
return match.bindings["default"].payload;
315+
return match.bindings["default"].payload();
267316
};
268317

269318
indexer[clause.name.text] = {

src/formatter/ModuleFormatter.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ import {Config} from "../static/Config";
55
import {IStringUtil} from "../util/interface/IStringUtil";
66
import {IModuleFormatter} from "./interface/IModuleFormatter";
77
import "querystring";
8-
import {IMarshaller} from "@wessberg/marshaller";
98
import {BindingIdentifier} from "../model/BindingIdentifier";
9+
import {isIImportExportBinding, isILiteralValue, isNamespacedModuleMap} from "../predicate/PredicateFunctions";
1010

1111
export abstract class ModuleFormatter implements IModuleFormatter {
1212
private static readonly RESOLVED_PATHS: Map<string, string> = new Map();
1313

1414
constructor (protected stringUtil: IStringUtil,
15-
private marshaller: IMarshaller,
1615
private fileLoader: IFileLoader) {
1716
}
1817

@@ -40,7 +39,12 @@ export abstract class ModuleFormatter implements IModuleFormatter {
4039

4140
const isNamespace = binding.name === NAMESPACE_NAME;
4241
// If it isn't a namespace, just add the key to the object.
43-
if (!isNamespace) indexer[key] = binding.payload();
42+
43+
if (!isNamespace) {
44+
let payload = binding.payload();
45+
while (isIImportExportBinding(payload)) payload = payload.payload();
46+
indexer[key] = payload;
47+
}
4448
else {
4549
if (!(moduleDeclaration.source instanceof BindingIdentifier)) {
4650
const path = moduleDeclaration.source.fullPath();
@@ -50,9 +54,14 @@ export abstract class ModuleFormatter implements IModuleFormatter {
5054
}
5155
}
5256
// Merge the two.
53-
let payload = <NamespacedModuleMap>binding.payload();
54-
if (typeof payload === "string") payload = <NamespacedModuleMap>this.marshaller.marshal(payload, {});
55-
Object.keys(payload).forEach(key => indexer[key] = payload[key]);
57+
let payload = binding.payload();
58+
while (isIImportExportBinding(payload)) payload = payload.payload();
59+
if (isILiteralValue(payload)) {
60+
const value = payload.value();
61+
if (isNamespacedModuleMap(value)) {
62+
Object.keys(value).forEach(key => indexer[key] = (<any>value)[key]);
63+
}
64+
}
5665
}
5766
});
5867
});

src/formatter/RequireFormatter.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {IFileLoader} from "@wessberg/fileloader";
88
import {isCallExpression, isExternalModuleReference, isICallExpression, isParenthesizedExpression, isVariableDeclaration, isVariableDeclarationList, isVariableStatement} from "../predicate/PredicateFunctions";
99
import {IValueableFormatter} from "./interface/IValueableFormatter";
1010
import {ISourceFilePropertiesGetter} from "../getter/interface/ISourceFilePropertiesGetter";
11-
import {IMarshaller} from "@wessberg/marshaller";
1211

1312
export class RequireFormatter extends ModuleFormatter implements IRequireFormatter {
1413

@@ -17,9 +16,8 @@ export class RequireFormatter extends ModuleFormatter implements IRequireFormatt
1716
private valueableFormatter: IValueableFormatter,
1817
private callExpressionFormatter: ICallExpressionFormatter,
1918
protected stringUtil: IStringUtil,
20-
marshaller: IMarshaller,
2119
fileLoader: IFileLoader) {
22-
super(stringUtil, marshaller, fileLoader);
20+
super(stringUtil, fileLoader);
2321
}
2422
/**
2523
* Formats the given CallExpression and returns an IRequire.
@@ -60,7 +58,12 @@ export class RequireFormatter extends ModuleFormatter implements IRequireFormatt
6058

6159
const payload = () => {
6260
const path = fullPath();
63-
return this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true));
61+
return {
62+
___kind: IdentifierMapKind.LITERAL,
63+
startsAt: statement.pos,
64+
endsAt: statement.end,
65+
value: () => this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true))
66+
};
6467
};
6568

6669
const map: IRequire = {
@@ -133,7 +136,13 @@ export class RequireFormatter extends ModuleFormatter implements IRequireFormatt
133136

134137
const payload = () => {
135138
const path = fullPath();
136-
return this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true));
139+
return {
140+
___kind: IdentifierMapKind.LITERAL,
141+
startsAt: isICallExpression(statement) ? statement.startsAt : statement.pos,
142+
endsAt: isICallExpression(statement) ? statement.endsAt : statement.end,
143+
value: () => this.moduleToNamespacedObjectLiteral(this.languageService.getExportDeclarationsForFile(path, true))
144+
};
145+
;
137146
};
138147

139148
const map: IRequire = {

0 commit comments

Comments
 (0)