1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const fs = require("fs");
|
4 | const path = require("path");
|
5 | const resolution_1 = require("./resolution");
|
6 | class VueProgram {
|
7 | static loadProgramConfig(typescript, configFile, compilerOptions) {
|
8 | const extraExtensions = ['vue'];
|
9 | const parseConfigHost = {
|
10 | fileExists: typescript.sys.fileExists,
|
11 | readFile: typescript.sys.readFile,
|
12 | useCaseSensitiveFileNames: typescript.sys.useCaseSensitiveFileNames,
|
13 | readDirectory: (rootDir, extensions, excludes, includes, depth) => {
|
14 | return typescript.sys.readDirectory(rootDir, extensions.concat(extraExtensions), excludes, includes, depth);
|
15 | }
|
16 | };
|
17 | const tsconfig = typescript.readConfigFile(configFile, typescript.sys.readFile).config;
|
18 | tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
19 | tsconfig.compilerOptions = Object.assign({}, tsconfig.compilerOptions, compilerOptions);
|
20 | const parsed = typescript.parseJsonConfigFileContent(tsconfig, parseConfigHost, path.dirname(configFile));
|
21 | parsed.options.allowNonTsExtensions = true;
|
22 | return parsed;
|
23 | }
|
24 | |
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | static resolveNonTsModuleName(moduleName, containingFile, basedir, options) {
|
31 | const baseUrl = options.baseUrl ? options.baseUrl : basedir;
|
32 | const discardedSymbols = ['.', '..', '/'];
|
33 | const wildcards = [];
|
34 | if (options.paths) {
|
35 | Object.keys(options.paths).forEach(key => {
|
36 | const pathSymbol = key[0];
|
37 | if (discardedSymbols.indexOf(pathSymbol) < 0 &&
|
38 | wildcards.indexOf(pathSymbol) < 0) {
|
39 | wildcards.push(pathSymbol);
|
40 | }
|
41 | });
|
42 | }
|
43 | else {
|
44 | wildcards.push('@');
|
45 | }
|
46 | const isRelative = !path.isAbsolute(moduleName);
|
47 | let correctWildcard;
|
48 | wildcards.forEach(wildcard => {
|
49 | if (moduleName.substr(0, 2) === `${wildcard}/`) {
|
50 | correctWildcard = wildcard;
|
51 | }
|
52 | });
|
53 | if (correctWildcard) {
|
54 | const pattern = options.paths
|
55 | ? options.paths[`${correctWildcard}/*`]
|
56 | : undefined;
|
57 | const substitution = pattern
|
58 | ? options.paths[`${correctWildcard}/*`][0].replace('*', '')
|
59 | : 'src';
|
60 | moduleName = path.resolve(baseUrl, substitution, moduleName.substr(2));
|
61 | }
|
62 | else if (isRelative) {
|
63 | moduleName = path.resolve(path.dirname(containingFile), moduleName);
|
64 | }
|
65 | return moduleName;
|
66 | }
|
67 | static isVue(filePath) {
|
68 | return path.extname(filePath) === '.vue';
|
69 | }
|
70 | static createProgram(typescript, programConfig, basedir, files, watcher, oldProgram, userResolveModuleName, userResolveTypeReferenceDirective) {
|
71 | const host = typescript.createCompilerHost(programConfig.options);
|
72 | const realGetSourceFile = host.getSourceFile;
|
73 | const { resolveModuleName, resolveTypeReferenceDirective } = resolution_1.makeResolutionFunctions(userResolveModuleName, userResolveTypeReferenceDirective);
|
74 | host.resolveModuleNames = (moduleNames, containingFile) => {
|
75 | return moduleNames.map(moduleName => {
|
76 | return resolveModuleName(typescript, moduleName, containingFile, programConfig.options, host).resolvedModule;
|
77 | });
|
78 | };
|
79 | host.resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile) => {
|
80 | return typeDirectiveNames.map(typeDirectiveName => {
|
81 | return resolveTypeReferenceDirective(typescript, typeDirectiveName, containingFile, programConfig.options, host).resolvedTypeReferenceDirective;
|
82 | });
|
83 | };
|
84 |
|
85 | host.getSourceFile = (filePath, languageVersion, onError) => {
|
86 |
|
87 | if (!watcher.isWatchingFile(filePath)) {
|
88 | try {
|
89 | const stats = fs.statSync(filePath);
|
90 | files.setMtime(filePath, stats.mtime.valueOf());
|
91 | }
|
92 | catch (e) {
|
93 |
|
94 | files.remove(filePath);
|
95 | }
|
96 | }
|
97 |
|
98 | if (!files.has(filePath) || !files.getData(filePath).source) {
|
99 | files.mutateData(filePath, data => {
|
100 | data.source = realGetSourceFile(filePath, languageVersion, onError);
|
101 | });
|
102 | }
|
103 | let source = files.getData(filePath).source;
|
104 |
|
105 | if (source && VueProgram.isVue(filePath)) {
|
106 | const resolved = VueProgram.resolveScriptBlock(typescript, source.text);
|
107 | source = typescript.createSourceFile(filePath, resolved.content, languageVersion, true, resolved.scriptKind);
|
108 | }
|
109 | return source;
|
110 | };
|
111 |
|
112 | host.resolveModuleNames = (moduleNames, containingFile) => {
|
113 | const resolvedModules = [];
|
114 | for (const moduleName of moduleNames) {
|
115 |
|
116 | const { resolvedModule } = typescript.resolveModuleName(moduleName, containingFile, programConfig.options, {
|
117 | fileExists(fileName) {
|
118 | if (fileName.endsWith('.vue.ts')) {
|
119 | return (host.fileExists(fileName.slice(0, -3)) ||
|
120 | host.fileExists(fileName));
|
121 | }
|
122 | else {
|
123 | return host.fileExists(fileName);
|
124 | }
|
125 | },
|
126 | readFile(fileName) {
|
127 |
|
128 | if (fileName.endsWith('.vue.ts') && !host.fileExists(fileName)) {
|
129 | return host.readFile(fileName.slice(0, -3));
|
130 | }
|
131 | else {
|
132 | return host.readFile(fileName);
|
133 | }
|
134 | }
|
135 | });
|
136 | if (resolvedModule) {
|
137 | if (resolvedModule.resolvedFileName.endsWith('.vue.ts') &&
|
138 | !host.fileExists(resolvedModule.resolvedFileName)) {
|
139 | resolvedModule.resolvedFileName = resolvedModule.resolvedFileName.slice(0, -3);
|
140 | }
|
141 | resolvedModules.push(resolvedModule);
|
142 | }
|
143 | else {
|
144 |
|
145 | const absolutePath = VueProgram.resolveNonTsModuleName(moduleName, containingFile, basedir, programConfig.options);
|
146 | if (VueProgram.isVue(moduleName)) {
|
147 | resolvedModules.push({
|
148 | resolvedFileName: absolutePath,
|
149 | extension: '.ts'
|
150 | });
|
151 | }
|
152 | else {
|
153 | resolvedModules.push({
|
154 |
|
155 | resolvedFileName: host.fileExists(absolutePath)
|
156 | ? ''
|
157 | : absolutePath,
|
158 | extension: '.ts'
|
159 | });
|
160 | }
|
161 | }
|
162 | }
|
163 | return resolvedModules;
|
164 | };
|
165 | return typescript.createProgram(programConfig.fileNames, programConfig.options, host, oldProgram
|
166 | );
|
167 | }
|
168 | static getScriptKindByLang(typescript, lang) {
|
169 | if (lang === 'ts') {
|
170 | return typescript.ScriptKind.TS;
|
171 | }
|
172 | else if (lang === 'tsx') {
|
173 | return typescript.ScriptKind.TSX;
|
174 | }
|
175 | else if (lang === 'jsx') {
|
176 | return typescript.ScriptKind.JSX;
|
177 | }
|
178 | else {
|
179 |
|
180 | return typescript.ScriptKind.JS;
|
181 | }
|
182 | }
|
183 | static resolveScriptBlock(typescript, content) {
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | let parser;
|
189 | try {
|
190 |
|
191 | parser = require('vue-template-compiler');
|
192 | }
|
193 | catch (err) {
|
194 | throw new Error('When you use `vue` option, make sure to install `vue-template-compiler`.');
|
195 | }
|
196 | const { script } = parser.parseComponent(content, {
|
197 | pad: 'space'
|
198 | });
|
199 |
|
200 | if (!script) {
|
201 | return {
|
202 | scriptKind: typescript.ScriptKind.JS,
|
203 | content: '/* tslint:disable */\nexport default {};\n'
|
204 | };
|
205 | }
|
206 | const scriptKind = VueProgram.getScriptKindByLang(typescript, script.lang);
|
207 |
|
208 | if (script.attrs.src) {
|
209 |
|
210 | const src = script.attrs.src.replace(/\.tsx?$/i, '');
|
211 | return {
|
212 | scriptKind,
|
213 |
|
214 |
|
215 |
|
216 | content: '/* tslint:disable */\n' +
|
217 | '// @ts-ignore\n' +
|
218 | `export { default } from '${src}';\n` +
|
219 | '// @ts-ignore\n' +
|
220 | `export * from '${src}';\n`
|
221 | };
|
222 | }
|
223 |
|
224 |
|
225 |
|
226 | const offset = content.slice(0, script.start).split(/\r?\n/g).length;
|
227 | const paddedContent = Array(offset).join('//\n') + script.content.slice(script.start);
|
228 | return {
|
229 | scriptKind,
|
230 | content: paddedContent
|
231 | };
|
232 | }
|
233 | }
|
234 | exports.VueProgram = VueProgram;
|
235 |
|
\ | No newline at end of file |