Socket
Book a DemoInstallSign in
Socket

esbuild-tsc

Package Overview
Dependencies
Maintainers
0
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

esbuild-tsc - npm Package Compare versions

Comparing version

to
1.1.0

137

cjs/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = esbuildPluginTsc;
exports.EsbuildPluginTsc = void 0;
const tslib_1 = require("tslib");

@@ -8,78 +8,75 @@ const node_fs_1 = tslib_1.__importDefault(require("node:fs"));

const node_util_1 = require("node:util");
const strip_comments_1 = tslib_1.__importDefault(require("strip-comments"));
const typescript_1 = tslib_1.__importDefault(require("typescript"));
const DECORATOR_PATTERN = /((?<![(\s]\s*['"])@\(?\w*\w\s*(?!;)[(?=\s)])/;
function esbuildPluginTsc(options) {
const tsconfigPath = options?.tsconfigPath || node_path_1.default.join(process.cwd(), './tsconfig.json');
const tsx = options?.tsx ?? true;
return {
name: 'tsc',
setup(build) {
let parsedTsConfig;
build.onLoad({ filter: tsx ? /\.tsx?$/ : /\.ts$/ }, async (args) => {
if (!parsedTsConfig) {
parsedTsConfig = parseTsConfig(tsconfigPath, process.cwd());
if (parsedTsConfig.options.sourceMap) {
parsedTsConfig.options.sourceMap = false;
parsedTsConfig.options.inlineSources = true;
parsedTsConfig.options.inlineSourceMap = true;
}
}
// Just return if we don't need to search the file.
if (!(parsedTsConfig?.options?.emitDecoratorMetadata || options?.force)) {
return new EsbuildPluginTsc(options);
}
exports.default = esbuildPluginTsc;
/**
* @class EsbuildPluginTsc
*/
class EsbuildPluginTsc {
constructor(options) {
this.name = 'tsc';
this.options = {
tsconfigPath: options?.tsconfigPath || 'tsconfig.json',
filter: options?.filter || /\.tsx?$/,
};
}
setup(build) {
const parsedTsConfig = this._parseTsConfig(this.options.tsconfigPath, process.cwd());
if (parsedTsConfig.options?.sourceMap) {
parsedTsConfig.options.sourceMap = false;
parsedTsConfig.options.inlineSources = true;
parsedTsConfig.options.inlineSourceMap = true;
}
const filterFn = typeof this.options.filter === 'function'
? this.options.filter
: undefined;
build.onLoad({
filter: typeof this.options.filter === 'object'
? this.options.filter
: /\.tsx?$/,
}, async (args) => {
if (filterFn) {
if (!filterFn(args.path, parsedTsConfig))
return;
}
let fileContent;
try {
fileContent = node_fs_1.default.readFileSync(args.path, 'utf8');
}
catch (err) {
printDiagnostics({ file: args.path, err });
return;
}
if (!options?.force) {
// Find the decorator and if there isn't one, return out
const hasDecorator = findDecorators(fileContent);
if (!hasDecorator) {
return;
}
}
const program = typescript_1.default.transpileModule(fileContent, {
compilerOptions: parsedTsConfig.options,
fileName: node_path_1.default.basename(args.path),
});
return { contents: program.outputText };
}
else if (!parsedTsConfig?.options?.emitDecoratorMetadata) {
return;
}
const fileContent = node_fs_1.default.readFileSync(args.path, 'utf8');
const program = typescript_1.default.transpileModule(fileContent, {
compilerOptions: parsedTsConfig.options,
fileName: node_path_1.default.basename(args.path),
});
},
};
}
const findDecorators = (fileContent) => DECORATOR_PATTERN.test((0, strip_comments_1.default)(fileContent));
function parseTsConfig(tsconfig, cwd = process.cwd()) {
const fileName = typescript_1.default.findConfigFile(cwd, typescript_1.default.sys.fileExists, tsconfig);
// if the value was provided, but no file, fail hard
if (tsconfig !== undefined && !fileName) {
throw new Error(`failed to open '${fileName}'`);
return { contents: program.outputText };
});
}
let loadedConfig = {};
let baseDir = cwd;
if (fileName) {
const text = typescript_1.default.sys.readFile(fileName);
if (text === undefined)
throw new Error(`failed to read '${fileName}'`);
const result = typescript_1.default.parseConfigFileTextToJson(fileName, text);
if (result.error !== undefined) {
printDiagnostics(result.error);
throw new Error(`failed to parse '${fileName}'`);
_parseTsConfig(tsconfig, cwd = process.cwd()) {
const fileName = typescript_1.default.findConfigFile(cwd, typescript_1.default.sys.fileExists, tsconfig);
// if the value was provided, but no file, fail hard
if (tsconfig !== undefined && !fileName) {
throw new Error(`Unable to locate tsconfig'`);
}
loadedConfig = result.config;
baseDir = node_path_1.default.dirname(fileName);
let loadedConfig = {};
let baseDir = cwd;
if (fileName) {
const text = typescript_1.default.sys.readFile(fileName);
if (text === undefined)
throw new Error(`failed to read '${fileName}'`);
const result = typescript_1.default.parseConfigFileTextToJson(fileName, text);
loadedConfig = result.config;
baseDir = node_path_1.default.dirname(fileName);
}
const parsedTsConfig = typescript_1.default.parseJsonConfigFileContent(loadedConfig, typescript_1.default.sys, baseDir);
if (parsedTsConfig.errors.length) {
this._printDiagnostics(parsedTsConfig.errors);
}
return parsedTsConfig;
}
const parsedTsConfig = typescript_1.default.parseJsonConfigFileContent(loadedConfig, typescript_1.default.sys, baseDir);
if (parsedTsConfig.errors[0])
printDiagnostics(parsedTsConfig.errors);
return parsedTsConfig;
_printDiagnostics(...args) {
// eslint-disable-next-line no-console
console.log((0, node_util_1.inspect)(args, false, 10, true));
}
}
function printDiagnostics(...args) {
// eslint-disable-next-line no-console
console.log((0, node_util_1.inspect)(args, false, 10, true));
}
exports.EsbuildPluginTsc = EsbuildPluginTsc;
import fs from 'node:fs';
import path from 'node:path';
import { inspect } from 'node:util';
import stripComments from 'strip-comments';
import typescript from 'typescript';
const DECORATOR_PATTERN = /((?<![(\s]\s*['"])@\(?\w*\w\s*(?!;)[(?=\s)])/;
export default function esbuildPluginTsc(options) {
const tsconfigPath = options?.tsconfigPath || path.join(process.cwd(), './tsconfig.json');
const tsx = options?.tsx ?? true;
return {
name: 'tsc',
setup(build) {
let parsedTsConfig;
build.onLoad({ filter: tsx ? /\.tsx?$/ : /\.ts$/ }, async (args) => {
if (!parsedTsConfig) {
parsedTsConfig = parseTsConfig(tsconfigPath, process.cwd());
if (parsedTsConfig.options.sourceMap) {
parsedTsConfig.options.sourceMap = false;
parsedTsConfig.options.inlineSources = true;
parsedTsConfig.options.inlineSourceMap = true;
}
}
// Just return if we don't need to search the file.
if (!(parsedTsConfig?.options?.emitDecoratorMetadata || options?.force)) {
function esbuildPluginTsc(options) {
return new EsbuildPluginTsc(options);
}
export default esbuildPluginTsc;
/**
* @class EsbuildPluginTsc
*/
export class EsbuildPluginTsc {
constructor(options) {
this.name = 'tsc';
this.options = {
tsconfigPath: options?.tsconfigPath || 'tsconfig.json',
filter: options?.filter || /\.tsx?$/,
};
}
setup(build) {
const parsedTsConfig = this._parseTsConfig(this.options.tsconfigPath, process.cwd());
if (parsedTsConfig.options?.sourceMap) {
parsedTsConfig.options.sourceMap = false;
parsedTsConfig.options.inlineSources = true;
parsedTsConfig.options.inlineSourceMap = true;
}
const filterFn = typeof this.options.filter === 'function'
? this.options.filter
: undefined;
build.onLoad({
filter: typeof this.options.filter === 'object'
? this.options.filter
: /\.tsx?$/,
}, async (args) => {
if (filterFn) {
if (!filterFn(args.path, parsedTsConfig))
return;
}
let fileContent;
try {
fileContent = fs.readFileSync(args.path, 'utf8');
}
catch (err) {
printDiagnostics({ file: args.path, err });
return;
}
if (!options?.force) {
// Find the decorator and if there isn't one, return out
const hasDecorator = findDecorators(fileContent);
if (!hasDecorator) {
return;
}
}
const program = typescript.transpileModule(fileContent, {
compilerOptions: parsedTsConfig.options,
fileName: path.basename(args.path),
});
return { contents: program.outputText };
}
else if (!parsedTsConfig?.options?.emitDecoratorMetadata) {
return;
}
const fileContent = fs.readFileSync(args.path, 'utf8');
const program = typescript.transpileModule(fileContent, {
compilerOptions: parsedTsConfig.options,
fileName: path.basename(args.path),
});
},
};
}
const findDecorators = (fileContent) => DECORATOR_PATTERN.test(stripComments(fileContent));
function parseTsConfig(tsconfig, cwd = process.cwd()) {
const fileName = typescript.findConfigFile(cwd, typescript.sys.fileExists, tsconfig);
// if the value was provided, but no file, fail hard
if (tsconfig !== undefined && !fileName) {
throw new Error(`failed to open '${fileName}'`);
return { contents: program.outputText };
});
}
let loadedConfig = {};
let baseDir = cwd;
if (fileName) {
const text = typescript.sys.readFile(fileName);
if (text === undefined)
throw new Error(`failed to read '${fileName}'`);
const result = typescript.parseConfigFileTextToJson(fileName, text);
if (result.error !== undefined) {
printDiagnostics(result.error);
throw new Error(`failed to parse '${fileName}'`);
_parseTsConfig(tsconfig, cwd = process.cwd()) {
const fileName = typescript.findConfigFile(cwd, typescript.sys.fileExists, tsconfig);
// if the value was provided, but no file, fail hard
if (tsconfig !== undefined && !fileName) {
throw new Error(`Unable to locate tsconfig'`);
}
loadedConfig = result.config;
baseDir = path.dirname(fileName);
let loadedConfig = {};
let baseDir = cwd;
if (fileName) {
const text = typescript.sys.readFile(fileName);
if (text === undefined)
throw new Error(`failed to read '${fileName}'`);
const result = typescript.parseConfigFileTextToJson(fileName, text);
loadedConfig = result.config;
baseDir = path.dirname(fileName);
}
const parsedTsConfig = typescript.parseJsonConfigFileContent(loadedConfig, typescript.sys, baseDir);
if (parsedTsConfig.errors.length) {
this._printDiagnostics(parsedTsConfig.errors);
}
return parsedTsConfig;
}
const parsedTsConfig = typescript.parseJsonConfigFileContent(loadedConfig, typescript.sys, baseDir);
if (parsedTsConfig.errors[0])
printDiagnostics(parsedTsConfig.errors);
return parsedTsConfig;
_printDiagnostics(...args) {
// eslint-disable-next-line no-console
console.log(inspect(args, false, 10, true));
}
}
function printDiagnostics(...args) {
// eslint-disable-next-line no-console
console.log(inspect(args, false, 10, true));
}
{
"name": "esbuild-tsc",
"description": "An esbuild plugin which uses tsc to compile typescript files",
"version": "1.0.0",
"version": "1.1.0",
"author": "Panates",
"license": "MIT",
"dependencies": {
"strip-comments": "^2.0.1"
},
"dependencies": {},
"type": "module",

@@ -11,0 +9,0 @@ "exports": {

# esbuild-tsc
An esbuild plugin which uses tsc to compile typescript files
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![CircleCI][circleci-image]][circleci-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Note: Originally inspired from [esbuild-plugin-tsc](https://www.npmjs.com/package/esbuild-plugin-tsc), Thanks to *Thomas Schaaf*
## Motivation
## About
Esbuild natively supports typescript files - so if you are not using exotic typescript features this plugin is not meant for you!
An ESBuild plugin which uses tsc to compile typescript files
I wanted to use [`typescripts emitDecoratorMetadata`](https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata) feature,
which is [not supported by esbuild](https://github.com/evanw/esbuild/issues/257).
If you are only using typescript decorators in some files, this plugin allows you to convert only
the files containing decorators and lets esbuild handle all other files.
If for some reason you want to use typescripts compiler for all files
you can simple set the `force` option.
## Motivation
## Basic Usage
Esbuild natively supports typescript files, but not TypeScript decorators.
TypeScript decorators are different from EcmaScript decorators.
If TypeScript decorators are used in your project, tsc should be used to transpile.
1. Install this plugin in your project:
## Installation

@@ -26,19 +25,10 @@ ```sh

2. Add this plugin to your esbuild build script:
## Basic Usage
Javascript:
```diff
+const esbuildPluginTsc = require('esbuild-tsc');
...
esbuild.build({
...
plugins: [
+ esbuildPluginTsc(),
],
})
```
Add this plugin to your esbuild build script:
Typescript:
```diff
+import esbuildPluginTsc from 'esbuild-plugin-tsc';
```ts
import esbuildPluginTsc from 'esbuild-tsc';
...

@@ -48,18 +38,28 @@ esbuild.build({

plugins: [
+ esbuildPluginTsc(),
esbuildPluginTsc(options),
],
})
});
```
## Config
### Options
```typescript
esbuildPluginTsc({
// If empty, uses tsconfig.json
tsconfigPath?: string,
// If true, force compilation with tsc
force?: boolean,
// If true, enables tsx file support
tsx?: boolean
})
```
**_tsconfigPath [string] _**: Path of the tsconfig json file.
**_filter [RegExp | Function]_**: A RegExp or function to filter files.
[npm-image]: https://img.shields.io/npm/v/esbuild-tsc.svg
[npm-url]: https://npmjs.org/package/esbuild-tsc
[circleci-image]: https://circleci.com/gh/panates/esbuild-tsc/tree/master.svg?style=shield
[circleci-url]: https://circleci.com/gh/panates/esbuild-tsc/tree/master
[coveralls-image]: https://img.shields.io/coveralls/panates/esbuild-tsc/master.svg
[coveralls-url]: https://coveralls.io/r/panates/esbuild-tsc
[downloads-image]: https://img.shields.io/npm/dm/esbuild-tsc.svg
[downloads-url]: https://npmjs.org/package/esbuild-tsc
[gitter-image]: https://badges.gitter.im/panates/esbuild-tsc.svg
[gitter-url]: https://gitter.im/panates/esbuild-tsc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[dependencies-image]: https://david-dm.org/panates/esbuild-tsc/status.svg
[dependencies-url]:https://david-dm.org/panates/esbuild-tsc
[devdependencies-image]: https://david-dm.org/panates/esbuild-tsc/dev-status.svg
[devdependencies-url]:https://david-dm.org/panates/esbuild-tsc?type=dev
[quality-image]: http://npm.packagequality.com/shield/esbuild-tsc.png
[quality-url]: http://packagequality.com/#?package=esbuild-tsc

@@ -1,6 +0,24 @@

import type { Plugin } from 'esbuild';
export default function esbuildPluginTsc(options?: {
tsconfigPath?: string;
force?: boolean;
tsx?: boolean;
}): Plugin;
import type { Plugin, PluginBuild } from 'esbuild';
import typescript from 'typescript';
declare function esbuildPluginTsc(options?: EsbuildPluginTsc.Options): EsbuildPluginTsc;
export default esbuildPluginTsc;
/**
* @namespace EsbuildPluginTsc
*/
export declare namespace EsbuildPluginTsc {
interface Options {
tsconfigPath?: string;
filter?: RegExp | ((filename: string, tsconfig: typescript.ParsedCommandLine) => boolean);
}
}
/**
* @class EsbuildPluginTsc
*/
export declare class EsbuildPluginTsc implements Plugin {
name: string;
options: Required<EsbuildPluginTsc.Options>;
constructor(options?: EsbuildPluginTsc.Options);
setup(build: PluginBuild): void;
protected _parseTsConfig(tsconfig: string, cwd?: string): typescript.ParsedCommandLine;
protected _printDiagnostics(...args: any[]): void;
}