-
Notifications
You must be signed in to change notification settings - Fork 413
/
preeval.ts
121 lines (101 loc) · 3.53 KB
/
preeval.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* This file is a babel preset used to transform files inside evaluators.
* It works the same as main `babel/extract` preset, but do not evaluate lazy dependencies.
*/
import type { BabelFile, PluginObj } from '@babel/core';
import { createCustomDebug } from '@linaria/logger';
import type { StrictOptions } from '@linaria/utils';
import {
EventEmitter,
getFileIdx,
addIdentifierToLinariaPreval,
removeDangerousCode,
isFeatureEnabled,
} from '@linaria/utils';
import type { Core } from '../babel';
import type { IPluginState } from '../types';
import { processTemplateExpression } from '../utils/processTemplateExpression';
export type PreevalOptions = Pick<
StrictOptions,
'classNameSlug' | 'displayName' | 'evaluate' | 'features'
> & { eventEmitter: EventEmitter };
const onFinishCallbacks = new WeakMap<object, () => void>();
export default function preeval(
babel: Core,
{ eventEmitter = EventEmitter.dummy, ...options }: PreevalOptions
): PluginObj<IPluginState & { onFinish: () => void }> {
const { types: t } = babel;
return {
name: '@linaria/babel/preeval',
pre(file: BabelFile) {
const filename = file.opts.filename!;
const log = createCustomDebug('preeval', getFileIdx(filename));
log('start', 'Looking for template literals…');
const rootScope = file.scope;
this.processors = [];
const onProcessTemplateFinished = eventEmitter.pair({
method: 'preeval:processTemplate',
});
file.path.traverse({
Identifier: (p) => {
processTemplateExpression(p, file.opts, options, (processor) => {
processor.dependencies.forEach((dependency) => {
if (dependency.ex.type === 'Identifier') {
addIdentifierToLinariaPreval(rootScope, dependency.ex.name);
}
});
processor.doEvaltimeReplacement();
this.processors.push(processor);
});
},
});
onProcessTemplateFinished();
if (
isFeatureEnabled(options.features, 'dangerousCodeRemover', filename)
) {
log('start', 'Strip all JSX and browser related stuff');
const onCodeRemovingFinished = eventEmitter.pair({
method: 'preeval:removeDangerousCode',
});
removeDangerousCode(file.path);
onCodeRemovingFinished();
}
onFinishCallbacks.set(
this,
eventEmitter.pair({ method: 'preeval:rest-transformations' })
);
},
visitor: {},
post(file: BabelFile) {
onFinishCallbacks.get(this)?.();
const log = createCustomDebug('preeval', getFileIdx(file.opts.filename!));
if (this.processors.length === 0) {
log('end', "We didn't find any Linaria template literals");
// We didn't find any Linaria template literals.
return;
}
this.file.metadata.linaria = {
processors: this.processors,
replacements: [],
rules: {},
dependencies: [],
};
const linariaPreval = file.path.getData('__linariaPreval');
if (!linariaPreval) {
// Event if there is no dependencies, we still need to add __linariaPreval
const linariaExport = t.expressionStatement(
t.assignmentExpression(
'=',
t.memberExpression(
t.identifier('exports'),
t.identifier('__linariaPreval')
),
t.objectExpression([])
)
);
file.path.pushContainer('body', linariaExport);
}
log('end', '__linariaPreval has been added');
},
};
}