|
1 | 1 | import * as https from 'https'
|
| 2 | +import Module from 'module' |
2 | 3 | const concat = require('concat-stream')
|
| 4 | +import * as YarnLockFile from '@yarnpkg/lockfile' |
| 5 | +import * as path from 'path' |
| 6 | +import * as fs from 'fs' |
3 | 7 |
|
4 | 8 | type TSModule = typeof import('typescript')
|
5 | 9 |
|
6 |
| -export const loadTSModule = async (version: string) => { |
7 |
| - let localTS: TSModule |
8 | 10 |
|
9 |
| - try { |
10 |
| - const CDNPath = `https://cdnjs.cloudflare.com/ajax/libs/typescript/${version}/typescript.min.js` |
11 |
| - const remoteScript = await fetchScript(CDNPath) |
12 |
| - localTS = _eval(remoteScript) |
13 |
| - console.log(`Loaded typescript@${localTS.version} from CDN.`); |
14 |
| - } catch (e) { |
15 |
| - localTS = require('typescript'); |
16 |
| - console.log(`Failed to load typescript from CDN. Using bundled typescript@${localTS.version}.`); |
17 |
| - } |
| 11 | +export const loadTSModule = async (projectPath:string) => { |
| 12 | + let ts: TSModule = await loadLocalTSModule(projectPath).catch(_ => null) |
| 13 | + || await loadRemoteTSModule(projectPath).catch(_ => null) |
| 14 | + || loadBundledTSModule() |
| 15 | + |
| 16 | + return ts |
| 17 | +} |
| 18 | + |
| 19 | + |
| 20 | +/** |
| 21 | + * Attempts to load typescript for the given project path by loading `typescript` |
| 22 | + * from with-in it. If fails (e.g. no such module is installed) returns null. |
| 23 | + */ |
| 24 | + |
| 25 | +const loadLocalTSModule = async (projectPath: string) => { |
| 26 | + const require = Module.createRequire(projectPath) |
| 27 | + const ts = require('typescript') |
| 28 | + console.log(`Using local typescript@${ts.version}`); |
| 29 | + return ts |
| 30 | +} |
| 31 | + |
| 32 | +const loadBundledTSModule = () => { |
| 33 | + const ts = require('typescript') |
| 34 | + console.log(`Failed to find project specific typescript, falling back to bundled typescript@${ts.version}`); |
| 35 | + return ts |
| 36 | +} |
18 | 37 |
|
19 |
| - return localTS |
| 38 | +const loadRemoteTSModule = async(projectPath:string) => { |
| 39 | + const version = parseTSVersion(projectPath) |
| 40 | + const CDNPath = `https://cdnjs.cloudflare.com/ajax/libs/typescript/${version}/typescript.min.js` |
| 41 | + const remoteScript = await fetchScript(CDNPath) |
| 42 | + const ts = _eval(remoteScript) |
| 43 | + console.log(`Loaded typescript@${ts.version} from CDN.`); |
| 44 | + return ts |
20 | 45 | }
|
21 | 46 |
|
22 | 47 | async function fetchScript(url: string) {
|
@@ -60,3 +85,49 @@ function _eval(script: string): any {
|
60 | 85 |
|
61 | 86 | return module.exports;
|
62 | 87 | }
|
| 88 | + |
| 89 | +function parseTSVersion(projectPath: string) { |
| 90 | + const yarnLockFilePath = path.resolve(projectPath, './yarn.lock') |
| 91 | + const packageLockFile = path.resolve(projectPath, './package-lock.json') |
| 92 | + if (fs.existsSync(yarnLockFilePath)) { |
| 93 | + const content = fs.readFileSync(yarnLockFilePath, 'utf8') |
| 94 | + return parseTSVersionFromYarnLockFile(content) |
| 95 | + } else if (fs.existsSync(packageLockFile)) { |
| 96 | + const content = fs.readFileSync(packageLockFile, 'utf8') |
| 97 | + return parseTSVersionFromPackageLockFile(content) |
| 98 | + } else { |
| 99 | + throw new Error('no lock file found.') |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +function parseTSVersionFromYarnLockFile(content: string) { |
| 104 | + const { type, object } = YarnLockFile.parse(content) |
| 105 | + if (type !== 'success') { |
| 106 | + throw new Error('failed to parse yarn.lock') |
| 107 | + } |
| 108 | + const packages = Object.keys(object) |
| 109 | + const _typescript = packages.find(p => /^typescript@.*/.test(p)) |
| 110 | + if (!_typescript) { |
| 111 | + throw new Error('could not find typescript in yarn.lock') |
| 112 | + } |
| 113 | + const _typescriptInfo = object[_typescript] |
| 114 | + const tsVersion = _typescriptInfo && _typescriptInfo['version'] |
| 115 | + if (typeof tsVersion !== 'string') { |
| 116 | + throw new Error('could not par typescript version from yarn.lock') |
| 117 | + } |
| 118 | + return tsVersion |
| 119 | +} |
| 120 | + |
| 121 | +function parseTSVersionFromPackageLockFile(content: string) { |
| 122 | + const json = JSON.parse(content) |
| 123 | + const dependencies = json['dependencies'] || {} |
| 124 | + const _typescriptInfo = dependencies['typescript'] |
| 125 | + if (!_typescriptInfo) { |
| 126 | + throw new Error('could not find typescript in package-lock.json') |
| 127 | + } |
| 128 | + const tsVersion = _typescriptInfo['version'] |
| 129 | + if (typeof tsVersion !== 'string') { |
| 130 | + throw new Error('could not par typescript version from yarn.lock') |
| 131 | + } |
| 132 | + return tsVersion |
| 133 | +} |
0 commit comments