tsnite 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +54 -0
- package/dist/builders/swc.js +43 -0
- package/dist/cli.js +154 -0
- package/dist/common/constants.js +6 -0
- package/dist/utils/gradient.js +36 -0
- package/dist/utils/tsconfig-loader.js +13 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2025
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# tsnite
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
TypeScript at full throttle—fast, safe, unstoppable. 🚀
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
`tsnite` is a tool that accelerates TypeScript project development, offering a streamlined build and run experience. Ideal for developers seeking productivity without compromising security and performance.
|
|
8
|
+
|
|
9
|
+
## ⚡ Recursos principais
|
|
10
|
+
|
|
11
|
+
- **Execução rápida de arquivos TypeScript** sem build manual.
|
|
12
|
+
- **Integração simples** com projetos existentes.
|
|
13
|
+
- **Suporte a múltiplos roots** e configurações flexíveis de projeto.
|
|
14
|
+
|
|
15
|
+
## 🚀 Install
|
|
16
|
+
|
|
17
|
+
To add `tsnite` to your project as a development dependency, run:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install tsnite -D
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or, if you're using Yarn:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
yarn add --dev tsnite
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🛠️ How to use
|
|
30
|
+
|
|
31
|
+
With `tsnite` installed, you can use it directly in your terminal to run TypeScript files without needing to compile them first.
|
|
32
|
+
|
|
33
|
+
### Run a TypeScript file
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx tsnite caminho/do/arquivo.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This will execute the specified TypeScript file, allowing you to quickly test and run scripts during development.
|
|
40
|
+
|
|
41
|
+
## 💡 Tips & Best Practices
|
|
42
|
+
|
|
43
|
+
- Keep your TypeScript project configuration (tsconfig.json) up to date for best performance.
|
|
44
|
+
- Use multiple source roots for large projects to organize files efficiently.
|
|
45
|
+
- Combine tsnite with scripts in package.json for a smoother development workflow.
|
|
46
|
+
|
|
47
|
+
## 📚 More information
|
|
48
|
+
|
|
49
|
+
Check the official npm page for details, examples, and updates:
|
|
50
|
+
[https://www.npmjs.com/package/tsnite](https://www.npmjs.com/package/tsnite)
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
|
|
54
|
+
Enjoy developing TypeScript at full throttle!
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { transformFile } from '@swc/core';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join, parse } from 'node:path';
|
|
4
|
+
import { loadTsConfigPaths } from '../utils/tsconfig-loader.js';
|
|
5
|
+
import { outDir } from '../common/constants.js';
|
|
6
|
+
const paths = await loadTsConfigPaths();
|
|
7
|
+
export async function compile(filename, sourceRoot) {
|
|
8
|
+
const { code, map } = await transformFile(filename, {
|
|
9
|
+
jsc: {
|
|
10
|
+
baseUrl: join(process.cwd(), '.'),
|
|
11
|
+
parser: {
|
|
12
|
+
syntax: 'typescript',
|
|
13
|
+
decorators: true
|
|
14
|
+
},
|
|
15
|
+
target: 'es2022',
|
|
16
|
+
keepClassNames: true,
|
|
17
|
+
transform: {
|
|
18
|
+
treatConstEnumAsEnum: true,
|
|
19
|
+
decoratorMetadata: true,
|
|
20
|
+
legacyDecorator: true
|
|
21
|
+
},
|
|
22
|
+
experimental: {
|
|
23
|
+
keepImportAssertions: true
|
|
24
|
+
},
|
|
25
|
+
paths
|
|
26
|
+
},
|
|
27
|
+
module: {
|
|
28
|
+
type: 'es6',
|
|
29
|
+
strict: true,
|
|
30
|
+
outFileExtension: 'js',
|
|
31
|
+
resolveFully: true
|
|
32
|
+
},
|
|
33
|
+
sourceMaps: true
|
|
34
|
+
});
|
|
35
|
+
const { dir, name } = parse(filename
|
|
36
|
+
.replace(join(process.cwd(), '/'), '')
|
|
37
|
+
.replace(join(sourceRoot, '/'), ''));
|
|
38
|
+
await mkdir(join(outDir, dir), { recursive: true });
|
|
39
|
+
await writeFile(join(outDir, dir, `${name}.js`), `${code}\n//# sourceMappingURL=${join(outDir, dir, `${name}.js.map`)}`);
|
|
40
|
+
if (map) {
|
|
41
|
+
await writeFile(join(outDir, dir, `${name}.js.map`), map);
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { readdir, stat, rm, mkdir, cp, symlink } from 'node:fs/promises';
|
|
5
|
+
import { fork } from 'node:child_process';
|
|
6
|
+
import { watch } from 'chokidar';
|
|
7
|
+
import { EventEmitter } from 'node:events';
|
|
8
|
+
import { name, description, version, outDir } from './common/constants.js';
|
|
9
|
+
import { compile } from './builders/swc.js';
|
|
10
|
+
import { gradient } from './utils/gradient.js';
|
|
11
|
+
program
|
|
12
|
+
.name(name)
|
|
13
|
+
.description(description)
|
|
14
|
+
.version(version, '-v, --version', 'Output the current version')
|
|
15
|
+
.option('--source-root <string>', 'Source Root', '.')
|
|
16
|
+
.option('--watch', 'Enables watch mode', false)
|
|
17
|
+
.option('--include-assets', 'Include static files in the build', false)
|
|
18
|
+
.argument('<string>', 'Entrypoint file')
|
|
19
|
+
.argument('[args...]', 'Specify the Node.js command and any additional arguments')
|
|
20
|
+
.showSuggestionAfterError();
|
|
21
|
+
const events = new EventEmitter();
|
|
22
|
+
const pids = new Set();
|
|
23
|
+
let starts = 0;
|
|
24
|
+
export async function* discover(path) {
|
|
25
|
+
const entries = await readdir(path);
|
|
26
|
+
const ignores = /^(?:node_modules|dist|coverage|tests|\..+|.*\.(?:spec|test)\.ts)$/;
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
if (ignores.test(entry))
|
|
29
|
+
continue;
|
|
30
|
+
const stats = await stat(join(path, entry));
|
|
31
|
+
if (stats.isDirectory()) {
|
|
32
|
+
yield* discover(join(path, entry));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
yield join(path, entry);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function handler() {
|
|
39
|
+
const options = program.opts();
|
|
40
|
+
const [entry, nodeArgs] = program.processedArgs;
|
|
41
|
+
try {
|
|
42
|
+
await rm(outDir, {
|
|
43
|
+
force: true,
|
|
44
|
+
recursive: true
|
|
45
|
+
});
|
|
46
|
+
await mkdir(outDir, { recursive: true });
|
|
47
|
+
await symlink(join(process.cwd(), 'node_modules'), join(outDir, 'node_modules'), 'junction');
|
|
48
|
+
starts = performance.now();
|
|
49
|
+
for await (const filename of discover(options.sourceRoot)) {
|
|
50
|
+
if (filename.endsWith('.ts')) {
|
|
51
|
+
await compile(join(process.cwd(), filename), options.sourceRoot);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (options.includeAssets) {
|
|
55
|
+
await cp(join(process.cwd(), filename), join(outDir, join(filename.replace(`${join(options.sourceRoot)}/`, ''))), {
|
|
56
|
+
force: true,
|
|
57
|
+
recursive: true
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const ends = performance.now();
|
|
62
|
+
const entrypoint = entry
|
|
63
|
+
.replace(join(options.sourceRoot, '/'), '')
|
|
64
|
+
.replace(/(.+).ts$/, '$1.js');
|
|
65
|
+
const { pid } = fork(join(outDir, entrypoint), {
|
|
66
|
+
execArgv: ['--enable-source-maps', ...nodeArgs],
|
|
67
|
+
stdio: 'inherit'
|
|
68
|
+
});
|
|
69
|
+
pids.add(pid);
|
|
70
|
+
process.stdout.write(`\x1b[1m${gradient(['#5e23e6', '#f88bc7'])(`➤ Compiled successfully in ${(ends - starts).toFixed(2)}ms`)}\x1b[0m\n`);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
process.stdout.write(`\x1b${gradient(['#cf4444', '#9b1e1e'])(`❌ Failed to compile!\n`)}\x1b[0m\n${err}`);
|
|
74
|
+
}
|
|
75
|
+
if (options.watch) {
|
|
76
|
+
const watcher = watch(join(process.cwd(), options.sourceRoot), {
|
|
77
|
+
atomic: true,
|
|
78
|
+
ignoreInitial: true,
|
|
79
|
+
ignored: [/.+\.(?:test|spec)\.ts$/i]
|
|
80
|
+
});
|
|
81
|
+
watcher.on('change', async function (path) {
|
|
82
|
+
process.stdout.write('\x1Bc');
|
|
83
|
+
starts = performance.now();
|
|
84
|
+
try {
|
|
85
|
+
if (!path.endsWith('.ts') && options.includeAssets) {
|
|
86
|
+
await cp(path, join(outDir, path.replace(join(process.cwd(), options.sourceRoot, '/'), '')), { force: true, recursive: true });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
await compile(path, options.sourceRoot);
|
|
90
|
+
events.emit('ready');
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
process.stdout.write(`\x1b${gradient(['#cf4444', '#9b1e1e'])(`❌ Failed to compile!\n`)}\x1b[0m\n${err}`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
watcher.on('add', async function (path) {
|
|
97
|
+
process.stdout.write('\x1Bc');
|
|
98
|
+
starts = performance.now();
|
|
99
|
+
try {
|
|
100
|
+
if (!path.endsWith('.ts') && options.includeAssets) {
|
|
101
|
+
await cp(path, join(outDir, path.replace(join(process.cwd(), options.sourceRoot, '/'), '')), { force: true, recursive: true });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
await compile(path, options.sourceRoot);
|
|
105
|
+
events.emit('ready');
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
process.stdout.write(`\x1b${gradient(['#cf4444', '#9b1e1e'])(`❌ Failed to compile!\n`)}\x1b[0m\n${err}`);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
watcher.on('unlink', async function (path) {
|
|
112
|
+
process.stdout.write('\x1Bc');
|
|
113
|
+
starts = performance.now();
|
|
114
|
+
try {
|
|
115
|
+
await rm(join(outDir, path.replace(join(process.cwd(), options.sourceRoot, '/'), '')), {
|
|
116
|
+
force: true,
|
|
117
|
+
recursive: true
|
|
118
|
+
});
|
|
119
|
+
events.emit('ready');
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error(err);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
events.on('ready', async function () {
|
|
126
|
+
try {
|
|
127
|
+
for (const pid of pids.values()) {
|
|
128
|
+
try {
|
|
129
|
+
process.kill(pid);
|
|
130
|
+
pids.delete(pid);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
pids.delete(pid);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const ends = performance.now();
|
|
137
|
+
const entrypoint = entry
|
|
138
|
+
.replace(join(options.sourceRoot, '/'), '')
|
|
139
|
+
.replace(/(.+).ts$/, '$1.js');
|
|
140
|
+
const { pid } = fork(join(outDir, entrypoint), {
|
|
141
|
+
execArgv: ['--enable-source-maps', ...nodeArgs],
|
|
142
|
+
stdio: 'inherit'
|
|
143
|
+
});
|
|
144
|
+
pids.add(pid);
|
|
145
|
+
process.stdout.write(`\x1b[1m${gradient(['#5e23e6', '#f88bc7'])(`› Compiled successfully in ${(ends - starts).toFixed(2)}ms`)}\x1b[0m\n`);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
console.error(err);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
program.action(handler);
|
|
154
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const require = createRequire(import.meta.dirname);
|
|
5
|
+
export const { name, description, version } = require(join(import.meta.dirname, '..', '..', 'package.json'));
|
|
6
|
+
export const outDir = join(tmpdir(), name);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function hexToRgb(hex) {
|
|
2
|
+
hex = hex.replace(/^#/, '');
|
|
3
|
+
if (hex.length === 3) {
|
|
4
|
+
hex = hex
|
|
5
|
+
.split('')
|
|
6
|
+
.map((c) => c + c)
|
|
7
|
+
.join('');
|
|
8
|
+
}
|
|
9
|
+
const num = parseInt(hex, 16);
|
|
10
|
+
return [num >> 16, (num >> 8) & 255, num & 255];
|
|
11
|
+
}
|
|
12
|
+
function rgbToAnsi([r, g, b]) {
|
|
13
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
14
|
+
}
|
|
15
|
+
export function gradient(colors) {
|
|
16
|
+
return function (text) {
|
|
17
|
+
if (colors.length < 2) {
|
|
18
|
+
throw new Error('gradient needs at least 2 colors');
|
|
19
|
+
}
|
|
20
|
+
const segments = colors.length - 1;
|
|
21
|
+
const length = text.length;
|
|
22
|
+
let result = '';
|
|
23
|
+
for (let i = 0; i < length; i++) {
|
|
24
|
+
const pos = (i / (length - 1)) * segments;
|
|
25
|
+
const segIndex = Math.min(Math.floor(pos), segments - 1);
|
|
26
|
+
const t = pos - segIndex;
|
|
27
|
+
const start = hexToRgb(colors[segIndex]);
|
|
28
|
+
const end = hexToRgb(colors[segIndex + 1]);
|
|
29
|
+
const r = Math.round(start[0] + (end[0] - start[0]) * t);
|
|
30
|
+
const g = Math.round(start[1] + (end[1] - start[1]) * t);
|
|
31
|
+
const b = Math.round(start[2] + (end[2] - start[2]) * t);
|
|
32
|
+
result += rgbToAnsi([r, g, b]) + text[i];
|
|
33
|
+
}
|
|
34
|
+
return result + '\x1b[0m';
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import json5 from 'json5';
|
|
4
|
+
export async function loadTsConfigPaths() {
|
|
5
|
+
try {
|
|
6
|
+
const data = await readFile(join(process.cwd(), 'tsconfig.json'), 'utf-8');
|
|
7
|
+
const { compilerOptions: { paths } } = json5.parse(data);
|
|
8
|
+
return paths;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tsnite",
|
|
3
|
+
"description": "TypeScript at full throttle—fast, safe, unstoppable. 🚀",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"cli",
|
|
6
|
+
"esm",
|
|
7
|
+
"watch",
|
|
8
|
+
"nodejs",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
11
|
+
"version": "0.0.4",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"tsnite": "dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"prebuild": "rimraf dist",
|
|
18
|
+
"build": "tsc -p tsconfig.build.json",
|
|
19
|
+
"postbuild": "tsc-alias -f -p tsconfig.build.json",
|
|
20
|
+
"lint": "eslint . --config eslint.config.js",
|
|
21
|
+
"test": "jest --passWithNoTests --verbose",
|
|
22
|
+
"test:ci": "jest --passWithNoTests --ci",
|
|
23
|
+
"test:watch": "jest --passWithNoTests --watch",
|
|
24
|
+
"test:watchAll": "jest --passWithNoTests --watchAll",
|
|
25
|
+
"test:coverage": "jest --passWithNoTests --coverage",
|
|
26
|
+
"prepare": "husky"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@swc/core": "^1.13.5",
|
|
30
|
+
"chokidar": "^4.0.3",
|
|
31
|
+
"commander": "^14.0.0",
|
|
32
|
+
"json5": "^2.2.3"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@commitlint/cli": "^19.8.1",
|
|
36
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
37
|
+
"@eslint/js": "^9.35.0",
|
|
38
|
+
"@jest/globals": "^30.1.2",
|
|
39
|
+
"@swc/jest": "^0.2.39",
|
|
40
|
+
"eslint": "^9.35.0",
|
|
41
|
+
"eslint-plugin-jest": "^29.0.1",
|
|
42
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
43
|
+
"globals": "^16.3.0",
|
|
44
|
+
"husky": "^9.1.7",
|
|
45
|
+
"jest": "^30.1.3",
|
|
46
|
+
"jest-environment-node": "^30.1.2",
|
|
47
|
+
"jest-mock-extended": "^4.0.0",
|
|
48
|
+
"lint-staged": "^16.1.6",
|
|
49
|
+
"prettier": "^3.6.2",
|
|
50
|
+
"rimraf": "^6.0.1",
|
|
51
|
+
"tsc-alias": "^1.8.16",
|
|
52
|
+
"typescript": "^5.9.2",
|
|
53
|
+
"typescript-eslint": "^8.42.0"
|
|
54
|
+
},
|
|
55
|
+
"author": {
|
|
56
|
+
"name": "Luciano Alves",
|
|
57
|
+
"url": "https://github.com/luas10c"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": "^20.9.0 || ^22.11.0"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://github.com/luas10c/tsnite",
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "github",
|
|
65
|
+
"url": "git+https://github.com/luas10c/tsnite.git"
|
|
66
|
+
},
|
|
67
|
+
"bugs": {
|
|
68
|
+
"url": "https://gitbub.com/luas10c/tsnite/issues"
|
|
69
|
+
},
|
|
70
|
+
"license": "MIT"
|
|
71
|
+
}
|