Merge branch 'split'

This commit is contained in:
Derrick Hammer 2023-06-30 00:33:28 -04:00
commit 2e05208469
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
11 changed files with 1046 additions and 0 deletions

165
CHANGELOG.md Normal file
View File

@ -0,0 +1,165 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [4.0.1](https://github.com/alvis/presetter/compare/v4.0.0...v4.0.1) (2023-06-21)
# [4.0.0](https://github.com/alvis/presetter/compare/v3.5.5...v4.0.0) (2023-06-18)
### ✨ Features
* convert the whole project into ESM ([381c84f](https://github.com/alvis/presetter/commit/381c84f59605faf9ce6c2b3f81c2eea81bfebc61))
* **types:** separate types from presetter ([4ff3626](https://github.com/alvis/presetter/commit/4ff3626d915649208067b2235645e8534508f341))
### 🐛 Bug Fixes
* **preset-rollup:** inject NODE_ENV for build and develop stages ([b09ade5](https://github.com/alvis/presetter/commit/b09ade516250b8b5256d7f3d52ab1a30102607b5))
* **preset-rollup:** make the rollup preset compatible with ESM ([86154b8](https://github.com/alvis/presetter/commit/86154b8daaf7e3f97c1a93753416263fe7b086dc))
* update outdated packages ([bbaf33f](https://github.com/alvis/presetter/commit/bbaf33f0eaeaeca2c296cfc68207b4ff4632674f))
### 📦 Code Refactoring
* **preset-rollup:** normalize config in functional way ([f6b3815](https://github.com/alvis/presetter/commit/f6b3815a13309791852ba2442e0a48e6531f8d45))
### ♻️ Chores
* allow tests can be done individually ([b86f6ee](https://github.com/alvis/presetter/commit/b86f6eef689f7783a2a19841eaadf6e581dbb649))
* use pnpm for workspace management ([358d0d7](https://github.com/alvis/presetter/commit/358d0d77cdc2b37affb36931f13568464f1a46ab))
### 💎 Styles
* make any node build-in modules explicitly imported first ([90730f2](https://github.com/alvis/presetter/commit/90730f2dfd27a6a6f1fbceb26ac5fb974e11508e))
### Breaking changes
* - by default, client project emit ESM and for clarity preset-essentials has been renamed to preset-esm
- ts-node is removed in favor of a more powerful and less buggy tsx
## [3.5.5](https://github.com/alvis/presetter/compare/v3.5.4...v3.5.5) (2023-03-31)
## [3.5.4](https://github.com/alvis/presetter/compare/v3.5.3...v3.5.4) (2023-03-30)
## [3.5.3](https://github.com/alvis/presetter/compare/v3.5.2...v3.5.3) (2023-03-26)
## [3.5.2](https://github.com/alvis/presetter/compare/v3.5.1...v3.5.2) (2023-03-26)
## [3.5.1](https://github.com/alvis/presetter/compare/v3.5.0...v3.5.1) (2023-03-18)
# [3.5.0](https://github.com/alvis/presetter/compare/v3.4.1...v3.5.0) (2022-09-23)
### 🛠 Builds
* move .presetterrc to the root ([0eb17a0](https://github.com/alvis/presetter/commit/0eb17a058fa245faae96dcb017184460dae08b46))
### 📦 Code Refactoring
* **presetter:** remove dependency on fs-extra ([8810c56](https://github.com/alvis/presetter/commit/8810c568d1cf1de275b055916b6aeac450b43403))
* **rollup:** remove unnecessary async waits ([9d9c4c3](https://github.com/alvis/presetter/commit/9d9c4c3b5131548512574634414214380cb501f2))
## [3.4.1](https://github.com/alvis/presetter/compare/v3.4.0...v3.4.1) (2022-08-10)
### 🐛 Bug Fixes
* **presetter:** merge arrays only if the values are all primitive ([961f30c](https://github.com/alvis/presetter/commit/961f30c8fcbf9ba6f6fbf9e4d90cf0cb8c5a1069))
* update packages ([ec8307d](https://github.com/alvis/presetter/commit/ec8307d79468f8529b29a0f7b356b4368c03302c))
# [3.4.0](https://github.com/alvis/presetter/compare/v3.3.0...v3.4.0) (2022-08-02)
### 🐛 Bug Fixes
* **presetter:** resolve presets as a tree not a list ([0db5ff3](https://github.com/alvis/presetter/commit/0db5ff3b0020735591b3986c216578857dde3039))
# [3.3.0](https://github.com/alvis/presetter/compare/v3.2.0...v3.3.0) (2022-07-12)
### 📚 Documentation
* update dependencies badges ([94c084d](https://github.com/alvis/presetter/commit/94c084ddc39821106c9077bd4c12d1a7da9529eb))
# [3.2.0](https://github.com/alvis/presetter/compare/v3.1.1...v3.2.0) (2022-05-18)
### 📦 Code Refactoring
* use American English ([17315b7](https://github.com/alvis/presetter/commit/17315b78a9d65fb6193a609dd27b4d34454df1bc))
### ♻️ Chores
* update package dependencies ([4e50e0d](https://github.com/alvis/presetter/commit/4e50e0d2fce1bea470fbea62fc1eba52dccb3aed))
## [3.1.1](https://github.com/alvis/presetter/compare/v3.1.0...v3.1.1) (2021-12-29)
# [3.1.0](https://github.com/alvis/presetter/compare/v3.0.3...v3.1.0) (2021-12-28)
## [3.0.3](https://github.com/alvis/presetter/compare/v3.0.2...v3.0.3) (2021-11-03)
## [3.0.2](https://github.com/alvis/presetter/compare/v3.0.1...v3.0.2) (2021-11-03)
## [3.0.1](https://github.com/alvis/presetter/compare/v3.0.0...v3.0.1) (2021-10-14)
# [3.0.0](https://github.com/alvis/presetter/compare/v2.1.0...v3.0.0) (2021-10-04)
### ✨ Features
* **preset-rollup:** provide a preset for code bundling via rollup ([b0704b0](https://github.com/alvis/presetter/commit/b0704b0fe727c2724d7057d3803ecee49c230eff))
### 🐛 Bug Fixes
* **presetter:** narrow types in directive's argument ([c6de804](https://github.com/alvis/presetter/commit/c6de8044d4d9f584e3ef4ef688f81c08db425d1c))
### 🛠 Builds
* use presetter-preset-strict wherever possible ([4ff72a1](https://github.com/alvis/presetter/commit/4ff72a1a9730dfd4ad99d0a63dd4b005041ce759))
### 📦 Code Refactoring
* rename presetter-preset to presetter-preset-essentials ([b799587](https://github.com/alvis/presetter/commit/b7995871d85a1ccb8d2e43ba9b3a7e305de7a99b))

26
configs/rollup.yaml Normal file
View File

@ -0,0 +1,26 @@
input: '{source}/index.ts'
output:
- file: '{output}/index.js'
format: cjs
sourcemap: true
- file: '{output}/index.mjs'
format: es
sourcemap: true
plugins:
- '@apply rollup-plugin-ts[default]'
- '@apply rollup-plugin-tsconfig-paths[default]'
- '@apply @rollup/plugin-node-resolve[default]'
- - '@apply @rollup/plugin-commonjs[default]'
- extensions:
- .js
- .jsx
- .ts
- .tsx
- '@apply @rollup/plugin-json[default]'
- '@apply @rollup/plugin-graphql[default]'
- '@apply @rollup/plugin-image[default]'
- '@apply @rollup/plugin-yaml[default]'
- - '@apply rollup-plugin-postcss[default]'
- inject:
insertAt: top
- '@apply rollup-plugin-visualizer[visualizer]'

55
package.json Normal file
View File

@ -0,0 +1,55 @@
{
"name": "presetter-preset-rollup",
"version": "4.0.1",
"description": "An opinionated presetter preset for using rollup as a bundler",
"keywords": [
"presetter",
"preset"
],
"homepage": "https://github.com/alvis/presetter#readme",
"bugs": {
"url": "https://github.com/alvis/presetter/issues"
},
"license": "MIT",
"author": {
"name": "Alvis HT Tang",
"email": "alvis@hilbert.space"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/alvis/presetter.git"
},
"scripts": {
"bootstrap": "presetter bootstrap && run prepare",
"build": "run build",
"coverage": "run coverage --",
"lint": "run lint --",
"prepublishOnly": "run prepare && run prepublishOnly",
"test": "run test --",
"watch": "run watch --"
},
"peerDependencies": {
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-graphql": "^2.0.0",
"@rollup/plugin-image": "^3.0.0",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-yaml": "^4.0.0",
"presetter": "workspace:*",
"rollup": "^3.0.0",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-ts": "^3.0.0",
"rollup-plugin-tsconfig-paths": "^1.0.0",
"rollup-plugin-visualizer": "^5.0.0"
},
"devDependencies": {
"presetter": "workspace:*"
},
"dependencies": {
"presetter-types": "workspace:*",
"type-fest": "^3.12.0"
}
}

78
source/index.ts Normal file
View File

@ -0,0 +1,78 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Collection of preset assets for bundling a project with rollup
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2021 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadFile, template } from 'presetter';
import { getRollupParameter } from './rollup';
import type { PresetAsset } from 'presetter-types';
import type { RollupConfig } from './rollup';
const DIR = fileURLToPath(dirname(import.meta.url));
// paths to the template directory
const TEMPLATES = resolve(DIR, '..', 'templates');
const CONFIGS = resolve(DIR, '..', 'configs');
/** config for this preset */
export type PresetConfig = {
rollup?: RollupConfig;
};
/** List of configurable variables */
export type Variable = {
/** the directory containing all source code (default: source) */
source: string;
/** the directory containing all the compiled files (default: lib) */
output: string;
};
export const DEFAULT_VARIABLE: Variable = {
source: 'source',
output: 'lib',
};
/**
* get the list of templates provided by this preset
* @returns list of preset templates
*/
export default function (): PresetAsset {
return {
template: {
/* eslint-disable @typescript-eslint/naming-convention */
'rollup.config.ts': (context) => {
const content = loadFile(
resolve(TEMPLATES, 'rollup.config.ts'),
'text',
);
const variable = getRollupParameter(context);
return template(content, variable);
/* eslint-enable @typescript-eslint/naming-convention */
},
},
scripts: resolve(TEMPLATES, 'scripts.yaml'),
noSymlinks: ['rollup.config.ts'],
supplementaryConfig: {
gitignore: ['/rollup.config.ts'],
rollup: resolve(CONFIGS, 'rollup.yaml'),
},
variable: DEFAULT_VARIABLE,
};
}

115
source/plugin.ts Normal file
View File

@ -0,0 +1,115 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Collection of plugin related helpers
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2021 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import { isDirective } from 'presetter';
import type { ApplyDirective, ImportDirective } from 'presetter';
import type { JsonObject } from 'type-fest';
/** full configuration about a plugin */
export type PluginConfiguration =
| [name: PluginHeader]
| [name: PluginHeader, options: PluginOptions | null];
/** specification of a plugin name and its handling direction (e.g. by invoking the function or just simply specify the name) */
export type PluginHeader = string | ApplyDirective;
/** options for a plugin */
export type PluginOptions = JsonObject | ApplyDirective | ImportDirective;
/** plugin configuration as an object */
export type PluginObject = Record<PluginHeader, PluginOptions | null>;
/** plugin configuration as an array */
export type PluginList = PluginListItem[];
/** possible types for individual item in a PluginList */
type PluginListItem = PluginHeader | [name: PluginHeader] | PluginConfiguration;
/** all possible configuration form for a collection of plugins */
export type PluginManifest = PluginList | PluginObject;
/**
* ensure that the given value is a valid PluginManifest
* @param value value to be tested
* @returns nothing if it's a pass
*/
export function assertPluginManifest(
value: unknown,
): asserts value is PluginManifest {
if (typeof value === 'object') {
if (Array.isArray(value)) {
return assertPluginList(value);
} else if (value !== null) {
return assertPluginObject(value as Record<string, unknown>);
}
}
throw new TypeError('plugin manifest is not in a supported format');
}
/**
* ensure that the given value is a valid PluginObject
* @param value value to be tested
*/
export function assertPluginObject(
value: Record<string, unknown>,
): asserts value is PluginObject {
// all values must be an object
if (
[...Object.values(value)].some(
(opt) => typeof opt !== 'object' && !isDirective(opt),
)
) {
throw new TypeError('all plugin options must be a object');
}
}
/**
* ensure that the given value is a valid PluginList
* @param value value to be tested
*/
export function assertPluginList(
value: unknown[],
): asserts value is PluginList {
for (const plugin of value) {
assertPluginListItem(plugin);
}
}
const PLUGIN_LIST_MAX_ITEMS = 2;
/**
* ensure that the given value is a valid PluginListItem
* @param value value to be tested
*/
export function assertPluginListItem(
value: unknown,
): asserts value is PluginListItem {
if (
typeof value !== 'string' &&
!(
Array.isArray(value) &&
value.length <= PLUGIN_LIST_MAX_ITEMS &&
typeof value[0] === 'string' &&
(isDirective(value[1]) ||
['undefined', 'object'].includes(typeof value[1]))
)
) {
throw new TypeError(
'a plugin manifest in an array form must be in either one of the following forms: string, [string], [string, object]',
);
}
}

216
source/rollup.ts Normal file
View File

@ -0,0 +1,216 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Collection of helpers for rollup
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2021 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import {
isDirective,
isJSON,
merge,
resolveDirective,
template,
} from 'presetter';
import { assertPluginManifest } from './plugin';
import type { ApplyDirective, ImportDirective } from 'presetter';
import type { ResolvedPresetContext } from 'presetter-types';
import type {
PluginConfiguration,
PluginList,
PluginManifest,
PluginObject,
} from './plugin';
/** preset configuration for rollup */
export interface RollupConfig {
[index: string]: unknown | RollupConfig;
/** list of plugin and its options */
plugins?: PluginManifest | ApplyDirective | ImportDirective;
}
/** genuine configuration that rollup would take, making sure all plugins are a list */
interface TrueRollupConfig {
[index: string]: unknown | TrueRollupConfig;
/** list of plugin and its options */
plugins?: PluginConfiguration[];
}
/** transformed configuration for rollup, with all plugins represented by an object */
interface IntermediateRollupConfig {
[index: string]: unknown | IntermediateRollupConfig;
/** list of plugin and its options */
plugins?: PluginObject;
}
/**
* get template parameters for rollup
* @param context context about the build environment
* @returns template parameter related to rollup
*/
export function getRollupParameter(
context: ResolvedPresetContext,
): Record<'rollupImport' | 'rollupExport', string> {
const { config, variable } = context.custom;
const normalizedConfig = template(
normalizeConfig(transformConfig({ ...config.rollup })),
variable,
);
return generateRollupParameter(normalizedConfig, context);
}
/**
* generate template parameters for rollup
* @param config normalized rollup config
* @param context context about the build environment
* @returns template parameter related to rollup
*/
function generateRollupParameter(
config: TrueRollupConfig,
context: ResolvedPresetContext,
): Record<'rollupImport' | 'rollupExport', string> {
const { importMap, stringifiedConfig } = resolveDirective(config, context);
// generate import statements
const rollupImport = Object.entries(importMap)
.map(([name, resolved]) => `import * as ${resolved} from '${name}';`)
.join('\n');
// generate export statements
const rollupExport = `export default ${stringifiedConfig}`;
return { rollupImport, rollupExport };
}
/**
* normalize rollup config with all plugins represented as a list
* @param config transformed config
* @returns config that rollup would take
*/
function normalizeConfig(config: IntermediateRollupConfig): TrueRollupConfig {
return Object.fromEntries(
Object.entries(config).map(([key, value]): [string, unknown] => {
return [
key,
isDirective(value) ? value : normalizeConfigValue(key, value),
];
}),
);
}
/**
* try to normalize any nested configuration
* @param key field name
* @param value value of a field
* @returns normalized value
*/
function normalizeConfigValue(key: string, value: unknown): unknown {
switch (key) {
case 'plugins':
return [
...Object.entries(value as PluginObject)
.filter(([_, options]) => options !== null)
.map(([plugin, options]) =>
[plugin, normalizeConfigValue(plugin, options)].filter(
(element) => element !== undefined,
),
),
];
default:
return isJSON(value)
? normalizeConfig(value as IntermediateRollupConfig)
: value;
}
}
/**
* transform rollup config with plugins represented by an object for better merging
* @param config rollup config in .presetterrc
* @returns transformed config
*/
function transformConfig(
config: Record<string, any>,
): IntermediateRollupConfig {
return Object.fromEntries(
Object.entries(config).map(([key, value]): [string, unknown] => {
return [
key,
isDirective(value) ? value : transformConfigValue(key, value),
];
}),
);
}
/**
* try to transform any nested configuration
* @param key field name
* @param value value of a field
* @returns transformed value
*/
function transformConfigValue(key: string, value: unknown): unknown {
switch (key) {
case 'plugins':
assertPluginManifest(value);
return objectifyPlugins(value);
default:
return isJSON(value) ? transformConfig(value) : value;
}
}
/**
* objectify rollup plugins
* @param plugins rollup plugin config
* @returns normalized plugin config
*/
function objectifyPlugins(
plugins: PluginManifest,
): IntermediateRollupConfig['plugins'] {
const pluginList: PluginConfiguration[] = Array.isArray(plugins)
? arrayToPluginConfiguration(plugins)
: objectToPluginConfiguration(plugins);
return pluginList.reduce(
(normalizedPlugin, [name, options]) =>
merge(normalizedPlugin, { [name]: options }),
{},
);
}
/**
* normalize rollup plugin config in array form
* @param plugins rollup plugin config in array form
* @returns normalized plugin config
*/
function arrayToPluginConfiguration(
plugins: PluginList,
): PluginConfiguration[] {
return plugins.map((plugin) =>
typeof plugin === 'string' ? [plugin] : plugin,
);
}
/**
* normalize rollup plugin config in object form
* @param plugins rollup plugin config in object form
* @returns normalized plugin config
*/
function objectToPluginConfiguration(
plugins: PluginObject,
): PluginConfiguration[] {
return [...Object.entries(plugins)];
}

62
spec/index.spec.ts Normal file
View File

@ -0,0 +1,62 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Tests on config generation
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2020 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import { existsSync, readdirSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import * as pathNode from 'node:path';
import { fileURLToPath } from 'node:url';
import { jest } from '@jest/globals';
const __dir = fileURLToPath(dirname(import.meta.url));
jest.unstable_mockModule('node:path', () => ({
...pathNode,
// spy on resolve to check if a template is referenced
resolve: jest.fn(resolve),
}));
const { resolve: resolveSpyed } = await import('node:path');
const { loadDynamicMap, resolveContext } = await import('presetter');
const { default: getPresetAsset } = await import('#index');
describe('fn:getPresetAsset', () => {
it('use all templates', async () => {
const asset = await getPresetAsset();
const context = await resolveContext({
graph: [{ name: 'preset', asset, nodes: [] }],
context: {
target: { name: 'preset', root: '/', package: {} },
custom: { preset: 'preset' },
},
});
// load all potential dynamic content
await loadDynamicMap(asset.supplementaryConfig, context);
await loadDynamicMap(asset.template, context);
const CONFIGS = resolve(__dir, '..', 'configs');
const configs = (existsSync(CONFIGS) && readdirSync(CONFIGS)) || [];
const TEMPLATES = resolve(__dir, '..', 'templates');
const templates = (existsSync(TEMPLATES) && readdirSync(TEMPLATES)) || [];
for (const path of configs) {
expect(resolveSpyed).toBeCalledWith(CONFIGS, path);
}
for (const path of templates) {
expect(resolveSpyed).toBeCalledWith(TEMPLATES, path);
}
});
});

101
spec/plugin.spec.ts Normal file
View File

@ -0,0 +1,101 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Tests on plugin related helpers
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2021 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import {
assertPluginList,
assertPluginListItem,
assertPluginObject,
assertPluginManifest,
} from '#plugin';
describe('fn:assertPluginListItem', () => {
it('pass with just a string', () => {
expect(() => assertPluginListItem('plugin')).not.toThrow();
});
it('pass with a string in an array', () => {
expect(() => assertPluginListItem(['plugin'])).not.toThrow();
});
it('pass with a string and its options in an array', () => {
expect(() =>
assertPluginListItem(['plugin', { options: true }]),
).not.toThrow();
});
it('fails with a non-string header', () => {
expect(() => assertPluginListItem([0])).toThrow(TypeError);
});
it('fails with an array more than 2 items', () => {
expect(() =>
assertPluginListItem(['plugin', { options: true }, 'extra']),
).toThrow(TypeError);
});
});
describe('fn:assertPluginList', () => {
it('pass with a valid plugin configuration list', () => {
expect(() =>
assertPluginList(['plugin', ['plugin'], ['plugin', { options: true }]]),
).not.toThrow();
});
it('fail with any invalid plugin configurations', () => {
expect(() =>
assertPluginList([
'plugin',
['plugin'],
['plugin', { options: true }],
{ invalid: true },
]),
).toThrow(TypeError);
});
});
describe('fn:assertPluginObject', () => {
it('pass with a valid plugin configuration object', () => {
expect(() =>
assertPluginObject({ plugin: { options: true } }),
).not.toThrow();
});
it('fail with any invalid plugin options', () => {
expect(() => assertPluginObject({ plugin: true })).toThrow(TypeError);
});
});
describe('fn:assertPluginManifest', () => {
it('pass with a valid plugin configuration object', () => {
expect(() =>
assertPluginManifest({ plugin: { options: true } }),
).not.toThrow();
});
it('pass with a valid plugin configuration list', () => {
expect(() =>
assertPluginManifest([
'plugin',
['plugin'],
['plugin', { options: true }],
]),
).not.toThrow();
});
it('fail with any invalid manifest', () => {
expect(() => assertPluginManifest(null)).toThrow(TypeError);
expect(() => assertPluginManifest('invalid')).toThrow(TypeError);
});
});

220
spec/rollup.spec.ts Normal file
View File

@ -0,0 +1,220 @@
/*
* *** MIT LICENSE ***
* -------------------------------------------------------------------------
* This code may be modified and distributed under the MIT license.
* See the LICENSE file for details.
* -------------------------------------------------------------------------
*
* @summary Tests on the helpers for rollup
*
* @author Alvis HT Tang <alvis@hilbert.space>
* @license MIT
* @copyright Copyright (c) 2021 - All Rights Reserved.
* -------------------------------------------------------------------------
*/
import { getRollupParameter } from '#rollup';
import type { Config, ResolvedPresetContext } from 'presetter-types';
describe('fn:getRollupParameter', () => {
const generateContext = (config?: Config): ResolvedPresetContext => ({
target: { name: 'target', root: '/path/to/target', package: {} },
custom: {
preset: 'preset',
config: config ? { rollup: config } : {},
noSymlinks: [],
variable: {},
},
});
it('add plugins by importing from another config files', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: '@import config[plugins]',
}),
),
).toEqual({
rollupImport: `import * as import0 from 'config';`,
rollupExport: 'export default {"plugins": import0.plugins}',
});
});
it('add a plugin by adding the plugin in the object form, using the supplied options', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: { '@apply newPlugin': { name: 'newPlugin' } },
}),
),
).toEqual({
rollupImport: `import * as import0 from 'newPlugin';`,
rollupExport:
'export default {"plugins": [import0(...([{"name": "newPlugin"}] as const))]}',
});
});
it('add a plugin by just the plugin name, using everything default', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: ['@apply newPlugin'],
}),
),
).toEqual({
rollupImport: `import * as import0 from 'newPlugin';`,
rollupExport: 'export default {"plugins": [import0(...([] as const))]}',
});
});
it('add a plugin by adding the plugin in the array form, using everything default', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: [['@apply newPlugin']],
}),
),
).toEqual({
rollupImport: `import * as import0 from 'newPlugin';`,
rollupExport: 'export default {"plugins": [import0(...([] as const))]}',
});
});
it('add a plugin by adding the plugin in the array form, using the supplied options', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: [['@apply newPlugin', { name: 'newPlugin' }]],
}),
),
).toEqual({
rollupImport: `import * as import0 from 'newPlugin';`,
rollupExport:
'export default {"plugins": [import0(...([{"name": "newPlugin"}] as const))]}',
});
});
it('remove a plugin by setting the plugin config as null', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: {
'@apply pluginWithOptions': null,
},
}),
),
).toEqual({
rollupImport: ``,
rollupExport: 'export default {"plugins": []}',
});
});
it('add a plugin from a named import', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: {
'@apply pluginWithOptions': null,
'@apply pluginWithoutOptions': null,
'@apply newPlugin[plugin]': { options: true },
},
}),
),
).toEqual({
rollupImport: `import * as import0 from 'newPlugin';`,
rollupExport:
'export default {"plugins": [import0.plugin(...([{"options": true}] as const))]}',
});
});
it('generate default parameters if no further config is given', async () => {
expect(await getRollupParameter(generateContext())).toEqual({
rollupImport: ``,
rollupExport: 'export default {}',
});
});
it('generate config with extra options other than plugins', async () => {
expect(
await getRollupParameter(
generateContext({
cache: null,
extra: { options: true },
external: ['import1', 'import2'],
}),
),
).toEqual({
rollupImport: ``,
rollupExport:
'export default {"cache": null, "extra": {"options": true}, "external": ["import1", "import2"]}',
});
});
it('generate extra import statements for imports within plugin options', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: {
'@apply pluginWithOptions': '@import another',
'@apply pluginWithoutOptions': '@import another',
},
}),
),
).toEqual({
rollupImport: `import * as import0 from 'another';\nimport * as import1 from 'pluginWithOptions';\nimport * as import2 from 'pluginWithoutOptions';`,
rollupExport: `export default {"plugins": [import1(...([import0] as const)), import2(...([import0] as const))]}`,
});
expect(
await getRollupParameter(
generateContext({
plugins: [
['@apply pluginWithOptions', '@import another'],
['@apply pluginWithoutOptions', '@import another'],
],
}),
),
).toEqual({
rollupImport: `import * as import0 from 'another';\nimport * as import1 from 'pluginWithOptions';\nimport * as import2 from 'pluginWithoutOptions';`,
rollupExport: `export default {"plugins": [import1(...([import0] as const)), import2(...([import0] as const))]}`,
});
});
it('generate only one import statement per unique import', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: {
'@apply pluginWithOptions': null,
'@apply pluginWithoutOptions': null,
'@apply plugin0': '@import another[export0]',
'@apply plugin1': '@import another[export1]',
},
}),
),
).toEqual({
rollupImport: `import * as import0 from 'another';\nimport * as import1 from 'plugin0';\nimport * as import2 from 'plugin1';`,
rollupExport: `export default {"plugins": [import1(...([import0.export0] as const)), import2(...([import0.export1] as const))]}`,
});
});
it('support nested plugin declaration', async () => {
expect(
await getRollupParameter(
generateContext({
plugins: {
'@apply pluginWithOptions': null,
'@apply pluginWithoutOptions': null,
'@apply plugin0': {
plugins: { another: '@import options[export0]' },
},
},
}),
),
).toEqual({
rollupImport: `import * as import0 from 'options';\nimport * as import1 from 'plugin0';`,
rollupExport: `export default {"plugins": [import1(...([{"plugins": [["another", import0.export0]]}] as const))]}`,
});
});
});

View File

@ -0,0 +1,3 @@
{rollupImport}
{rollupExport}

5
templates/scripts.yaml Normal file
View File

@ -0,0 +1,5 @@
# replace the `prepare` template from presetter-preset
# so that the build procedure will not be triggered upon package installation
build: cross-env NODE_ENV=production run-s clean build:rollup
build:rollup: rollup --config rollup.config.ts --configPlugin rollup-plugin-ts
develop: cross-env NODE_ENV=development run-s "build:rollup -- --watch {@}" --