New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@chialab/esbuild-plugin-transform

Package Overview
Dependencies
Maintainers
2
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chialab/esbuild-plugin-transform - npm Package Compare versions

Comparing version 0.8.4 to 0.9.0

245

lib/index.js

@@ -6,4 +6,15 @@ import { promises } from 'fs';

const { readFile } = promises;
const { default: SourceMap } = sourcemap;
const { default: SourceMapNode } = sourcemap;
/**
* @typedef {Object} SourceMap
* @property {number} version
* @property {string[]} sources
* @property {string[]} names
* @property {string} [sourceRoot]
* @property {string[]} [sourcesContent]
* @property {string} mappings
* @property {string} file
*/
export const SCRIPT_LOADERS = ['tsx', 'ts', 'jsx', 'js'];

@@ -28,6 +39,10 @@

/**
* @typedef {{ filter: RegExp, store: Map<string, Entry>, getEntry(filePath: string): Promise<Entry>, buildEntry(filePath: string, extra?: Partial<import('esbuild').OnLoadResult>): Promise<import('esbuild').OnLoadResult|undefined>, finishEntry(filePath: string, extra?: Partial<import('esbuild').OnLoadResult>): Promise<import('esbuild').OnLoadResult|undefined> }} TransformOptions
* @typedef {(filePath: string, result: { code: string, map?: SourceMap|SourceMap[], loader?: import('esbuild').Loader }, extra?: Partial<import('esbuild').OnLoadResult>) => Promise<import('esbuild').OnLoadResult|undefined>} BuildFactory
*/
/**
* @typedef {{ entry?: Entry, filter: RegExp, store: Map<string, Entry>, getEntry(filePath: string): Promise<Entry>, buildEntry: BuildFactory }} TransformOptions
*/
/**
* @typedef {import('esbuild').BuildOptions & { transform?: TransformOptions }} BuildTransformOptions

@@ -61,3 +76,2 @@ */

buildEntry: buildEntryFactory(build, options),
finishEntry: buildEntryFactory(build, options),
};

@@ -68,6 +82,7 @@ }

* @param {string} filePath
* @param {string} [contents]
* @return {Promise<Entry>}
*/
export async function createEntry(filePath) {
const code = await readFile(filePath, 'utf-8');
export async function createEntry(filePath, contents) {
const code = contents || await readFile(filePath, 'utf-8');
return {

@@ -83,2 +98,33 @@ filePath,

/**
* Transpile entry to standard js.
* @param {Entry} entry
* @param {typeof import('esbuild')} esbuild
* @param {import('esbuild').BuildOptions} [options]
*/
export async function transpileEntry(entry, esbuild, options = {}) {
if (entry.target !== TARGETS.typescript) {
return {
code: entry.code,
loader: entry.loader,
};
}
const loaders = options.loader || {};
const { code, map } = await esbuild.transform(entry.code, {
sourcefile: entry.filePath,
sourcemap: true,
loader: loaders[path.extname(entry.filePath)] === 'ts' ? 'ts' : 'tsx',
format: 'esm',
target: TARGETS.es2020,
jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
});
return {
code,
map,
loader: /** @type {import('esbuild').Loader} */ ('js'),
};
}
/**
* @param {import('esbuild').PluginBuild} build

@@ -89,11 +135,12 @@ */

* @param {string} filePath
* @param {string} [initialContents]
*/
async function getEntry(filePath) {
async function getEntry(filePath, initialContents) {
const options = /** @type {BuildTransformOptions} */ (build.initialOptions);
if (!options.transform) {
return await createEntry(filePath);
return await createEntry(filePath, initialContents);
}
const store = options.transform.store;
const entry = store.get(filePath) || await createEntry(filePath);
const entry = store.get(filePath) || await createEntry(filePath, initialContents);
store.set(filePath, entry);

@@ -107,2 +154,37 @@ return entry;

/**
* @param {string} basename
* @param {string} original
*/
function createInitialSourceMap(basename, original) {
const initialSourceMap = new SourceMapNode();
initialSourceMap.setSourceContent(basename, original);
return initialSourceMap;
}
/**
* @param {string} basename
* @param {string} original
* @param {SourceMap[]} mappings
*/
function mergeMappings(basename, original, mappings) {
const initial = createInitialSourceMap(basename, original);
const sourceMap = mappings.reduce((sourceMap, mapping) => {
mapping.file = basename;
mapping.sources = [basename];
mapping.sourcesContent = [original];
try {
const map = new SourceMapNode();
map.addVLQMap(mapping);
map.extends(sourceMap.toBuffer());
return map;
} catch (err) {
//
}
return sourceMap;
}, initial);
return sourceMap.toVLQ();
}
/**
* @param {import('esbuild').PluginBuild} build

@@ -113,11 +195,5 @@ * @param {import('esbuild').BuildOptions} options

/**
* @param {string} filePath
* @param {Partial<import('esbuild').OnLoadResult>} extra
* @return {Promise<import('esbuild').OnLoadResult|undefined>}
* @type {BuildFactory}
*/
async function buildEntry(filePath, extra = {}) {
if (!shouldReturn) {
return;
}
async function buildEntry(filePath, { code, map, loader }, extra = {}) {
const { store } = getTransformOptions(build);

@@ -129,5 +205,19 @@ const entry = store.get(filePath);

if (!shouldReturn) {
entry.code = code;
if (Array.isArray(map)) {
entry.mappings.push(...map);
} else if (map) {
entry.mappings.push(map);
}
if (loader) {
entry.loader = loader;
}
return;
}
const loaders = options.loader || {};
const defaultLoader = (loaders[path.extname(filePath)] === 'ts' ? 'ts' : 'tsx');
const { original, mappings, code } = entry;
const { original } = entry;
const mappings = Array.isArray(map) ? map : (map ? [map] : entry.mappings);
if (!mappings.length) {

@@ -142,29 +232,12 @@ return {

const basename = path.basename(entry.filePath);
const initialSourceMap = new SourceMap();
initialSourceMap.setSourceContent(basename, original);
const sourceMap = mappings.reduce((sourceMap, mapping) => {
mapping.file = basename;
mapping.sources = [basename];
mapping.sourcesContent = [original];
try {
const map = new SourceMap();
map.addVLQMap(mapping);
map.extends(sourceMap.toBuffer());
return map;
} catch(err) {
//
}
return sourceMap;
}, initialSourceMap);
const finalMap = mappings.length > 1 ? mergeMappings(basename, original, mappings) : mappings[0];
finalMap.version = 3;
finalMap.file = basename;
finalMap.sources = [basename];
finalMap.sourcesContent = [original];
const map = sourceMap.toVLQ();
map.version = 3;
map.file = basename;
map.sources = [basename];
map.sourcesContent = [original];
return {
...extra,
loader: entry.loader || extra.loader || defaultLoader,
contents: `${code}\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(JSON.stringify(map)).toString('base64')}`,
contents: `${code}\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(JSON.stringify(finalMap)).toString('base64')}`,
};

@@ -177,5 +250,10 @@ }

/**
* @typedef {(args: import('esbuild').OnLoadArgs) => import('esbuild').OnLoadResult} LoadCallback
*/
/**
* @param {import('esbuild').Plugin[]} plugins
* @return An esbuild plugin.
*/
export function start() {
export default function(plugins = []) {
/**

@@ -185,3 +263,3 @@ * @type {import('esbuild').Plugin}

const plugin = {
name: 'transform-start',
name: 'transform',
setup(build) {

@@ -195,2 +273,15 @@ /**

const getEntry = getEntryFactory(build);
const buildEntry = buildEntryFactory(build, options, false);
const finishEntry = buildEntryFactory(build, options);
const { stdin, loader: loaders = {} } = options;
const input = stdin ? (stdin.sourcefile || 'stdin.js') : undefined;
if (stdin && input) {
const regex = new RegExp(input.replace(/([()[\]{}\\\-+.*?^$])/g, '\\$1'));
build.onResolve({ filter: regex }, () => ({ path: input, namespace: 'file' }));
delete options.stdin;
options.entryPoints = [input];
}
Object.defineProperty(options, 'transform', {

@@ -202,30 +293,53 @@ enumerable: false,

store,
getEntry: getEntryFactory(build),
buildEntry: buildEntryFactory(build, options, false),
finishEntry: buildEntryFactory(build, options),
getEntry,
buildEntry,
},
});
},
};
return plugin;
}
/**
* @type {Array<[import('esbuild').OnLoadOptions, LoadCallback]>}
*/
const onLoad = [];
for (let i = 0; i < plugins.length; i++) {
plugins[i].setup({
initialOptions: build.initialOptions,
onStart: build.onStart.bind(build),
onEnd: build.onEnd.bind(build),
onResolve: build.onResolve.bind(build),
/**
* @param {import('esbuild').OnLoadOptions} options
* @param {LoadCallback} callback
*/
onLoad(options, callback) {
if (options.namespace === 'file') {
onLoad.push([options, callback]);
} else {
build.onLoad(options, callback);
}
},
});
}
/**
* @return An esbuild plugin.
*/
export function end() {
/**
* @type {import('esbuild').Plugin}
*/
const plugin = {
name: 'transform-end',
setup(build) {
const options = build.initialOptions;
const loaders = options.loader || {};
const { filter, finishEntry } = getTransformOptions(build);
build.onLoad({ filter, namespace: 'file' }, async (args) => {
if (args.path === input && stdin) {
await getEntry(args.path, stdin.contents);
}
build.onLoad({ filter, namespace: 'file' }, async (args) => finishEntry(args.path, {
loader: loaders[path.extname(args.path)] === 'ts' ? 'ts' : 'tsx',
}));
for (let i = 0; i < onLoad.length; i++) {
const [{ filter, namespace }, callback] = onLoad[i];
if (!filter.test(args.path) || (namespace && namespace !== args.namespace)) {
continue;
}
await callback(args);
}
const { code, mappings, loader } = await getEntry(args.path);
return finishEntry(args.path, {
code,
map: mappings,
loader,
}, {
loader: loaders[path.extname(args.path)] === 'ts' ? 'ts' : 'tsx',
});
});
},

@@ -236,1 +350,2 @@ };

}
{
"name": "@chialab/esbuild-plugin-transform",
"type": "module",
"version": "0.8.4",
"version": "0.9.0",
"description": "Pipe transformation plugin for esbuild.",

@@ -13,3 +13,3 @@ "main": "lib/index.js",

"url": "https://github.com/chialab/rna",
"directory": "packages/esbuild-plugin-commonjs"
"directory": "packages/esbuild-plugin-transform"
},

@@ -43,3 +43,3 @@ "keywords": [

},
"gitHead": "dfc6716438e20433c8f424ec1f0689a2c80f167f"
"gitHead": "530ad171be0786bc9e5fdc044276467db3a2697a"
}

@@ -22,8 +22,9 @@ <p align="center">

import esbuild from 'esbuild';
import { start, end } from '@chialab/esbuild-plugin-transform';
import transform from '@chialab/esbuild-plugin-transform';
await esbuild.build({
plugins: [
start(),
end(),
transform([
// plugins
]),
],

@@ -55,9 +56,9 @@ });

build.onLoad({ filter: /\./, namespace: 'file' }, async (args) => {
build.onLoad({ filter, namespace: 'file' }, async (args) => {
const entry = await getEntry(args.path);
const { code, map } = await transform(entry.code);
entry.code = code;
entry.mappings.push(map);
return buildEntry(entry, {
code,
map,
loader: 'js',

@@ -64,0 +65,0 @@ });

@@ -5,5 +5,8 @@ /**

/**
* @typedef {{ filter: RegExp, store: Map<string, Entry>, getEntry(filePath: string): Promise<Entry>, buildEntry(filePath: string, extra?: Partial<import('esbuild').OnLoadResult>): Promise<import('esbuild').OnLoadResult|undefined>, finishEntry(filePath: string, extra?: Partial<import('esbuild').OnLoadResult>): Promise<import('esbuild').OnLoadResult|undefined> }} TransformOptions
* @typedef {(filePath: string, result: { code: string, map?: SourceMap|SourceMap[], loader?: import('esbuild').Loader }, extra?: Partial<import('esbuild').OnLoadResult>) => Promise<import('esbuild').OnLoadResult|undefined>} BuildFactory
*/
/**
* @typedef {{ entry?: Entry, filter: RegExp, store: Map<string, Entry>, getEntry(filePath: string): Promise<Entry>, buildEntry: BuildFactory }} TransformOptions
*/
/**
* @typedef {import('esbuild').BuildOptions & { transform?: TransformOptions }} BuildTransformOptions

@@ -22,13 +25,39 @@ */

* @param {string} filePath
* @param {string} [contents]
* @return {Promise<Entry>}
*/
export function createEntry(filePath: string): Promise<Entry>;
export function createEntry(filePath: string, contents?: string | undefined): Promise<Entry>;
/**
* @return An esbuild plugin.
* Transpile entry to standard js.
* @param {Entry} entry
* @param {typeof import('esbuild')} esbuild
* @param {import('esbuild').BuildOptions} [options]
*/
export function start(): import("esbuild").Plugin;
export function transpileEntry(entry: Entry, esbuild: typeof import('esbuild'), options?: import("esbuild").BuildOptions | undefined): Promise<{
code: string;
loader: import("esbuild").Loader | undefined;
map?: undefined;
} | {
code: string;
map: string;
loader: import('esbuild').Loader;
}>;
/**
* @typedef {(args: import('esbuild').OnLoadArgs) => import('esbuild').OnLoadResult} LoadCallback
*/
/**
* @param {import('esbuild').Plugin[]} plugins
* @return An esbuild plugin.
*/
export function end(): import("esbuild").Plugin;
export default function _default(plugins?: import('esbuild').Plugin[]): import("esbuild").Plugin;
/**
* @typedef {Object} SourceMap
* @property {number} version
* @property {string[]} sources
* @property {string[]} names
* @property {string} [sourceRoot]
* @property {string[]} [sourcesContent]
* @property {string} mappings
* @property {string} file
*/
export const SCRIPT_LOADERS: string[];

@@ -51,11 +80,16 @@ export namespace TARGETS {

target: string;
loader?: import("esbuild").Loader | undefined;
loader?: import('esbuild').Loader;
mappings: SourceMap[];
};
export type BuildFactory = (filePath: string, result: {
code: string;
map?: SourceMap | SourceMap[];
loader?: import('esbuild').Loader;
}, extra?: Partial<import("esbuild").OnLoadResult> | undefined) => Promise<import('esbuild').OnLoadResult | undefined>;
export type TransformOptions = {
entry?: Entry | undefined;
filter: RegExp;
store: Map<string, Entry>;
getEntry(filePath: string): Promise<Entry>;
buildEntry(filePath: string, extra?: Partial<import("esbuild").OnLoadResult> | undefined): Promise<import('esbuild').OnLoadResult | undefined>;
finishEntry(filePath: string, extra?: Partial<import("esbuild").OnLoadResult> | undefined): Promise<import('esbuild').OnLoadResult | undefined>;
buildEntry: BuildFactory;
};

@@ -65,1 +99,11 @@ export type BuildTransformOptions = import('esbuild').BuildOptions & {

};
export type LoadCallback = (args: import('esbuild').OnLoadArgs) => import('esbuild').OnLoadResult;
export type SourceMap = {
version: number;
sources: string[];
names: string[];
sourceRoot?: string | undefined;
sourcesContent?: string[] | undefined;
mappings: string;
file: string;
};
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc