Skip to content

Commit ab61987

Browse files
committed
feat: add project param and load TSC from project
- project param can be used to specify location of the tsc project - will use locally installed typescript module and then fallback to CDN
1 parent 8bfd1c4 commit ab61987

File tree

6 files changed

+111
-70
lines changed

6 files changed

+111
-70
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,16 @@ jobs:
4949
"include": ["src/**/*.ts"]
5050
}
5151
```
52+
53+
## Passing `project` parameter
54+
55+
If your working with a monorepo or your `tsconfig.json` is not in the root repo,
56+
or you use different config file, you can provide a `project` parmeter with a
57+
path to the repo itself:
58+
59+
```yaml
60+
- name: Typecheck
61+
uses: andoshin11/[email protected]
62+
with:
63+
project: packages/subpackage/tsconfig.json
64+
```

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ runs:
77
branding:
88
icon: 'check-circle'
99
color: 'blue'
10+
inputs:
11+
project:
12+
description: 'Optional project path.'
13+
required: false

dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,23 @@
11
import * as path from 'path'
22
import * as fs from 'fs'
33
import { DiagnosticCategory } from 'typescript'
4-
import { setFailed } from '@actions/core'
5-
import * as YarnLockFile from '@yarnpkg/lockfile'
4+
import { getInput, setFailed } from '@actions/core'
65
import { Doctor } from './doctor'
76
import { loadTSModule } from './loadTSModule'
87

9-
function parseTSVersion(currentDir: string) {
10-
const yarnLockFilePath = path.resolve(currentDir, 'yarn.lock')
11-
const packageLockFile = path.resolve(currentDir, 'package-lock.json')
12-
if (fs.existsSync(yarnLockFilePath)) {
13-
const content = fs.readFileSync(yarnLockFilePath, 'utf8')
14-
return parseTSVersionFromYarnLockFile(content)
15-
} else if (fs.existsSync(packageLockFile)) {
16-
const content = fs.readFileSync(packageLockFile, 'utf8')
17-
return parseTSVersionFromPackageLockFile(content)
18-
} else {
19-
throw new Error('no lock file found.')
20-
}
21-
}
22-
23-
function parseTSVersionFromYarnLockFile(content: string) {
24-
const { type, object } = YarnLockFile.parse(content)
25-
if (type !== 'success') {
26-
throw new Error('failed to parse yarn.lock')
27-
}
28-
const packages = Object.keys(object)
29-
const _typescript = packages.find(p => /^typescript@.*/.test(p))
30-
if (!_typescript) {
31-
throw new Error('could not find typescript in yarn.lock')
32-
}
33-
const _typescriptInfo = object[_typescript]
34-
const tsVersion = _typescriptInfo && _typescriptInfo['version']
35-
if (typeof tsVersion !== 'string') {
36-
throw new Error('could not par typescript version from yarn.lock')
37-
}
38-
return tsVersion
39-
}
40-
41-
function parseTSVersionFromPackageLockFile(content: string) {
42-
const json = JSON.parse(content)
43-
const dependencies = json['dependencies'] || {}
44-
const _typescriptInfo = dependencies['typescript']
45-
if (!_typescriptInfo) {
46-
throw new Error('could not find typescript in package-lock.json')
47-
}
48-
const tsVersion = _typescriptInfo['version']
49-
if (typeof tsVersion !== 'string') {
50-
throw new Error('could not par typescript version from yarn.lock')
51-
}
52-
return tsVersion
53-
}
548

559
async function main() {
5610
try {
57-
58-
const currentDir = process.cwd()
59-
const configPath = path.resolve(currentDir, 'tsconfig.json')
60-
if (!fs.existsSync(configPath)) {
61-
throw new Error(`could not find tsconfig.json at: ${currentDir}`)
11+
const project = getInput('project') || 'tsconfig.json'
12+
const tscPath = getInput('tsc')
13+
const projectPath = path.resolve(process.cwd(), project)
14+
if (!fs.existsSync(projectPath)) {
15+
throw new Error(`No such TS config file: ${projectPath}`)
6216
}
6317

64-
const tsVersion = parseTSVersion(currentDir)
65-
const remoteTS = await loadTSModule(tsVersion)
18+
const ts = await loadTSModule(projectPath)
6619

67-
const doctor = Doctor.fromConfigFile(configPath, remoteTS)
20+
const doctor = Doctor.fromConfigFile(projectPath, ts)
6821
const diagnostics = doctor.getSemanticDiagnostics()
6922

7023
if (diagnostics) {

src/langSvc/createHost.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const createHost = (fileNames: string[], compilerOptions: _ts.CompilerOpt
6767
},
6868
getCurrentDirectory: () => process.cwd(),
6969
getCompilationSettings: () => compilerOptions,
70-
getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
70+
getDefaultLibFileName: options => ts.getDefaultLibFileName(options),
7171
resolveModuleNames: (moduleNames, containingFile, _, __, options) => {
7272
const ret: (_ts.ResolvedModule | undefined)[] = moduleNames.map(name => {
7373
if (/\.vue$/.test(name)) {

src/loadTSModule.ts

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
11
import * as https from 'https'
2+
import Module from 'module'
23
const concat = require('concat-stream')
4+
import * as YarnLockFile from '@yarnpkg/lockfile'
5+
import * as path from 'path'
6+
import * as fs from 'fs'
37

48
type TSModule = typeof import('typescript')
59

6-
export const loadTSModule = async (version: string) => {
7-
let localTS: TSModule
810

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+
}
1837

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
2045
}
2146

2247
async function fetchScript(url: string) {
@@ -60,3 +85,49 @@ function _eval(script: string): any {
6085

6186
return module.exports;
6287
}
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

Comments
 (0)