Skip to content
This repository was archived by the owner on Dec 1, 2019. It is now read-only.

Commit 77a67df

Browse files
author
Stanislav Panferov
committed
feat(*): implement node-style module resolution
1 parent 5c7a157 commit 77a67df

File tree

6 files changed

+63
-43
lines changed

6 files changed

+63
-43
lines changed

README.md

-5
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,6 @@ Specify path to a TS config file. Useful when you have multiple config files. Th
9999

100100
Use this setting to force loader to use webpack's way to load files. Useful only with ts-jsx-loader. Builds may become slower.
101101

102-
### rewriteImports *(array)*
103-
104-
Array of modules that must be processed by webpack in imports. Useful if you want to use `some-lib`
105-
with pure TS files inside your app.
106-
107102
### externals *(array)*
108103

109104
Array of paths to .d.ts files that must be included in program. Useful with `rewriteImports`.

package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
"homepage": "https://github.com/s-panferov/awesome-typescript-loader",
2626
"dependencies": {
2727
"bluebird": "^2.7.1",
28+
"colors": "^1.1.2",
29+
"deasync": "^0.1.1",
2830
"loader-utils": "^0.2.6",
2931
"lodash": "^3.10.0",
30-
"object-assign": "^2.0.0",
31-
"colors": "^1.1.2"
32+
"object-assign": "^2.0.0"
3233
},
3334
"devDependencies": {
34-
"typescript": "1.6.0-dev.20150801",
3535
"git-hooks": "0.0.10",
3636
"grunt": "^0.4.5",
3737
"grunt-bump": "^0.3.1",
@@ -41,6 +41,7 @@
4141
"grunt-conventional-changelog": "^1.2.1",
4242
"grunt-shell": "^1.1.2",
4343
"grunt-ts": "^3.0.0",
44-
"load-grunt-tasks": "^0.6.0"
44+
"load-grunt-tasks": "^0.6.0",
45+
"typescript": "^1.7.0-dev.20150901"
4546
}
4647
}

src/deps.ts

-26
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,6 @@ function pathWithoutExt(fileName) {
3131
);
3232
}
3333

34-
function needRewrite(rewriteImports, importPath): boolean {
35-
return rewriteImports && _.any(rewriteImports, (i) => {
36-
return importPath.split('/')[0] == i
37-
})
38-
}
39-
40-
function updateText(text, pos, end, newText): string {
41-
return text.slice(0, pos) + ` '${newText}'` + text.slice(end, text.length);
42-
}
43-
4434
function isImportOrExportDeclaration(node: ts.Node) {
4535
return (!!(<any>node).exportClause || !!(<any>node).importClause)
4636
&& (<any>node).moduleSpecifier;
@@ -128,7 +118,6 @@ export class FileAnalyzer {
128118

129119
let isDeclaration = isTypeDeclaration(fileName);
130120

131-
let rewrites: {pos: number, end: number, module: string}[] = [];
132121
let resolves: Promise<void>[] = [];
133122

134123
let result = [];
@@ -137,23 +126,13 @@ export class FileAnalyzer {
137126
// we need this check to ensure that we have an external import
138127
let importPath = (<any>node).moduleReference.expression.text;
139128
resolves.push(this.resolve(resolver, fileName, importPath).then((absolutePath) => {
140-
if (needRewrite(this.state.options.rewriteImports, importPath)) {
141-
let { pos, end } = (<any>node).moduleReference.expression;
142-
let module = pathWithoutExt(absolutePath);
143-
rewrites.push({ pos, end, module });
144-
}
145129
if (!isIgnoreDependency(absolutePath)) {
146130
result.push(absolutePath);
147131
}
148132
}));
149133
} else if (!isDeclaration && isImportOrExportDeclaration(node)) {
150134
let importPath = (<any>node).moduleSpecifier.text;
151135
resolves.push(this.resolve(resolver, fileName, importPath).then((absolutePath) => {
152-
if (needRewrite(this.state.options.rewriteImports, importPath)) {
153-
let module = pathWithoutExt(absolutePath);
154-
let { pos, end } = (<any>node).moduleSpecifier;
155-
rewrites.push({ pos, end, module });
156-
}
157136
if (!isIgnoreDependency(absolutePath)) {
158137
result.push(absolutePath);
159138
}
@@ -168,11 +147,6 @@ export class FileAnalyzer {
168147

169148
visit(sourceFile);
170149
return Promise.all(resolves).then(() => {
171-
let orderedRewrites = (<any>_).sortByAll(rewrites, 'pos', 'end').reverse();
172-
orderedRewrites.forEach(({ pos, end, module }) => {
173-
scriptSnapshot = updateText(scriptSnapshot, pos, end, module)
174-
});
175-
this.state.updateFile(fileName, scriptSnapshot);
176150
return result;
177151
});
178152
}

src/helpers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3-
import * as host from 'host';
3+
import * as host from './host';
44

55
function isFileEmit(fileName, outputFileName, sourceFileName) {
66
return sourceFileName === fileName

src/host.ts

+53-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export interface ICompilerInfo {
2424
lib6: { fileName: string, text: string };
2525
}
2626

27+
export interface SyncResolver {
28+
(context: string, fileName: string): string;
29+
}
30+
2731
export interface ICompilerOptions extends ts.CompilerOptions {
2832
noLib?: boolean;
2933
instanceName?: string;
@@ -34,7 +38,6 @@ export interface ICompilerOptions extends ts.CompilerOptions {
3438
reEmitDependentFiles?: boolean;
3539
tsconfig?: string;
3640
useWebpackText?: boolean;
37-
rewriteImports?: any;
3841
externals?: any;
3942
doTypeCheck?: boolean;
4043
forkChecker?: boolean;
@@ -53,12 +56,31 @@ export interface IEmitOutput extends ts.EmitOutput {
5356
outputFiles: IOutputFile[]
5457
}
5558

59+
export class ModuleResolutionHost implements ts.ModuleResolutionHost {
60+
servicesHost: Host;
61+
62+
constructor(servicesHost: Host) {
63+
this.servicesHost = servicesHost;
64+
}
65+
66+
fileExists(fileName: string) {
67+
return this.servicesHost.getScriptSnapshot(fileName) !== undefined;
68+
}
69+
70+
readFile(fileName: string): string {
71+
let snapshot = this.servicesHost.getScriptSnapshot(fileName);
72+
return snapshot && snapshot.getText(0, snapshot.getLength());
73+
}
74+
}
75+
5676
export class Host implements ts.LanguageServiceHost {
5777

5878
state: State;
79+
moduleResolutionHost: ModuleResolutionHost
5980

6081
constructor(state: State) {
6182
this.state = state;
83+
this.moduleResolutionHost = new ModuleResolutionHost(this);
6284
}
6385

6486
getScriptFileNames() {
@@ -96,6 +118,32 @@ export class Host implements ts.LanguageServiceHost {
96118
this.state.compilerInfo.lib5.fileName;
97119
}
98120

121+
resolveModuleNames(moduleNames: string[], containingFile: string) {
122+
let resolvedFileNames: string[] = [];
123+
124+
for (let moduleName of moduleNames) {
125+
let resolvedFileName: string;
126+
try {
127+
resolvedFileName = this.state.resolver(containingFile, moduleName)
128+
if (!resolvedFileName.match(/\.tsx?$/)) resolvedFileName = null;
129+
}
130+
catch (e) { resolvedFileName = null }
131+
132+
if (!resolvedFileName) {
133+
resolvedFileName = this.state.ts.resolveModuleName(
134+
moduleName,
135+
containingFile,
136+
this.state.options,
137+
this.moduleResolutionHost
138+
).resolvedFileName
139+
}
140+
141+
resolvedFileNames.push(resolvedFileName);
142+
}
143+
144+
return resolvedFileNames;
145+
}
146+
99147
log(message) {
100148
//console.log(message);
101149
}
@@ -113,14 +161,17 @@ export class State {
113161
options: ICompilerOptions;
114162
program: ts.Program;
115163
fileAnalyzer: FileAnalyzer;
164+
resolver: SyncResolver;
116165

117166
constructor(
118167
options: ICompilerOptions,
119168
fsImpl: typeof fs,
120-
compilerInfo: ICompilerInfo
169+
compilerInfo: ICompilerInfo,
170+
resolver: SyncResolver
121171
) {
122172
this.ts = compilerInfo.tsImpl;
123173
this.compilerInfo = compilerInfo;
174+
this.resolver = resolver;
124175
this.fs = fsImpl;
125176
this.host = new Host(this);
126177
this.services = this.ts.createLanguageService(this.host, this.ts.createDocumentRegistry());

src/index.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import * as helpers from './helpers';
1515
import { loadLib } from './helpers';
1616

1717
let loaderUtils = require('loader-utils');
18+
let deasync = require('deasync');
1819

1920
let pkg = require('../package.json');
2021
let cachePromise = Promise.promisify(cache);
@@ -225,10 +226,6 @@ function ensureInstance(webpack: IWebPack, options: ICompilerOptions, instanceNa
225226
}
226227
}
227228

228-
if (typeof options.rewriteImports == 'undefined') {
229-
options.rewriteImports = [];
230-
}
231-
232229
if (typeof options.externals == 'undefined') {
233230
options.externals = [];
234231
}
@@ -276,7 +273,9 @@ function ensureInstance(webpack: IWebPack, options: ICompilerOptions, instanceNa
276273
}
277274
}
278275

279-
let tsState = new State(options, webpack._compiler.inputFileSystem, compilerInfo);
276+
let syncResolver = deasync(webpack.resolve);
277+
278+
let tsState = new State(options, webpack._compiler.inputFileSystem, compilerInfo, syncResolver);
280279
let compiler = (<any>webpack._compiler);
281280

282281
compiler.plugin('watch-run', (watching, callback) => {

0 commit comments

Comments
 (0)