Skip to content

Commit

Permalink
feat(babel): overrideContext option (#1342)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anber authored Sep 23, 2023
1 parent b8eaf3e commit 144995f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-moles-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@linaria/babel-preset': patch
---

The new option, 'overrideContext,' allows the extension of the module evaluation context.
14 changes: 14 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ module.exports = {
- `unit` - the unit.
- `valueSlug` - the value slug.
- `overrideContext: (context: Partial<vm.Context>, filename: string) => Partial<vm.Context>`
A custom function to override the context used to evaluate modules. This can be used to add custom globals or override the default ones.
```js
module.exports = {
overrideContext: (context, filename) => ({
...context,
HighLevelAPI: () => "I'm a high level API",
}),
};
```
- `rules: EvalRule[]`
The set of rules that defines how the matched files will be transformed during the evaluation.
Expand Down
7 changes: 4 additions & 3 deletions packages/babel/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class Module {
evaluatedCreated = true;
}

const source = entrypoint.transformedCode;
const { transformedCode: source, pluginOptions } = entrypoint;

if (!source) {
this.debug(`evaluate`, 'there is nothing to evaluate');
Expand All @@ -277,14 +277,15 @@ class Module {

const { context, teardown } = createVmContext(
filename,
entrypoint.pluginOptions.features,
pluginOptions.features,
{
module: this,
exports: entrypoint.exports,
require: this.require,
__linaria_dynamic_import: async (id: string) => this.require(id),
__dirname: path.dirname(filename),
}
},
pluginOptions.overrideContext
);

try {
Expand Down
19 changes: 13 additions & 6 deletions packages/babel/src/vm/createVmContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as vm from 'vm';

import type { Window } from 'happy-dom';

import type { FeatureFlags } from '@linaria/utils';
import type { FeatureFlags, StrictOptions } from '@linaria/utils';
import { isFeatureEnabled } from '@linaria/utils';

import * as process from './process';
Expand Down Expand Up @@ -72,17 +72,24 @@ function createNothing() {
export function createVmContext(
filename: string,
features: FeatureFlags<'happyDOM'>,
additionalContext: Partial<vm.Context>
additionalContext: Partial<vm.Context>,
overrideContext: StrictOptions['overrideContext'] = (i) => i
) {
const isHappyDOMEnabled = isFeatureEnabled(features, 'happyDOM', filename);

const { teardown, window } = isHappyDOMEnabled
? createHappyDOMWindow()
: createNothing();
const baseContext = createBaseContext(window, {
__filename: filename,
...additionalContext,
});
const baseContext = createBaseContext(
window,
overrideContext(
{
__filename: filename,
...additionalContext,
},
filename
)
);

const context = vm.createContext(baseContext);

Expand Down
18 changes: 16 additions & 2 deletions packages/testkit/src/module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,22 @@ const createServices = (partial: Partial<Services>): Services => {
const filename = path.resolve(__dirname, './__fixtures__/test.js');

const options: StrictOptions = {
babelOptions: {},
displayName: false,
evaluate: true,
extensions: ['.cjs', '.js', '.jsx', '.ts', '.tsx'],
rules: [],
babelOptions: {},
features: {
dangerousCodeRemover: true,
globalCache: true,
happyDOM: true,
softErrors: false,
},
highPriorityPlugins: [],
overrideContext: (context) => ({
...context,
HighLevelAPI: () => "I'm a high level API",
}),
rules: [],
};

const createEntrypoint = (
Expand Down Expand Up @@ -296,6 +300,16 @@ it("doesn't have access to the process object", () => {
expect(() => mod.evaluate()).toThrow('process.abort is not a function');
});

it('has access to a overridden context', () => {
const { mod } = create`
module.exports = HighLevelAPI();
`;

safeEvaluate(mod);

expect(mod.exports).toBe("I'm a high level API");
});

it('has access to NODE_ENV', () => {
const { mod } = create`
module.exports = process.env.NODE_ENV;
Expand Down
6 changes: 6 additions & 0 deletions packages/utils/src/options/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Context as VmContext } from 'vm';

import type { TransformOptions } from '@babel/core';
import type { File } from '@babel/types';

Expand Down Expand Up @@ -68,6 +70,10 @@ export type StrictOptions = {
features: FeatureFlags;
highPriorityPlugins: string[];
ignore?: RegExp;
overrideContext?: (
context: Partial<VmContext>,
filename: string
) => Partial<VmContext>;
rules: EvalRule[];
tagResolver?: (source: string, tag: string) => string | null;
variableNameConfig?: 'var' | 'dashes' | 'raw';
Expand Down

0 comments on commit 144995f

Please sign in to comment.