Skip to content

Commit

Permalink
Merge pull request #1386 from SUI-Components/feat/typescript-support-poc
Browse files Browse the repository at this point in the history
feat(packages/sui-js-compiler): add typescript support
  • Loading branch information
kikoruiz authored May 25, 2023
2 parents 0bd2bc5 + 6f0e5ca commit 9479b26
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 15 deletions.
16 changes: 12 additions & 4 deletions packages/sui-js-compiler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,23 @@ $ ./node_modules/.bin/sui-js-compiler

### Options

| Option | Type | Default | Description |
| -------- | -------------- | ------- | ------------------------------------------------------------------------- |
| --ignore | string \| glob | - | Takes all the pattern comma separated and ignore them during compilation. |
| --modern | boolean | - | Transpile using modern browser targets. |
| Option | Type | Default | Description |
| ---------- | -------------- | ------- | ------------------------------------------------------------------------- |
| `--ignore` | string \| glob | - | Takes all the pattern comma separated and ignore them during compilation. |
| `--modern` | boolean | - | Transpile using modern browser targets. |

```sh
$ ./node_modules/.bin/sui-js-compiler --ignore=./src/**/*.test.js
```

```sh
$ ./node_modules/.bin/sui-js-compiler --modern
```

#### Compiling TypeScript files and generating type declarations

This tools lets you compile **TS files** and generate their **type declarations** in your packages out of the box. It will do it if the package itself has a `tsconfig.json` placed in its root folder.

## Requirements

Automatically, `@s-ui/js-compiler` searches for `/src` folder and outputs the compiled files to `/lib`.
Expand Down
82 changes: 78 additions & 4 deletions packages/sui-js-compiler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,74 @@
import program from 'commander'
import fg from 'fast-glob'
import fs from 'fs-extra'
import path from 'node:path'
import ts from 'typescript'

import {transformFile} from '@swc/core'

import {getSWCConfig} from './swc-config.js'

const SOURCE_DIR = './src'
const OUTPUT_DIR = './lib'
const TS_EXTENSION_REGEX = /(\.ts)x?/
const COMPILED_EXTENSION = '.js'
const DEFAULT_TS_CONFIG = {
declaration: true,
emitDeclarationOnly: true,
incremental: true,
jsx: 'react-jsx',
module: 'es6',
esModuleInterop: true,
noImplicitAny: false,
baseUrl: '.',
outDir: OUTPUT_DIR,
skipLibCheck: true,
strict: true,
target: 'es5',
types: ['react', 'node']
}

const getTSConfig = () => {
// Get TS config from the package dir.
const tsConfigPath = path.join(process.cwd(), 'tsconfig.json')
let tsConfig

try {
if (fs.existsSync(tsConfigPath)) {
tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, {encoding: 'utf8'}))
}
} catch (err) {
console.error(err)
}

return tsConfig
}

const compileFile = async (file, options) => {
const {code} = await transformFile(file, getSWCConfig(options))
const outputPath = file.replace('./src', './lib')
const outputPath = file
.replace(SOURCE_DIR, OUTPUT_DIR)
.replace(TS_EXTENSION_REGEX, COMPILED_EXTENSION)

fs.outputFile(outputPath, code)
}

const compileTypes = (files, options) => {
const createdFiles = {}
const host = ts.createCompilerHost(options)
host.writeFile = (fileName, contents) => (createdFiles[fileName] = contents)
const program = ts.createProgram(files, options, host)
program.emit()

return Promise.all(
Object.keys(createdFiles).map(outputPath => {
const code = createdFiles[outputPath]

return fs.outputFile(outputPath, code)
})
)
}

const commaSeparatedList = value => value.split(',')

program
Expand All @@ -37,13 +94,30 @@ program
})
.parse(process.argv)

const {ignore = [], modern: isModern} = program.opts()
const {ignore = [], modern: isModern = false} = program.opts()

;(async () => {
console.time('[sui-js-compiler]')

const files = await fg('./src/**/*.{js,jsx}', {ignore})
files.forEach(file => compileFile(file, {isModern}))
const files = await fg('./src/**/*.{js,jsx,ts,tsx}', {ignore})
const filesToCompile = Promise.all(
files.map(async file => {
const isTypeScript = Boolean(file.match(TS_EXTENSION_REGEX))

return compileFile(file, {isModern, isTypeScript})
})
)
const tsConfig = getTSConfig()
// If TS config exists, set TypeScript as enabled.
const isTypeScriptEnabled = Boolean(tsConfig)
const typesToCompile = isTypeScriptEnabled
? compileTypes(files, {
...DEFAULT_TS_CONFIG,
...(tsConfig?.compilerOptions ?? {})
})
: Promise.resolve()

await Promise.all([filesToCompile, typesToCompile])

console.timeEnd('[sui-js-compiler]')
})()
7 changes: 4 additions & 3 deletions packages/sui-js-compiler/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@s-ui/js-compiler",
"version": "1.22.0",
"description": "JavaScript Compiler",
"description": "JavaScript & TypeScript Compiler",
"type": "module",
"exports": "./src/index.js",
"bin": {
Expand All @@ -15,7 +15,8 @@
"@swc/core": "1.3.14",
"@swc/helpers": "0.4.12",
"commander": "8.3.0",
"fast-glob": "3.2.11",
"fs-extra": "10.1.0"
"fast-glob": "3.2.12",
"fs-extra": "10.1.0",
"typescript": "5.0.4"
}
}
8 changes: 5 additions & 3 deletions packages/sui-js-compiler/swc-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ const DEFAULT_BROWSER_TARGETS = {
ios: '14.5'
}

export const getSWCConfig = ({isModern}) => {
export const getSWCConfig = ({isModern, isTypeScript}) => {
const targets = isModern
? DEFAULT_BROWSER_TARGETS
: DEFAULT_LEGACY_BROWSER_TARGETS
const syntaxOptions = isTypeScript
? {syntax: 'typescript', tsx: true}
: {syntax: 'ecmascript', jsx: true}

return {
minify: true,
jsc: {
parser: {
syntax: 'ecmascript',
jsx: true,
...syntaxOptions,
dynamicImport: true,
privateMethod: true,
functionBind: true,
Expand Down
2 changes: 1 addition & 1 deletion packages/sui-js-compiler/test/server/src/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export class Whatever {
@decorator
async execute() {
return await Promise.resolve('hello')
return Promise.resolve('hello')
}
}

Expand Down

0 comments on commit 9479b26

Please sign in to comment.