Skip to content

Commit

Permalink
Merge pull request #1 from joris-gallot/feat/cli-command-init
Browse files Browse the repository at this point in the history
feat: init command
  • Loading branch information
joris-gallot authored May 7, 2024
2 parents 5cf8f7c + a34a89b commit d7e69f5
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 71 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,43 @@

Typestep aims to simplify the migration process from JavaScript to TypeScript in existing projects by offering a gradual transition strategy. It allows developers to introduce TypeScript incrementally by leveraging the parsing of TypeScript compiler output (tsc)

**⚠️ Work in Progress ⚠️**

This project is currently under active development and is not yet considered stable
> [!WARNING]
> This project is currently under active development and is not yet considered stable
## Usage

```bash
npm install -g typestep
```

> [!WARNING]
> Do Not Use `--pretty` option with `tsc`
```bash
tsc > tsc-output.log
```

### Config file

#### Init config file

> [!NOTE]
> Init command will create your Typestep config file with all files from the tsc output marked as ignored
```bash
typestep init tsc-output.log
```

#### Or create your config file

```ts
// typestep.config.ts
export default {
ignoredFiles: ['src/main.ts']
}
```

⚠️ **Do Not Use `--pretty` option with `tsc`**
```bash
tsc > tsc-output.log
```
### Run typestep

```bash
typestep tsc-output.log
typestep run tsc-output.log
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"typecheck": "tsc"
},
"dependencies": {
"citty": "^0.1.6",
"jiti": "^1.21.0"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 16 additions & 62 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,17 @@
#!/usr/bin/env node
/* eslint-disable no-console */
import { existsSync } from 'node:fs'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import process from 'node:process'
import type { TypestepConfig } from './types.js'
import { tryImport, tscDiagnosticToTscError } from './utils.js'
import { getFinalOutput, parseTscOutput } from './index.js'

function getTscOutputPath() {
const args = process.argv.slice(2)

if (args.length === 0) {
console.log('No tsc output file provided')
process.exit(1)
}

const tscOutputPath = args[0]

if (!existsSync(tscOutputPath)) {
console.log(`File ${tscOutputPath} does not exist`)
process.exit(1)
}

return tscOutputPath
}

async function readConfigFile() {
const configFile = resolve(process.cwd(), 'typestep.config.ts')

if (!existsSync(configFile)) {
console.log('No config file found')
return
}

const configModule = await tryImport(configFile)

if (!configModule?.default) {
console.log('No default export found in config file')
return
}

return configModule.default as TypestepConfig
}

async function run() {
const tscOutput = await readFile(getTscOutputPath(), 'utf8')
const configFile = await readConfigFile()
const parsedTscOutput = parseTscOutput(tscOutput)

const tscDiagnostics = getFinalOutput(parsedTscOutput, configFile)

if (tscDiagnostics.length === 0) {
console.log('No tsc errors found')
return
}

console.error(tscDiagnostics.map(tscDiagnosticToTscError).join('\n'))
process.exit(1)
}

run()
import { defineCommand, runMain } from 'citty'
import { version } from '../package.json'

const main = defineCommand({
meta: {
name: 'typestep',
version,
description: 'CLI tool to filter tsc output',
},
subCommands: {
run: () => import('./commands/run.js').then(mod => mod.default),
init: () => import('./commands/init.js').then(mod => mod.default),
},
})

runMain(main)
42 changes: 42 additions & 0 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env node
import { existsSync } from 'node:fs'
import { readFile, writeFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import process from 'node:process'
import { defineCommand } from 'citty'
import { parseTscOutput } from '../index.js'
import { writeTypestepConfig } from '../utils.js'
import { CONFIG_FILE_NAME } from '../constants.js'

async function init(tscOutputFile: string) {
const tscOutput = await readFile(tscOutputFile, 'utf8')
const parsedTscOutput = parseTscOutput(tscOutput)

const ignoredFiles = [...new Set(parsedTscOutput.map(({ path }) => path))]
const configFileContent = writeTypestepConfig({ ignoredFiles })

return writeFile(CONFIG_FILE_NAME, configFileContent)
}

export default defineCommand({
meta: {
name: 'init',
description: 'Initialize the Typestep configuration file with all files from the tsc output marked as ignored',
},
args: {
tsc_output_file: {
type: 'positional',
description: 'The tsc output file path to be processed',
required: true,
},
},
run({ args }) {
if (!existsSync(args.tsc_output_file))
throw new Error('Tsc output file not found')

if (existsSync(CONFIG_FILE_NAME))
throw new Error('Typestep config file already exists')

init(resolve(process.cwd(), args.tsc_output_file))
},
})
66 changes: 66 additions & 0 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env node
/* eslint-disable no-console */
import { existsSync } from 'node:fs'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import process from 'node:process'
import { defineCommand } from 'citty'

import type { TypestepConfig } from '../types.js'
import { tryImport, tscDiagnosticToTscError } from '../utils.js'
import { getFinalOutput, parseTscOutput } from '../index.js'
import { CONFIG_FILE_NAME } from '../constants.js'

async function readConfigFile() {
const configFile = resolve(process.cwd(), CONFIG_FILE_NAME)

if (!existsSync(configFile)) {
console.log('No config file found')
return
}

const configModule = await tryImport(configFile)

if (!configModule?.default) {
console.log('No default export found in config file')
return
}

return configModule.default as TypestepConfig
}

async function run(tscOutputFile: string) {
const tscOutput = await readFile(tscOutputFile, 'utf8')
const configFile = await readConfigFile()
const parsedTscOutput = parseTscOutput(tscOutput)

const tscDiagnostics = getFinalOutput(parsedTscOutput, configFile)

if (tscDiagnostics.length === 0) {
console.log('No tsc errors found')
return
}

console.error(tscDiagnostics.map(tscDiagnosticToTscError).join('\n'))
process.exit(1)
}

export default defineCommand({
meta: {
name: 'run',
description: 'Run the Typestep CLI tool with the tsc output file as input',
},
args: {
tsc_output_file: {
type: 'positional',
description: 'The tsc output file path to be processed',
required: true,
},
},
run({ args }) {
if (!existsSync(args.tsc_output_file))
throw new Error('Tsc output file not found')

run(resolve(process.cwd(), args.tsc_output_file))
},
})
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const CONFIG_FILE_NAME = 'typestep.config.ts'
6 changes: 5 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import process from 'node:process'
import jiti from 'jiti'
import type { TscDiagnostic } from './types.js'
import type { TscDiagnostic, TypestepConfig } from './types.js'

export function tryImport(file: string, rootDir: string = process.cwd()) {
// @ts-expect-error "This expression is not callable." but works fine
Expand All @@ -20,3 +20,7 @@ export function tscDiagnosticToTscError(diag: TscDiagnostic) {

return `${path}(${cursor.line},${cursor.column}): error ${tsCode}: ${error}`
}

export function writeTypestepConfig(config: TypestepConfig) {
return `export default ${JSON.stringify(config, null, 2)}`
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"resolveJsonModule": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
Expand Down

0 comments on commit d7e69f5

Please sign in to comment.