Skip to content

Commit

Permalink
Add CLI support for presets
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Jun 16, 2021
1 parent c193a7b commit d1324f0
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 46 deletions.
54 changes: 40 additions & 14 deletions src/utils/options/mergeOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@ import {
MergedRollupOptions,
OutputOptions,
RollupCache,
TreeshakingPreset,
WarningHandler,
WarningHandlerWithDefault
} from '../../rollup/types';
import { ensureArray } from '../ensureArray';
import { errInvalidOption, error } from '../error';
import { printQuotedStringList } from '../printStringList';
import { CommandConfigObject } from './normalizeInputOptions';
import { defaultOnWarn, GenericConfigObject, warnUnknownOptions } from './options';
import {
defaultOnWarn,
GenericConfigObject,
treeshakePresets,
warnUnknownOptions
} from './options';

export const commandAliases: { [key: string]: string } = {
c: 'config',
Expand Down Expand Up @@ -121,10 +129,7 @@ function mergeInputOptions(
preserveSymlinks: getOption('preserveSymlinks'),
shimMissingExports: getOption('shimMissingExports'),
strictDeprecations: getOption('strictDeprecations'),
// TODO Lukas implement "preset" form
// TODO Lukas command line string usage overrides this option
// TODO Lukas config strings are changed to the "preset" form
treeshake: getObjectOption(config, overrides, 'treeshake'),
treeshake: getObjectOption(config, overrides, 'treeshake', objectifyTreeshakeOption),
watch: getWatch(config, overrides, 'watch')
};

Expand Down Expand Up @@ -160,32 +165,53 @@ const getOnWarn = (
const getObjectOption = (
config: GenericConfigObject,
overrides: GenericConfigObject,
name: string
name: string,
objectifyValue: (value: unknown) => Record<string, unknown> | undefined = value =>
(typeof value === 'object' ? value : {}) as Record<string, unknown> | undefined
) => {
const commandOption = normalizeObjectOptionValue(overrides[name]);
const configOption = normalizeObjectOptionValue(config[name]);
const commandOption = normalizeObjectOptionValue(overrides[name], objectifyValue);
const configOption = normalizeObjectOptionValue(config[name], objectifyValue);
if (commandOption !== undefined) {
return commandOption && { ...configOption, ...commandOption };
}
return configOption;
};

const objectifyTreeshakeOption = (value: unknown): Record<string, unknown> => {
if (typeof value === 'string') {
const preset = treeshakePresets[value as TreeshakingPreset];
if (preset) {
return (preset as unknown) as Record<string, unknown>;
}
error(
errInvalidOption(
'treeshake',
`valid values are false, true, ${printQuotedStringList(
Object.keys(treeshakePresets)
)}. You can also supply an object for more fine-grained control`
)
);
}
return typeof value === 'object' ? (value as Record<string, unknown>) : {};
};

const getWatch = (config: GenericConfigObject, overrides: GenericConfigObject, name: string) =>
config.watch !== false && getObjectOption(config, overrides, name);

export const normalizeObjectOptionValue = (
optionValue: unknown
optionValue: unknown,
objectifyValue: (value: unknown) => Record<string, unknown> | undefined
): Record<string, unknown> | undefined => {
if (!optionValue) {
return optionValue as undefined;
}
if (Array.isArray(optionValue)) {
return optionValue.reduce((result, value) => value && result && { ...result, ...value }, {});
}
if (typeof optionValue !== 'object') {
return {};
return optionValue.reduce(
(result, value) => value && result && { ...result, ...objectifyValue(value) },
{}
);
}
return optionValue as Record<string, unknown>;
return objectifyValue(optionValue);
};

type CompleteOutputOptions<U extends keyof OutputOptions> = {
Expand Down
37 changes: 6 additions & 31 deletions src/utils/options/normalizeInputOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import { errInvalidOption, error, warnDeprecationWithOptions } from '../error';
import { resolve } from '../path';
import { printQuotedStringList } from '../printStringList';
import relativeId from '../relativeId';
import { defaultOnWarn, GenericConfigObject, warnUnknownOptions } from './options';
import {
defaultOnWarn,
GenericConfigObject,
treeshakePresets,
warnUnknownOptions
} from './options';

export interface CommandConfigObject {
[key: string]: unknown;
Expand Down Expand Up @@ -219,36 +224,6 @@ const getPreserveModules = (
return configPreserveModules;
};

type ObjectValue<Base> = Base extends Record<string, any> ? Base : never;

const treeshakePresets: {
[key in NonNullable<
ObjectValue<InputOptions['treeshake']>['preset']
>]: NormalizedInputOptions['treeshake'];
} = {
recommended: {
annotations: true,
moduleSideEffects: () => true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: false
},
safest: {
annotations: true,
moduleSideEffects: () => true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
},
smallest: {
annotations: true,
moduleSideEffects: () => false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false,
unknownGlobalSideEffects: false
}
};

const getTreeshake = (
config: InputOptions,
warn: WarningHandler,
Expand Down
32 changes: 31 additions & 1 deletion src/utils/options/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { WarningHandler } from '../../rollup/types';
import { InputOptions, NormalizedInputOptions, WarningHandler } from '../../rollup/types';

export interface GenericConfigObject {
[key: string]: unknown;
Expand Down Expand Up @@ -28,3 +28,33 @@ export function warnUnknownOptions(
});
}
}

type ObjectValue<Base> = Base extends Record<string, any> ? Base : never;

export const treeshakePresets: {
[key in NonNullable<
ObjectValue<InputOptions['treeshake']>['preset']
>]: NormalizedInputOptions['treeshake'];
} = {
recommended: {
annotations: true,
moduleSideEffects: () => true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: false
},
safest: {
annotations: true,
moduleSideEffects: () => true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
},
smallest: {
annotations: true,
moduleSideEffects: () => false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false,
unknownGlobalSideEffects: false
}
};
5 changes: 5 additions & 0 deletions test/cli/samples/treeshake-preset-override/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
description: 'overrides the treeshake option when using presets',
command:
'rollup --config --treeshake recommended --treeshake.unknownGlobalSideEffects --no-treeshake.moduleSideEffects'
};
13 changes: 13 additions & 0 deletions test/cli/samples/treeshake-preset-override/_expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
console.log('main');

({
get foo() {
console.log('effect');
}
}.foo);

try {
const noeffect = 1;
} catch {}

unknownGlobal;
1 change: 1 addition & 0 deletions test/cli/samples/treeshake-preset-override/dep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('dep');
15 changes: 15 additions & 0 deletions test/cli/samples/treeshake-preset-override/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import './dep.js';

console.log('main');

({
get foo() {
console.log('effect');
}
}.foo);

try {
const noeffect = 1;
} catch {}

unknownGlobal;
10 changes: 10 additions & 0 deletions test/cli/samples/treeshake-preset-override/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default {
input: 'main.js',
treeshake: {
unknownGlobalSideEffects: false,
tryCatchDeoptimization: false
},
output: {
format: 'es'
}
}
13 changes: 13 additions & 0 deletions test/cli/samples/treeshake-unknown-preset/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { assertIncludes } = require('../../../utils.js');

module.exports = {
description: 'overrides the treeshake option when using presets',
command: 'rollup main.js --format es --treeshake unknown',
error: () => true,
stderr: stderr => {
assertIncludes(
stderr,
'[!] Error: Invalid value for option "treeshake" - valid values are false, true, "recommended", "safest" and "smallest". You can also supply an object for more fine-grained control.\n'
);
}
};
1 change: 1 addition & 0 deletions test/cli/samples/treeshake-unknown-preset/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('main');

0 comments on commit d1324f0

Please sign in to comment.