Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(babel): add typings #462

Merged
merged 10 commits into from Jul 7, 2020
17 changes: 13 additions & 4 deletions packages/babel/package.json
Expand Up @@ -25,12 +25,14 @@
"lint:js": "eslint --fix --cache src test",
"lint:package": "prettier --write package.json --plugin=prettier-plugin-package",
"prebuild": "del-cli dist",
"prepublishOnly": "pnpm run lint && pnpm run test && pnpm run build",
"prepublishOnly": "pnpm run lint && pnpm run test && pnpm run build && pnpm run test:ts",
"pretest": "pnpm run build",
"test": "ava"
"test": "ava",
"test:ts": "tsc types/index.d.ts test/types.ts --noEmit"
},
"files": [
"dist",
"types",
"README.md",
"LICENSE"
],
Expand All @@ -44,7 +46,8 @@
],
"peerDependencies": {
"@babel/core": "^7.0.0",
"rollup": "^1.20.0||^2.0.0"
"rollup": "^1.20.0||^2.0.0",
"@types/babel__core": "^7.1.8"
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
},
"dependencies": {
"@babel/helper-module-imports": "^7.7.4",
Expand Down Expand Up @@ -73,5 +76,11 @@
"Bogdan Chadkin <trysound@yandex.ru>",
"Mateusz Burzyński <mateuszburzynski@gmail.com> (https://github.com/Andarist)"
],
"module": "dist/index.es.js"
"module": "dist/index.es.js",
"peerDependenciesMeta": {
"@types/babel__core": {
"optional": true
}
},
"types": "types/index.d.ts"
}
145 changes: 145 additions & 0 deletions packages/babel/test/types.ts
@@ -0,0 +1,145 @@
/** eslint-disable @typescript-eslint/no-unused-vars */

import babel, {
getBabelInputPlugin,
getBabelOutputPlugin,
createBabelInputPluginFactory,
createBabelOutputPluginFactory
} from '../types';

const rollipConfig: import('rollup').RollupOptions = {
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
input: 'main.js',
output: {
file: 'bundle.js',
format: 'iife'
},
plugins: [
babel({
include: 'node_modules/**',
exclude: ['node_modules/foo/**', 'node_modules/bar/**', /node_modules/],
extensions: ['.js', '.coffee'],
babelHelpers: 'runtime',
skipPreflightCheck: true,
babelrc: false,
plugins: []
}),
getBabelInputPlugin({
include: 'node_modules/**',
exclude: ['node_modules/foo/**', 'node_modules/bar/**', /node_modules/],
extensions: ['.js', '.coffee'],
babelHelpers: 'runtime',
skipPreflightCheck: true,
babelrc: false,
plugins: []
}),
getBabelOutputPlugin({
include: 'node_modules/**',
exclude: ['node_modules/foo/**', 'node_modules/bar/**', /node_modules/],
extensions: ['.js', '.coffee'],
runtimeHelpers: true,
externalHelpers: true,
externalHelpersWhitelist: ['example'],
allowAllFormats: true,
babelrc: false,
plugins: []
})
]
};

export default rollipConfig;

createBabelInputPluginFactory((babelCore) => {
function myPlugin() {
return {
name: `input-${babelCore.version}`,
visitor: {}
};
}

return {
// Passed the plugin options.
options({ opt1, opt2, ...pluginOptions }) {
return {
// Pull out any custom options that the plugin might have.
customOptions: { opt1, opt2 },

// Pass the options back with the two custom options removed.
pluginOptions
};
},

// eslint-disable-next-line @typescript-eslint/no-unused-vars
config(cfg, { code, customOptions }) {
if (cfg.hasFilesystemConfig()) {
// Use the normal config
return cfg.options;
}

return {
...cfg.options,
plugins: [
...(cfg.options.plugins || []),

// Include a custom plugin in the options.
myPlugin
]
};
},

// eslint-disable-next-line @typescript-eslint/no-unused-vars
result(result, { code, customOptions, config, transformOptions }) {
return {
...result,
code: `${result.code}\n// Generated by some custom plugin`
};
}
};
});

createBabelOutputPluginFactory((babelCore) => {
function myPlugin() {
return {
name: `output-${babelCore.version}`,
visitor: {}
};
}

return {
// Passed the plugin options.
options({ opt1, opt2, ...pluginOptions }) {
return {
// Pull out any custom options that the plugin might have.
customOptions: { opt1, opt2 },

// Pass the options back with the two custom options removed.
pluginOptions
};
},

// eslint-disable-next-line @typescript-eslint/no-unused-vars
config(cfg, { code, customOptions }) {
if (cfg.hasFilesystemConfig()) {
// Use the normal config
return cfg.options;
}

return {
...cfg.options,
plugins: [
...(cfg.options.plugins || []),

// Include a custom plugin in the options.
myPlugin
]
};
},

// eslint-disable-next-line @typescript-eslint/no-unused-vars
result(result, { code, customOptions, config, transformOptions }) {
return {
...result,
code: `${result.code}\n// Generated by some custom plugin`
};
}
};
});
130 changes: 130 additions & 0 deletions packages/babel/types/index.d.ts
@@ -0,0 +1,130 @@
import { Plugin } from 'rollup';
import { FilterPattern } from '@rollup/pluginutils';
import * as babelCore from '@babel/core';

interface RollupBabelInputPluginOptions
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
extends Omit<babelCore.TransformOptions, 'include' | 'exclude'> {
/**
* A minimatch pattern, or array of patterns, which specifies the files in the build the plugin should operate on. When relying on Babel configuration files you cannot include files already excluded there.
* @default undefined;
*/
include?: FilterPattern;
/**
* A minimatch pattern, or array of patterns, which specifies the files in the build the plugin should ignore. When relaying on Babel configuration files you can only exclude additional files with this option, you cannot override what you have configured for Babel itself.
* @default undefined;
*/
exclude?: FilterPattern;
/**
* An array of file extensions that Babel should transpile. If you want to transpile TypeScript files with this plugin it's essential to include .ts and .tsx in this option.
* @default ['.js', '.jsx', '.es6', '.es', '.mjs']
*/
extensions?: string[];
/**
* It is recommended to configure this option explicitly (even if with its default value) so an informed decision is taken on how those babel helpers are inserted into the code.
* @default 'bundled'
*/
babelHelpers?: 'bundled' | 'runtime' | 'inline' | 'extends';
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
/**
* Before transpiling your input files this plugin also transpile a short piece of code for each input file. This is used to validate some misconfiguration errors, but for sufficiently big projects it can slow your build times so if you are confident about your configuration then you might disable those checks with this option.
* @default false
*/
skipPreflightCheck?: boolean;
}

interface RollupBabelOutputPluginOptions
extends Omit<babelCore.TransformOptions, 'include' | 'exclude'> {
/**
* A minimatch pattern, or array of patterns, which specifies the files in the build the plugin should operate on. When relying on Babel configuration files you cannot include files already excluded there.
* @default undefined;
*/
include?: FilterPattern;
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
/**
* A minimatch pattern, or array of patterns, which specifies the files in the build the plugin should ignore. When relaying on Babel configuration files you can only exclude additional files with this option, you cannot override what you have configured for Babel itself.
* @default undefined;
*/
exclude?: FilterPattern;
/**
* An array of file extensions that Babel should transpile. If you want to transpile TypeScript files with this plugin it's essential to include .ts and .tsx in this option.
* @default ['.js', '.jsx', '.es6', '.es', '.mjs']
*/
extensions?: string[];
/**
* A boolean value indicating whether to bundle in the Babel helpers.
* @default false
*/
externalHelpers?: boolean;
/**
* An array which gives explicit control over which babelHelper functions are allowed in the bundle.
* @default undefined
*/
externalHelpersWhitelist?: string[];
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
/**
* @default false
*/
runtimeHelpers?: boolean;
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved
/**
* Use with other formats than UMD/IIFE.
* @default false
*/
allowAllFormats?: boolean;
}

type CustomInputPluginOptions = (
options: RollupBabelInputPluginOptions & Record<string, any>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS is not my strongest suit so take my comment with a grain of salt - maybe instead of accepting & Record<string, any> here this should be parametrized with a generic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think the customOptions should be a 1-1 mapping, as that would limit the custom plugin, so they could not remove or add options. I think this way the user could build stronger on top if necassary.

) => {
customOptions: Record<string, any>;
pluginOptions: RollupBabelInputPluginOptions;
};
type CustomOutputPluginOptions = (
options: RollupBabelOutputPluginOptions & Record<string, any>
) => {
customOptions: Record<string, any>;
pluginOptions: RollupBabelOutputPluginOptions;
};
type CustomPluginConfig = (
cfg: babelCore.PartialConfig,
options: { code: string; customOptions: Record<string, any> }
) => babelCore.TransformOptions;
type CustomPluginResult = (
result: babelCore.BabelFileResult,
options: {
code: string;
customOptions: Record<string, any>;
config: babelCore.PartialConfig;
transformOptions: babelCore.TransformOptions;
}
) => babelCore.BabelFileResult;
interface CustomInputPlugin {
options?: CustomInputPluginOptions;
config?: CustomPluginConfig;
result?: CustomPluginResult;
}
interface CustomOutputPlugin {
options?: CustomOutputPluginOptions;
config?: CustomPluginConfig;
result?: CustomPluginResult;
}
type CustomInputPluginBuilder = (babel: typeof babelCore) => CustomInputPlugin;
type CustomOutputPluginBuilder = (babel: typeof babelCore) => CustomOutputPlugin;

/**
* A Rollup plugin for seamless integration between Rollup and Babel.
* @param options - Plugin options.
* @returns Plugin instance.
*/
export function getBabelInputPlugin(options?: RollupBabelInputPluginOptions): Plugin;
export function getBabelOutputPlugin(options?: RollupBabelOutputPluginOptions): Plugin;

export function createBabelInputPluginFactory(
customCallback?: CustomInputPluginBuilder
): typeof getBabelInputPlugin;
export function createBabelOutputPluginFactory(
customCallback?: CustomOutputPluginBuilder
): typeof getBabelOutputPlugin;

/**
* A Rollup plugin for seamless integration between Rollup and Babel.
* @param options - Plugin options.
* @returns Plugin instance.
*/
export default function babel(options?: RollupBabelInputPluginOptions): Plugin;
AndrewLeedham marked this conversation as resolved.
Show resolved Hide resolved