Merge branch 'split'
This commit is contained in:
commit
2e05208469
|
@ -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))
|
|
@ -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]'
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
}
|
|
@ -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]',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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)];
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -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))]}`,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
{rollupImport}
|
||||
|
||||
{rollupExport}
|
|
@ -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 {@}" --
|
Loading…
Reference in New Issue