Socket
Socket
Sign inDemoInstall

tshy

Package Overview
Dependencies
6
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0-3 to 1.0.0

dist/esm/add-dot.d.ts

2

dist/esm/build.d.ts
import './tsconfig.js';
declare const _default: () => void;
export default _default;
//# sourceMappingURL=build.d.ts.map

69

dist/esm/build.js
import chalk from 'chalk';
import { spawnSync } from 'node:child_process';
import { renameSync } from 'node:fs';
import { relative, resolve } from 'node:path/posix';
import { rimrafSync } from 'rimraf';
import { syncContentSync } from 'sync-content';
import bins from './bins.js';
import { buildCommonJS } from './build-commonjs.js';
import { buildESM } from './build-esm.js';
import * as console from './console.js';
import dialects from './dialects.js';
import { fail } from './fail.js';
import polyfills from './polyfills.js';
import setFolderDialect from './set-folder-dialect.js';
import './tsconfig.js';
import writePackage from './write-package.js';
const buildFail = (res) => {
setFolderDialect('src');
fail('build failed');
console.error(res);
process.exit(1);
export default () => {
rimrafSync('.tshy-build-tmp');
if (dialects.includes('esm'))
buildESM();
if (dialects.includes('commonjs'))
buildCommonJS();
console.debug(chalk.cyan.dim('moving to ./dist'));
syncContentSync('.tshy-build-tmp', 'dist');
console.debug(chalk.cyan.dim('removing build temp dir'));
rimrafSync('.tshy-build-tmp');
console.debug(chalk.cyan.dim('chmod bins'));
bins();
console.debug(chalk.cyan.dim('write package.json'));
writePackage();
};
rimrafSync('.tshy-build-tmp');
if (dialects.includes('esm')) {
setFolderDialect('src', 'esm');
console.debug(chalk.cyan.dim('building esm'));
const res = spawnSync('tsc -p .tshy/esm.json', {
shell: true,
stdio: 'inherit',
});
setFolderDialect('src');
if (res.status || res.signal)
buildFail(res);
setFolderDialect('.tshy-build-tmp/esm', 'esm');
console.error(chalk.cyan.bold('built esm'));
}
if (dialects.includes('commonjs')) {
setFolderDialect('src', 'commonjs');
console.debug(chalk.cyan.dim('building commonjs'));
const res = spawnSync('tsc -p .tshy/commonjs.json', {
shell: true,
stdio: 'inherit',
});
setFolderDialect('src');
if (res.status || res.signal)
buildFail(res);
setFolderDialect('.tshy-build-tmp/commonjs', 'commonjs');
console.error(chalk.cyan.bold('built commonjs'));
// apply polyfills
for (const [f, t] of polyfills.entries()) {
const stemFrom = resolve('.tshy-build-tmp/commonjs', relative(resolve('src'), resolve(f))).replace(/\.cts$/, '');
const stemTo = resolve('.tshy-build-tmp/commonjs', relative(resolve('src'), resolve(t))).replace(/\.tsx?$/, '');
renameSync(`${stemFrom}.cjs`, `${stemTo}.js`);
renameSync(`${stemFrom}.d.cts`, `${stemTo}.d.ts`);
}
}
console.debug(chalk.cyan.dim('moving to ./dist'));
syncContentSync('.tshy-build-tmp', 'dist');
console.debug(chalk.cyan.dim('removing build temp dir'));
rimrafSync('.tshy-build-tmp');
console.debug(chalk.cyan.dim('chmod bins'));
bins();
console.debug(chalk.cyan.dim('write package.json'));
writePackage();
//# sourceMappingURL=build.js.map
// get the config and package and stuff
import { fail } from './fail.js';
import pkg from './package.js';
import sources from './sources.js';
import validDialects from './valid-dialects.js';
import validExports from './valid-exports.js';
const validConfig = (e) => !!e &&

@@ -7,58 +10,2 @@ typeof e === 'object' &&

(e.dialects === undefined || validDialects(e['dialects']));
const isDialect = (d) => d === 'commonjs' || d === 'esm';
const validDialects = (d) => !!d && Array.isArray(d) && !d.some(d => !isDialect(d));
const validExternalExport = (exp) => {
const i = resolveExport(exp, 'import');
const r = resolveExport(exp, 'require');
if (!i && !r)
return false;
if (i && join(i).startsWith('src/'))
return false;
if (r && join(r).startsWith('src/'))
return false;
return true;
};
const validExports = (e) => {
if (!e)
return false;
if (typeof e !== 'object')
return false;
for (const [sub, exp] of Object.entries(e)) {
if (sub !== '.' && !sub.startsWith('./')) {
fail(`tshy.exports key must be "." or start with "./", got: ${sub}`);
process.exit(1);
}
// just a module. either a built export, or a simple unbuilt export
if (typeof exp === 'string') {
e[sub] = addDot(exp);
continue;
}
if (typeof exp !== 'object' || !exp || Array.isArray(exp)) {
fail(`tshy.exports ${sub} value must be string or import/require object, ` +
`got: ${JSON.stringify(exp)}`);
process.exit(1);
}
// can be:
// "./sub": "./unbuilt.js"
// "./sub": { require: "./unbuilt.js", types: "./unbuilt.d.ts" }
// "./sub": {require:"./u.cjs",import:"./u.cjs",types:"./u.dts"}
// "./sub": {import:{types:"u.d.ts",default:"u.js"},require:{types:"u.d.cts", default:"u.cjs"}}
// Just verify that import and require resolutions are not in src
if (!validExternalExport(exp)) {
fail(`tshy.exports ${sub} unbuilt exports must not be in ./src, ` +
`and exports in src must be string values. ` +
`got: ${JSON.stringify(exp)}`);
process.exit(1);
}
e[sub] = exp;
}
if (e.dialects) {
if (!validDialects(e.dialects)) {
fail(`tshy.dialects must be array containing 'esm' and/or 'commonjs', ` +
`got: ${JSON.stringify(e.dialects)}`);
}
}
return true;
};
const addDot = (s) => `./${join(s)}`;
const getConfig = (pkg, sources) => {

@@ -81,8 +28,4 @@ const tshy = validConfig(pkg.tshy) ? pkg.tshy : {};

};
import { join } from 'path/posix';
import pkg from './package.js';
import sources from './sources.js';
import { resolveExport } from './resolve-export.js';
const config = getConfig(pkg, sources);
export default config;
//# sourceMappingURL=config.js.map

@@ -1,4 +0,7 @@

import { Export } from './types.js';
import { Export, TshyConfig, TshyExport } from './types.js';
export declare const getImpTarget: (s: string | TshyExport | undefined | null) => string | undefined | null;
export declare const getReqTarget: (s: string | TshyExport | undefined | null, polyfills: Map<string, string>) => string | null | undefined;
export declare const getExports: (c: TshyConfig, polyfills: Map<string, string>) => Record<string, Export>;
declare const _default: Record<string, Export>;
export default _default;
//# sourceMappingURL=exports.d.ts.map
import { relative, resolve } from 'node:path/posix';
import config from './config.js';
import dialects from './dialects.js';
import { fail } from './fail.js';
import fail from './fail.js';
import pkg from './package.js';
import polyfills from './polyfills.js';
import { resolveExport } from './resolve-export.js';
const getImpTarget = (s) => {
export const getImpTarget = (s) => {
if (s === undefined)

@@ -19,7 +19,5 @@ return undefined;

}
if (s && typeof s === 'object') {
return resolveExport(s, 'import');
}
return resolveExport(s, 'import');
};
const getReqTarget = (s, polyfills) => {
export const getReqTarget = (s, polyfills) => {
if (s === undefined)

@@ -35,7 +33,7 @@ return undefined;

}
if (s && typeof s === 'object') {
return getReqTarget(resolveExport(s, 'require'), polyfills);
}
return getReqTarget(resolveExport(s, 'require'), polyfills);
};
const getExports = (c, polyfills) => {
export const getExports = (c, polyfills) => {
// by this time it always exports, will get the default if missing
/* c8 ignore start */
if (!c.exports) {

@@ -45,6 +43,5 @@ fail('no exports on tshy config (is there code in ./src?)');

}
/* c8 ignore stop */
const e = {};
for (const [sub, s] of Object.entries(c.exports)) {
const impTarget = getImpTarget(s);
const reqTarget = getReqTarget(s, polyfills);
// external export, not built by us

@@ -56,4 +53,9 @@ if (typeof s !== 'string' || !s.startsWith('./src/')) {

}
const impTarget = getImpTarget(s);
const reqTarget = getReqTarget(s, polyfills);
// should be impossible
/* c8 ignore start */
if (!impTarget && !reqTarget)
continue;
/* c8 ignore stop */
const exp = (e[sub] = {});

@@ -60,0 +62,0 @@ if (impTarget) {

@@ -1,2 +0,3 @@

export declare const fail: (message: string, er?: Error) => void;
declare const _default: (message: string, er?: Error) => void;
export default _default;
//# sourceMappingURL=fail.d.ts.map
import chalk from 'chalk';
import * as console from './console.js';
export const fail = (message, er) => {
export default (message, er) => {
console.error(chalk.red.bold(message));

@@ -5,0 +5,0 @@ if (er)

@@ -6,2 +6,3 @@ #!/usr/bin/env node

import pkg from './package.js';
import build from './build.js';
const { exports: exp, tshy } = pkg;

@@ -11,5 +12,4 @@ console.debug(chalk.yellow.bold('building'), process.cwd());

console.debug(chalk.cyan.dim('exports'), exp);
// have our config, time to build
await import('./build.js');
build();
console.log(chalk.bold.green('success!'));
//# sourceMappingURL=index.js.map
import { Package } from './types.js';
declare const pkg: Package;
export default pkg;
declare const _default: Package;
export default _default;
//# sourceMappingURL=package.d.ts.map
// get the package.json data for the cwd
import { readFileSync } from 'fs';
import { fail } from './fail.js';
import fail from './fail.js';
const readPkg = () => {
try {
return JSON.parse(readFileSync('package.json', 'utf8'));
return Object.assign(JSON.parse(readFileSync('package.json', 'utf8')), { type: 'module' });
}

@@ -13,5 +13,3 @@ catch (er) {

};
const pkg = readPkg();
pkg.type = 'module';
export default pkg;
export default readPkg();
//# sourceMappingURL=package.js.map

@@ -1,2 +0,2 @@

export declare const resolveExport: (exp: any, t: 'import' | 'require') => string | undefined;
export declare const resolveExport: (exp: any, m: 'import' | 'require') => string | undefined | null;
//# sourceMappingURL=resolve-export.d.ts.map

@@ -1,10 +0,12 @@

export const resolveExport = (exp, t) => {
export const resolveExport = (exp, m) => {
if (typeof exp === 'string')
return exp;
if (!exp || typeof exp !== 'object')
if (typeof exp !== 'object')
return undefined;
if (exp === null)
return exp;
if (Array.isArray(exp)) {
for (const e of exp) {
const u = resolveExport(e, t);
if (u)
const u = resolveExport(e, m);
if (u || u === null)
return u;

@@ -14,9 +16,9 @@ }

}
if (exp[t])
return resolveExport(exp[t], t);
if (exp[m])
return resolveExport(exp[m], m);
if (exp.node)
return resolveExport(exp.node, t);
return resolveExport(exp.node, m);
if (exp.default)
return resolveExport(exp.default, t);
return resolveExport(exp.default, m);
};
//# sourceMappingURL=resolve-export.js.map

@@ -32,3 +32,3 @@ export type TshyConfig = {

bin?: string | Record<string, string>;
exports: Record<string, Export>;
exports?: Record<string, Export>;
tshy?: TshyConfig;

@@ -35,0 +35,0 @@ [k: string]: any;

{
"name": "tshy",
"version": "1.0.0-3",
"version": "1.0.0",
"description": "TypeScript HYbridizer - Hybrid (CommonJS/ESM) TypeScript node package builder",

@@ -27,4 +27,9 @@ "author": "Isaac Z. Schlueter <i@izs.me> (https://izs.me)",

"format": "prettier --write . --ignore-path ./.prettierignore --cache",
"typedoc": "typedoc"
"typedoc": "typedoc",
"test": "tap",
"snap": "tap"
},
"tap": {
"coverage-map": "map.js"
},
"engines": {

@@ -45,2 +50,3 @@ "node": "16 >=16.17 || 18 >=18.16.0 || >=20.6.1"

"prettier": "^2.8.8",
"tap": "^18.0.0-26",
"typedoc": "^0.25.1"

@@ -47,0 +53,0 @@ },

# tshy - TypeScript HYbridizer
Hybrid (CommonJS/ESM) TypeScript node package builder.
Hybrid (CommonJS/ESM) TypeScript node package builder. Write
modules that Just Work in ESM and CommonJS, in easy mode.
This tool manages the `exports` in your package.json file, and
builds your TypeScript program using `tsc` 5.2 in both ESM and
CJS modes.
builds your TypeScript program using `tsc` 5.2, emitting both ESM
and CommonJS variants, [providing the full strength of
TypeScript’s checking for both output
formats](https://twitter.com/atcb/status/1702069237710479608).

@@ -38,7 +41,7 @@ ## USAGE

Mostly, this is opinionated convention, and so there is very
little to configure.
Mostly, this just uses opinionated convention, and so there is
very little to configure.
Source must be in `./src`. Builds are in `./dist/cjs` for
CommonJS and `./dist/mjs` for ESM.
Source must be in `./src`. Builds are in `./dist/commonjs` for
CommonJS and `./dist/esm` for ESM.

@@ -73,8 +76,8 @@ There is very little configuration for this. The only thing to

"import": {
"types": "./dist/mjs/foo.d.ts",
"default": "./dist/mjs/foo.js"
"types": "./dist/esm/foo.d.ts",
"default": "./dist/esm/foo.js"
},
"require": {
"types": "./dist/cjs/foo.d.ts",
"default": "./dist/cjs/foo.js"
"types": "./dist/commonjs/foo.d.ts",
"default": "./dist/commonjs/foo.js"
}

@@ -87,12 +90,23 @@ }

Any exports that are not within `./src` will not be built, and
can be either a string, or a `{ import, require, types }` object:
can be anything supported by package.json `exports`, as they will
just be passed through as-is.
```json
{
"exports": {
"./package.json": "./package.json"
"./thing": {
"import": "./lib/thing.mjs",
"require": "./lib/thing.cjs",
"types": "./lib/thing.d.ts"
"tshy": {
"exports": {
".": "./src/my-built-module.ts",
"./package.json": "./package.json"
"./thing": {
"import": "./lib/thing.mjs",
"require": "./lib/thing.cjs",
"types": "./lib/thing.d.ts"
},
"./arraystyle": [
{ "import": "./no-op.js" },
{ "browser": "./browser-thing.js" },
{ "require": [{ "types": "./using-require.d.ts" }, "./using-require.js"],
{ "types": "./blah.d.ts" },
"./etc.js"
]
}

@@ -143,3 +157,3 @@ }

// ^^^^^^^^^^--------- matching name
// ^^^^----- "-cts" tag
// ^^^^----- "-cjs" tag
// ^^^^- ".cts" filename suffix

@@ -156,5 +170,10 @@ // this one has a -cjs.cts suffix, so it will override the

You will generally have to `//@ts-ignore` a bunch of stuff to get
the CommonJS build to ignore it, so it's best to keep the
polyfill surface as small as possible.
```js
// src/source-dir.ts
// This is the ESM version of the module
//@ts-ignore
export const sourceDir = new URL('.', import.meta.url)

@@ -164,5 +183,5 @@ ```

Then in your code, you can just `import { sourceDir } from
'./source-dir.js'` and it'll work in both dialects.
'./source-dir.js'` and it'll work in both builds.
## `.cts` and `.mts` files
## Excluding from a build using `.cts` and `.mts` files

@@ -173,4 +192,4 @@ Files named `*.mts` will be excluded from the CommonJS build.

If you need to do something one way for CJS and another way for
ESM, use the "Dialect Switching" trick, with the ESM code living
If you need to do something one way for CommonJS and another way for
esm, use the "Dialect Switching" trick, with the ESM code living
in `src/<whatever>.ts` and the CommonJS polyfill living in

@@ -210,3 +229,3 @@ `src/<whatever>-cjs.cts`.

get local imports, and the package.json files placed in
`dist/{cjs,mjs}` can't have local imports outside of their
`dist/{commonjs,esm}` can't have local imports outside of their
folders.

@@ -236,3 +255,3 @@

Then the `tsconfig.json` file will be used as the default project
for code hints in VSCode/nvim, your tests, etc.
for code hints in VSCode, neovim, tests, etc.

@@ -242,3 +261,3 @@ ## `src/package.json`

As of TypeScript 5.2, the only way to emit JavaScript to ESM or
CJS, and also import packages using node-style `"exports"`-aware
cjs, and also import packages using node-style `"exports"`-aware
module resolution, is to set the `type` field in the

@@ -245,0 +264,0 @@ `package.json` file closest to the TypeScript source code.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc