Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
aduh95 committed May 16, 2023
0 parents commit d6ec8d5
Show file tree
Hide file tree
Showing 14 changed files with 3,196 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
parserOptions: {
sourceType: 'script',
ecmaVersion: 2022,
jsx: false,
},
env: { node: true, es2022: true },
extends: 'eslint:recommended',
overrides: [
{
files: ['*.mjs'],
parserOptions: {
sourceType: 'module',
},
env: { node: false, 'shared-node-browser': true },
},
],
};
79 changes: 79 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
YARN_ENABLE_GLOBAL_CACHE: false

jobs:
chore:
name: 'Testing chores'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: lts/*

- name: Get the Yarn cache directory path
id: yarn-cache-dir-path
run:
echo "dir=$(corepack yarn config get cacheFolder)" >> $GITHUB_OUTPUT
shell: bash

- uses: actions/cache@v3
with:
path: ${{steps.yarn-cache-dir-path.outputs.dir}}
key: ${{runner.os}}-yarn-${{hashFiles('**/yarn.lock')}}
restore-keys: |
${{runner.os}}-yarn-
- run: corepack yarn install --immutable

- name: 'Check for linting errors'
run: corepack yarn lint

build-and-test:
strategy:
fail-fast: false
matrix:
node:
- 16
- 18
- 20
platform:
- ubuntu-latest

name: '${{matrix.platform}} w/ Node.js ${{matrix.node}}.x'
runs-on: ${{matrix.platform}}

steps:
- uses: actions/checkout@v3

- name: 'Use Node.js ${{matrix.node}}.x'
uses: actions/setup-node@v3
with:
node-version: ${{matrix.node}}.x

- name: Get the Yarn cache directory path
id: yarn-cache-dir-path
run:
echo "dir=$(corepack yarn config get cacheFolder)" >> $GITHUB_OUTPUT
shell: bash

- uses: actions/cache@v3
with:
path: ${{steps.yarn-cache-dir-path.outputs.dir}}
key: ${{runner.os}}-yarn-${{hashFiles('**/yarn.lock')}}
restore-keys: |
${{runner.os}}-yarn-
- run: corepack yarn install --immutable

- run: corepack yarn test
52 changes: 52 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Publish releases

on:
push:
branches: [main]

env:
YARN_ENABLE_GLOBAL_CACHE: false

jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
steps:
- uses: google-github-actions/release-please-action@v3
id: release
with:
release-type: node
package-name: corepack
bump-minor-pre-major: true # TODO: remove this when releasing v1.0.0.

npm-publish:
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: lts/*

- name: Get the Yarn cache directory path
id: yarn-cache-dir-path
run:
echo "dir=$(corepack yarn config get cacheFolder)" >> $GITHUB_OUTPUT
shell: bash

- uses: actions/cache@v3
with:
path: ${{steps.yarn-cache-dir-path.outputs.dir}}
key: ${{runner.os}}-yarn-${{hashFiles('**/yarn.lock')}}
restore-keys: |
${{runner.os}}-yarn-
- name: Publish to the npm registry
run: |
corepack yarn install --immutable
corepack yarn npm publish
env:
YARN_NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.eslintcache
node_modules/
.yarn/cache
.yarn/install-state.gz
7 changes: 7 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"proseWrap": "always",
"singleQuote": true,
"trailingComma": "all",
"useTabs": true
}
22 changes: 22 additions & 0 deletions .yarn/patches/pre-commit-npm-1.2.2-f30af83877.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
diff --git a/index.js b/index.js
index a20646d922945004cb737918ef6b6d063bb3c2a4..f04bc39c5ed59125394030c1522483ca00ac7413 100644
--- a/index.js
+++ b/index.js
@@ -159,7 +159,7 @@ Hook.prototype.initialize = function initialize() {
if (!this.npm) {
try {
process.env.PATH += path.delimiter + path.dirname(process.env._);
- this.npm = which.sync('npm');
+ this.npm = which.sync('corepack');
} catch (e) {
return this.log(this.format(Hook.log.binary, 'npm'), 0);
}
@@ -225,7 +225,7 @@ Hook.prototype.run = function runner() {
// this doesn't have the required `isAtty` information that libraries use to
// output colors resulting in script output that doesn't have any color.
//
- spawn(hooked.npm, ['run', script, '--silent'], {
+ spawn(hooked.npm, ['yarn', script], {
env: process.env,
cwd: hooked.root,
stdio: [0, 1, 2]
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# @transloadit/ts-fly

`ts-fly` is a simple wrapper around Node.js that registers [Sucrase][] hooks,
making it possible to run TypeScript files in addition to JavaScript files
transparently. The difference with Sucrase is that it would let you import
ESM-only libraries, as well as `.ts` files.

TypeScript and JavaScript files can also import each other.

Like Sucrase, you should not run this on production. If you do, you are on your
own.

## Install

```sh
yarn add --dev @transloadit/ts-fly
```

## Usage

Use the `ts-fly` command the same as you would use `node`. Any CLI arguments are
passed along.

```sh
yarn ts-fly myFile.ts
```

You can use it with `--require` CLI flag:

```sh
node -r @transloadit/ts-fly myFile.ts
```

You can also `require` it from JS:

```js
'use strict';

require('@transloadit/ts-fly').defaultHooks();

require('./myFile.ts'); // works
```

### Limitations

- You can't load `.ts` files from static `import` statements from JS files. You
have to use dynamic `import()`, or convert the file to TS.
- By default, we only support `.js` and `.ts` file extensions.

## Contributing

```sh
corepack yarn
corepack yarn test
```

## Based on

- <https://github.com/alangpierce/sucrase/blob/7284b3733aa114b3f4f5371e36ff5a4704ec860e/bin/sucrase-node>
- <https://github.com/alangpierce/sucrase/blob/7284b3733aa114b3f4f5371e36ff5a4704ec860e/src/register.ts>

[Sucrase]: https://github.com/alangpierce/sucrase
55 changes: 55 additions & 0 deletions bin/ts-fly
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/sh

# Function is taken from https://stackoverflow.com/a/29835459
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.

target=$1 fname= targetDir= CDPATH=

# Try to make the execution environment as predictable as possible:
# All commands below are invoked via `command`, so we must make sure that `command`
# itself is not redefined as an alias or shell function.
# (Note that command is too inconsistent across shells, so we don't use it.)
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not even have
# an external utility version of it (e.g, Ubuntu).
# `command` bypasses aliases and shell functions and also finds builtins
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for that
# to happen.
{ \unalias command; \unset -f command; } >/dev/null 2>&1
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.

while :; do # Resolve potential symlinks until the ultimate target is found.
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
fname=$(command basename -- "$target") # Extract filename.
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
if [ -L "$fname" ]; then
# Extract [next] target path, which may be defined
# *relative* to the symlink's own directory.
# Note: We parse `ls -l` output to find the symlink target
# which is the only POSIX-compliant, albeit somewhat fragile, way.
target=$(command ls -l "$fname")
target=${target#* -> }
continue # Resolve [next] symlink target.
fi
break # Ultimate target reached.
done
targetDir=$(command pwd -P) # Get canonical dir. path
# Output the ultimate target's canonical path.
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
if [ "$fname" = '.' ]; then
command printf '%s\n' "${targetDir%/}"
elif [ "$fname" = '..' ]; then
# Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
# AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$fname"
fi
)

# Get directory of current file.
cwd=$(dirname -- "$(rreadlink "$0")")

# Run node but make sure the first loaded module is ts-fly. This makes it so that
# any subsequent Typescript code is interpreted correctly.
exec node -r "${cwd}/../index.js" "$@"
55 changes: 55 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';

const pirates = require('pirates');
const { transform } = require('sucrase');

/**
* @param {string} extension File extension. All files with said file extension
* that go through the CJS loader will be transpiled.
* @param {import('sucrase').Options} [options] Options to pass to the Sucrase transform function.
* @returns {import('pirates').RevertFunction}
*/
function addHook(extension, options) {
return pirates.addHook(
(code, filePath) => {
const { code: transformedCode, sourceMap } = transform(
// Replace dynamic imports of `.ts` files with `require`.
// Hooking into the Node.js ESM resolver would take more effort.
code.replace(
/\bimport(\(['"]\.[^'"]+\.ts['"]\))/g,
`Promise.resolve(require$1)`,
),
{
...options,
sourceMapOptions: { compiledFilename: filePath },
filePath,
},
);
const mapBase64 = Buffer.from(JSON.stringify(sourceMap)).toString(
'base64',
);
const suffix = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mapBase64}`;
return `${transformedCode}\n${suffix}`;
},
{ exts: [extension] },
);
}

function defaultHooks() {
addHook('.js');
addHook('.ts', {
transforms: ['imports', 'typescript'],
// We ask Sucrase to preserve dynamic imports because we replace them
// ourselves.
preserveDynamicImport: true,
});
}

if (module.isPreloading) {
defaultHooks();
}

module.exports = {
addHook,
defaultHooks,
};
Loading

0 comments on commit d6ec8d5

Please sign in to comment.