Skip to content

Commit

Permalink
feat: add project param and load TSC from project
Browse files Browse the repository at this point in the history
- project param can be used to specify location of the tsc project
- will use locally installed typescript module and then fallback to CDN
  • Loading branch information
Gozala committed Oct 12, 2020
1 parent 8bfd1c4 commit ab61987
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 70 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,16 @@ jobs:
"include": ["src/**/*.ts"]
}
```

## Passing `project` parameter

If your working with a monorepo or your `tsconfig.json` is not in the root repo,
or you use different config file, you can provide a `project` parmeter with a
path to the repo itself:

```yaml
- name: Typecheck
uses: andoshin11/[email protected]
with:
project: packages/subpackage/tsconfig.json
```
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ runs:
branding:
icon: 'check-circle'
color: 'blue'
inputs:
project:
description: 'Optional project path.'
required: false
4 changes: 2 additions & 2 deletions dist/index.js

Large diffs are not rendered by default.

63 changes: 8 additions & 55 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,23 @@
import * as path from 'path'
import * as fs from 'fs'
import { DiagnosticCategory } from 'typescript'
import { setFailed } from '@actions/core'
import * as YarnLockFile from '@yarnpkg/lockfile'
import { getInput, setFailed } from '@actions/core'
import { Doctor } from './doctor'
import { loadTSModule } from './loadTSModule'

function parseTSVersion(currentDir: string) {
const yarnLockFilePath = path.resolve(currentDir, 'yarn.lock')
const packageLockFile = path.resolve(currentDir, 'package-lock.json')
if (fs.existsSync(yarnLockFilePath)) {
const content = fs.readFileSync(yarnLockFilePath, 'utf8')
return parseTSVersionFromYarnLockFile(content)
} else if (fs.existsSync(packageLockFile)) {
const content = fs.readFileSync(packageLockFile, 'utf8')
return parseTSVersionFromPackageLockFile(content)
} else {
throw new Error('no lock file found.')
}
}

function parseTSVersionFromYarnLockFile(content: string) {
const { type, object } = YarnLockFile.parse(content)
if (type !== 'success') {
throw new Error('failed to parse yarn.lock')
}
const packages = Object.keys(object)
const _typescript = packages.find(p => /^typescript@.*/.test(p))
if (!_typescript) {
throw new Error('could not find typescript in yarn.lock')
}
const _typescriptInfo = object[_typescript]
const tsVersion = _typescriptInfo && _typescriptInfo['version']
if (typeof tsVersion !== 'string') {
throw new Error('could not par typescript version from yarn.lock')
}
return tsVersion
}

function parseTSVersionFromPackageLockFile(content: string) {
const json = JSON.parse(content)
const dependencies = json['dependencies'] || {}
const _typescriptInfo = dependencies['typescript']
if (!_typescriptInfo) {
throw new Error('could not find typescript in package-lock.json')
}
const tsVersion = _typescriptInfo['version']
if (typeof tsVersion !== 'string') {
throw new Error('could not par typescript version from yarn.lock')
}
return tsVersion
}

async function main() {
try {

const currentDir = process.cwd()
const configPath = path.resolve(currentDir, 'tsconfig.json')
if (!fs.existsSync(configPath)) {
throw new Error(`could not find tsconfig.json at: ${currentDir}`)
const project = getInput('project') || 'tsconfig.json'
const tscPath = getInput('tsc')
const projectPath = path.resolve(process.cwd(), project)
if (!fs.existsSync(projectPath)) {
throw new Error(`No such TS config file: ${projectPath}`)
}

const tsVersion = parseTSVersion(currentDir)
const remoteTS = await loadTSModule(tsVersion)
const ts = await loadTSModule(projectPath)

const doctor = Doctor.fromConfigFile(configPath, remoteTS)
const doctor = Doctor.fromConfigFile(projectPath, ts)
const diagnostics = doctor.getSemanticDiagnostics()

if (diagnostics) {
Expand Down
2 changes: 1 addition & 1 deletion src/langSvc/createHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const createHost = (fileNames: string[], compilerOptions: _ts.CompilerOpt
},
getCurrentDirectory: () => process.cwd(),
getCompilationSettings: () => compilerOptions,
getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
getDefaultLibFileName: options => ts.getDefaultLibFileName(options),
resolveModuleNames: (moduleNames, containingFile, _, __, options) => {
const ret: (_ts.ResolvedModule | undefined)[] = moduleNames.map(name => {
if (/\.vue$/.test(name)) {
Expand Down
95 changes: 83 additions & 12 deletions src/loadTSModule.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
import * as https from 'https'
import Module from 'module'
const concat = require('concat-stream')
import * as YarnLockFile from '@yarnpkg/lockfile'
import * as path from 'path'
import * as fs from 'fs'

type TSModule = typeof import('typescript')

export const loadTSModule = async (version: string) => {
let localTS: TSModule

try {
const CDNPath = `https://cdnjs.cloudflare.com/ajax/libs/typescript/${version}/typescript.min.js`
const remoteScript = await fetchScript(CDNPath)
localTS = _eval(remoteScript)
console.log(`Loaded typescript@${localTS.version} from CDN.`);
} catch (e) {
localTS = require('typescript');
console.log(`Failed to load typescript from CDN. Using bundled typescript@${localTS.version}.`);
}
export const loadTSModule = async (projectPath:string) => {
let ts: TSModule = await loadLocalTSModule(projectPath).catch(_ => null)
|| await loadRemoteTSModule(projectPath).catch(_ => null)
|| loadBundledTSModule()

return ts
}


/**
* Attempts to load typescript for the given project path by loading `typescript`
* from with-in it. If fails (e.g. no such module is installed) returns null.
*/

const loadLocalTSModule = async (projectPath: string) => {
const require = Module.createRequire(projectPath)
const ts = require('typescript')
console.log(`Using local typescript@${ts.version}`);
return ts
}

const loadBundledTSModule = () => {
const ts = require('typescript')
console.log(`Failed to find project specific typescript, falling back to bundled typescript@${ts.version}`);
return ts
}

return localTS
const loadRemoteTSModule = async(projectPath:string) => {
const version = parseTSVersion(projectPath)
const CDNPath = `https://cdnjs.cloudflare.com/ajax/libs/typescript/${version}/typescript.min.js`
const remoteScript = await fetchScript(CDNPath)
const ts = _eval(remoteScript)
console.log(`Loaded typescript@${ts.version} from CDN.`);
return ts
}

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

return module.exports;
}

function parseTSVersion(projectPath: string) {
const yarnLockFilePath = path.resolve(projectPath, './yarn.lock')
const packageLockFile = path.resolve(projectPath, './package-lock.json')
if (fs.existsSync(yarnLockFilePath)) {
const content = fs.readFileSync(yarnLockFilePath, 'utf8')
return parseTSVersionFromYarnLockFile(content)
} else if (fs.existsSync(packageLockFile)) {
const content = fs.readFileSync(packageLockFile, 'utf8')
return parseTSVersionFromPackageLockFile(content)
} else {
throw new Error('no lock file found.')
}
}

function parseTSVersionFromYarnLockFile(content: string) {
const { type, object } = YarnLockFile.parse(content)
if (type !== 'success') {
throw new Error('failed to parse yarn.lock')
}
const packages = Object.keys(object)
const _typescript = packages.find(p => /^typescript@.*/.test(p))
if (!_typescript) {
throw new Error('could not find typescript in yarn.lock')
}
const _typescriptInfo = object[_typescript]
const tsVersion = _typescriptInfo && _typescriptInfo['version']
if (typeof tsVersion !== 'string') {
throw new Error('could not par typescript version from yarn.lock')
}
return tsVersion
}

function parseTSVersionFromPackageLockFile(content: string) {
const json = JSON.parse(content)
const dependencies = json['dependencies'] || {}
const _typescriptInfo = dependencies['typescript']
if (!_typescriptInfo) {
throw new Error('could not find typescript in package-lock.json')
}
const tsVersion = _typescriptInfo['version']
if (typeof tsVersion !== 'string') {
throw new Error('could not par typescript version from yarn.lock')
}
return tsVersion
}

0 comments on commit ab61987

Please sign in to comment.