@atlaspack/babel-plugin-transform-contextual-imports 2.14.2-noselfbuild-8c516162e.0 → 2.14.2-noselfbuild-71fe9e998.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { PluginObj, types as BabelTypes } from '@babel/core';
2
+ interface Opts {
3
+ /** @deprecated Use "node" instead */
4
+ server?: boolean;
5
+ /** Use node safe import cond syntax */
6
+ node?: boolean;
7
+ }
8
+ interface State {
9
+ /** Plugin options */
10
+ opts: Opts;
11
+ /** @deprecated Statement types didn't work so using any */
12
+ importNodes?: any[];
13
+ /** Set of identifier names that need to be mutated after import was transformed */
14
+ conditionalImportIdentifiers?: Set<string>;
15
+ /** Set of identifiers that have been visited in the exit pass, to avoid adding the load property multiple times */
16
+ visitedIdentifiers?: Set<BabelTypes.Identifier>;
17
+ }
18
+ declare const _default: (api: object, options: Record<string, any> | null | undefined, dirname: string) => PluginObj<State>;
19
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1,289 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', {
3
+ value: true,
4
+ });
5
+ Object.defineProperty(exports, 'default', {
6
+ enumerable: true,
7
+ get: function () {
8
+ return _default;
9
+ },
10
+ });
11
+ const _helperpluginutils = require('@babel/helper-plugin-utils');
12
+ const isServer = (opts) => {
13
+ return 'server' in opts && opts.server;
14
+ };
15
+ const isNode = (opts) => !!('node' in opts && opts.node);
16
+ const _default = (0, _helperpluginutils.declare)((api) => {
17
+ const {types: t} = api;
18
+ const isImportCondCallExpression = (node) => {
19
+ if (
20
+ node.type === 'CallExpression' &&
21
+ node.callee.type === 'Identifier' &&
22
+ node.callee.name === 'importCond'
23
+ ) {
24
+ if (
25
+ node.arguments.length === 3 &&
26
+ node.arguments.every((arg) => arg.type === 'StringLiteral')
27
+ ) {
28
+ return true;
29
+ } else {
30
+ // Simple error for incorrect syntax (since it's documented with the type)
31
+ throw new Error('importCond must have three string literal arguments');
32
+ }
33
+ }
34
+ return false;
35
+ };
36
+ const buildCondFunction = (cond, ifTrue, ifFalse) =>
37
+ t.conditionalExpression(
38
+ t.logicalExpression(
39
+ '&&',
40
+ t.memberExpression(t.identifier('globalThis'), t.identifier('__MCOND')),
41
+ t.callExpression(
42
+ t.memberExpression(
43
+ t.identifier('globalThis'),
44
+ t.identifier('__MCOND'),
45
+ ),
46
+ [cond],
47
+ ),
48
+ ),
49
+ t.memberExpression(
50
+ t.callExpression(t.identifier('require'), [ifTrue]),
51
+ t.identifier('default'),
52
+ ),
53
+ t.memberExpression(
54
+ t.callExpression(t.identifier('require'), [ifFalse]),
55
+ t.identifier('default'),
56
+ ),
57
+ );
58
+ const buildNodeObject = (identifier, cond, ifTrue, ifFalse) => [
59
+ // Create object containing imports
60
+ t.variableDeclaration('const', [
61
+ t.variableDeclarator(
62
+ identifier,
63
+ t.objectExpression([
64
+ t.objectProperty(
65
+ t.identifier('ifTrue'),
66
+ t.memberExpression(
67
+ t.callExpression(t.identifier('require'), [ifTrue]),
68
+ t.identifier('default'),
69
+ ),
70
+ ),
71
+ t.objectProperty(
72
+ t.identifier('ifFalse'),
73
+ t.memberExpression(
74
+ t.callExpression(t.identifier('require'), [ifFalse]),
75
+ t.identifier('default'),
76
+ ),
77
+ ),
78
+ ]),
79
+ ),
80
+ ]),
81
+ // Create lazy getter via the load property on the object.
82
+ // This is node module resolution safe because each time the import is accessed, we re-evaluate the condition.
83
+ t.expressionStatement(
84
+ t.callExpression(
85
+ t.memberExpression(
86
+ t.identifier('Object'),
87
+ t.identifier('defineProperty'),
88
+ ),
89
+ [
90
+ identifier,
91
+ t.stringLiteral('load'),
92
+ t.objectExpression([
93
+ t.objectProperty(
94
+ t.identifier('get'),
95
+ t.arrowFunctionExpression(
96
+ [],
97
+ t.conditionalExpression(
98
+ t.logicalExpression(
99
+ '&&',
100
+ t.memberExpression(
101
+ t.identifier('globalThis'),
102
+ t.identifier('__MCOND'),
103
+ ),
104
+ t.callExpression(
105
+ t.memberExpression(
106
+ t.identifier('globalThis'),
107
+ t.identifier('__MCOND'),
108
+ ),
109
+ [cond],
110
+ ),
111
+ ),
112
+ t.memberExpression(identifier, t.identifier('ifTrue')),
113
+ t.memberExpression(identifier, t.identifier('ifFalse')),
114
+ ),
115
+ ),
116
+ ),
117
+ ]),
118
+ ],
119
+ ),
120
+ ),
121
+ ];
122
+ const buildServerObject = (identUid, cond, ifTrue, ifFalse) => [
123
+ // Create object containing imports
124
+ t.variableDeclaration('const', [
125
+ t.variableDeclarator(
126
+ t.identifier(identUid),
127
+ t.objectExpression([
128
+ t.objectProperty(
129
+ t.identifier('ifTrue'),
130
+ t.memberExpression(
131
+ t.callExpression(t.identifier('require'), [ifTrue]),
132
+ t.identifier('default'),
133
+ ),
134
+ ),
135
+ t.objectProperty(
136
+ t.identifier('ifFalse'),
137
+ t.memberExpression(
138
+ t.callExpression(t.identifier('require'), [ifFalse]),
139
+ t.identifier('default'),
140
+ ),
141
+ ),
142
+ ]),
143
+ ),
144
+ ]),
145
+ // Create lazy getter via the load property on the object
146
+ t.expressionStatement(
147
+ t.callExpression(
148
+ t.memberExpression(
149
+ t.identifier('Object'),
150
+ t.identifier('defineProperty'),
151
+ ),
152
+ [
153
+ t.identifier(identUid),
154
+ t.stringLiteral('load'),
155
+ t.objectExpression([
156
+ t.objectProperty(
157
+ t.identifier('get'),
158
+ t.arrowFunctionExpression(
159
+ [],
160
+ t.conditionalExpression(
161
+ t.logicalExpression(
162
+ '&&',
163
+ t.memberExpression(
164
+ t.identifier('globalThis'),
165
+ t.identifier('__MCOND'),
166
+ ),
167
+ t.callExpression(
168
+ t.memberExpression(
169
+ t.identifier('globalThis'),
170
+ t.identifier('__MCOND'),
171
+ ),
172
+ [cond],
173
+ ),
174
+ ),
175
+ t.memberExpression(
176
+ t.identifier(identUid),
177
+ t.identifier('ifTrue'),
178
+ ),
179
+ t.memberExpression(
180
+ t.identifier(identUid),
181
+ t.identifier('ifFalse'),
182
+ ),
183
+ ),
184
+ ),
185
+ ),
186
+ ]),
187
+ ],
188
+ ),
189
+ ),
190
+ ];
191
+ const checkIsServer = (path, state) => {
192
+ if (
193
+ path.node.callee.type === 'Identifier' &&
194
+ path.node.callee.name === 'importCond'
195
+ ) {
196
+ if (
197
+ path.node.arguments.length == 3 &&
198
+ path.node.arguments.every((arg) => arg.type === 'StringLiteral')
199
+ ) {
200
+ const [cond, ifTrue, ifFalse] = path.node.arguments;
201
+ if (isServer(state.opts)) {
202
+ // Make module pass lazy in ssr
203
+ const identUid = path.scope.generateUid(
204
+ `${cond.value}$${ifTrue.value}$${ifFalse.value}`,
205
+ );
206
+ state.importNodes ??= [];
207
+ state.importNodes.push(
208
+ ...buildServerObject(identUid, cond, ifTrue, ifFalse),
209
+ );
210
+ // Replace call expression with reference to lazy object getter
211
+ path.replaceWith(
212
+ t.memberExpression(t.identifier(identUid), t.identifier('load')),
213
+ );
214
+ }
215
+ }
216
+ }
217
+ };
218
+ return {
219
+ name: '@atlaspack/babel-plugin-transform-contextual-imports',
220
+ visitor: {
221
+ CallExpression: {
222
+ enter(path, state) {
223
+ // Preserve server behaviour in deletable code
224
+ checkIsServer(path, state);
225
+ const node = path.node;
226
+ if (isImportCondCallExpression(node)) {
227
+ const [cond, ifTrue, ifFalse] = node.arguments;
228
+ if (!isNode(state.opts)) {
229
+ // Replace the importCond call with a conditional require import, as a fallback for environments that don't support Atlaspack
230
+ path.replaceWith(buildCondFunction(cond, ifTrue, ifFalse));
231
+ }
232
+ }
233
+ },
234
+ },
235
+ VariableDeclaration: {
236
+ enter(path, state) {
237
+ if (isNode(state.opts)) {
238
+ if (
239
+ path.node.declarations.length === 1 &&
240
+ path.node.declarations[0].type === 'VariableDeclarator' &&
241
+ path.node.declarations[0].id.type === 'Identifier'
242
+ ) {
243
+ const importId = path.node.declarations[0].id;
244
+ const call = path.node.declarations[0].init;
245
+ // Mark identifier for object so we don't add the load property to it
246
+ state.visitedIdentifiers?.add(importId);
247
+ if (call && isImportCondCallExpression(call)) {
248
+ const [cond, ifTrue, ifFalse] = call.arguments;
249
+ // Replace with object containing imports and lazy getter, which allows us to load the correct import based on the condition at runtime
250
+ path.replaceWithMultiple(
251
+ buildNodeObject(importId, cond, ifTrue, ifFalse),
252
+ );
253
+ // Add identifier name to set so we can mutate all import usages in the exit pass
254
+ state.conditionalImportIdentifiers?.add(importId.name);
255
+ }
256
+ }
257
+ }
258
+ },
259
+ },
260
+ Identifier: {
261
+ exit(path, state) {
262
+ const identifier = state.conditionalImportIdentifiers?.has(
263
+ path.node.name,
264
+ );
265
+ if (identifier && !state.visitedIdentifiers?.has(path.node)) {
266
+ // Add load property to the import usage
267
+ const newIdentifer = t.identifier(path.node.name);
268
+ path.replaceWith(
269
+ t.memberExpression(newIdentifer, t.identifier('load')),
270
+ );
271
+ state.visitedIdentifiers?.add(newIdentifer);
272
+ }
273
+ },
274
+ },
275
+ Program: {
276
+ enter(_, state) {
277
+ state.conditionalImportIdentifiers = new Set();
278
+ state.visitedIdentifiers = new Set();
279
+ },
280
+ exit(path, state) {
281
+ if (state.importNodes) {
282
+ // If there's an import node, add it to the top of the body
283
+ path.unshiftContainer('body', state.importNodes);
284
+ }
285
+ },
286
+ },
287
+ },
288
+ };
289
+ });
package/lib/index.mjs ADDED
@@ -0,0 +1,279 @@
1
+ import {declare} from '@babel/helper-plugin-utils';
2
+ const isServer = (opts) => {
3
+ return 'server' in opts && opts.server;
4
+ };
5
+ const isNode = (opts) => !!('node' in opts && opts.node);
6
+ export default declare((api) => {
7
+ const {types: t} = api;
8
+ const isImportCondCallExpression = (node) => {
9
+ if (
10
+ node.type === 'CallExpression' &&
11
+ node.callee.type === 'Identifier' &&
12
+ node.callee.name === 'importCond'
13
+ ) {
14
+ if (
15
+ node.arguments.length === 3 &&
16
+ node.arguments.every((arg) => arg.type === 'StringLiteral')
17
+ ) {
18
+ return true;
19
+ } else {
20
+ // Simple error for incorrect syntax (since it's documented with the type)
21
+ throw new Error('importCond must have three string literal arguments');
22
+ }
23
+ }
24
+ return false;
25
+ };
26
+ const buildCondFunction = (cond, ifTrue, ifFalse) =>
27
+ t.conditionalExpression(
28
+ t.logicalExpression(
29
+ '&&',
30
+ t.memberExpression(t.identifier('globalThis'), t.identifier('__MCOND')),
31
+ t.callExpression(
32
+ t.memberExpression(
33
+ t.identifier('globalThis'),
34
+ t.identifier('__MCOND'),
35
+ ),
36
+ [cond],
37
+ ),
38
+ ),
39
+ t.memberExpression(
40
+ t.callExpression(t.identifier('require'), [ifTrue]),
41
+ t.identifier('default'),
42
+ ),
43
+ t.memberExpression(
44
+ t.callExpression(t.identifier('require'), [ifFalse]),
45
+ t.identifier('default'),
46
+ ),
47
+ );
48
+ const buildNodeObject = (identifier, cond, ifTrue, ifFalse) => [
49
+ // Create object containing imports
50
+ t.variableDeclaration('const', [
51
+ t.variableDeclarator(
52
+ identifier,
53
+ t.objectExpression([
54
+ t.objectProperty(
55
+ t.identifier('ifTrue'),
56
+ t.memberExpression(
57
+ t.callExpression(t.identifier('require'), [ifTrue]),
58
+ t.identifier('default'),
59
+ ),
60
+ ),
61
+ t.objectProperty(
62
+ t.identifier('ifFalse'),
63
+ t.memberExpression(
64
+ t.callExpression(t.identifier('require'), [ifFalse]),
65
+ t.identifier('default'),
66
+ ),
67
+ ),
68
+ ]),
69
+ ),
70
+ ]),
71
+ // Create lazy getter via the load property on the object.
72
+ // This is node module resolution safe because each time the import is accessed, we re-evaluate the condition.
73
+ t.expressionStatement(
74
+ t.callExpression(
75
+ t.memberExpression(
76
+ t.identifier('Object'),
77
+ t.identifier('defineProperty'),
78
+ ),
79
+ [
80
+ identifier,
81
+ t.stringLiteral('load'),
82
+ t.objectExpression([
83
+ t.objectProperty(
84
+ t.identifier('get'),
85
+ t.arrowFunctionExpression(
86
+ [],
87
+ t.conditionalExpression(
88
+ t.logicalExpression(
89
+ '&&',
90
+ t.memberExpression(
91
+ t.identifier('globalThis'),
92
+ t.identifier('__MCOND'),
93
+ ),
94
+ t.callExpression(
95
+ t.memberExpression(
96
+ t.identifier('globalThis'),
97
+ t.identifier('__MCOND'),
98
+ ),
99
+ [cond],
100
+ ),
101
+ ),
102
+ t.memberExpression(identifier, t.identifier('ifTrue')),
103
+ t.memberExpression(identifier, t.identifier('ifFalse')),
104
+ ),
105
+ ),
106
+ ),
107
+ ]),
108
+ ],
109
+ ),
110
+ ),
111
+ ];
112
+ const buildServerObject = (identUid, cond, ifTrue, ifFalse) => [
113
+ // Create object containing imports
114
+ t.variableDeclaration('const', [
115
+ t.variableDeclarator(
116
+ t.identifier(identUid),
117
+ t.objectExpression([
118
+ t.objectProperty(
119
+ t.identifier('ifTrue'),
120
+ t.memberExpression(
121
+ t.callExpression(t.identifier('require'), [ifTrue]),
122
+ t.identifier('default'),
123
+ ),
124
+ ),
125
+ t.objectProperty(
126
+ t.identifier('ifFalse'),
127
+ t.memberExpression(
128
+ t.callExpression(t.identifier('require'), [ifFalse]),
129
+ t.identifier('default'),
130
+ ),
131
+ ),
132
+ ]),
133
+ ),
134
+ ]),
135
+ // Create lazy getter via the load property on the object
136
+ t.expressionStatement(
137
+ t.callExpression(
138
+ t.memberExpression(
139
+ t.identifier('Object'),
140
+ t.identifier('defineProperty'),
141
+ ),
142
+ [
143
+ t.identifier(identUid),
144
+ t.stringLiteral('load'),
145
+ t.objectExpression([
146
+ t.objectProperty(
147
+ t.identifier('get'),
148
+ t.arrowFunctionExpression(
149
+ [],
150
+ t.conditionalExpression(
151
+ t.logicalExpression(
152
+ '&&',
153
+ t.memberExpression(
154
+ t.identifier('globalThis'),
155
+ t.identifier('__MCOND'),
156
+ ),
157
+ t.callExpression(
158
+ t.memberExpression(
159
+ t.identifier('globalThis'),
160
+ t.identifier('__MCOND'),
161
+ ),
162
+ [cond],
163
+ ),
164
+ ),
165
+ t.memberExpression(
166
+ t.identifier(identUid),
167
+ t.identifier('ifTrue'),
168
+ ),
169
+ t.memberExpression(
170
+ t.identifier(identUid),
171
+ t.identifier('ifFalse'),
172
+ ),
173
+ ),
174
+ ),
175
+ ),
176
+ ]),
177
+ ],
178
+ ),
179
+ ),
180
+ ];
181
+ const checkIsServer = (path, state) => {
182
+ if (
183
+ path.node.callee.type === 'Identifier' &&
184
+ path.node.callee.name === 'importCond'
185
+ ) {
186
+ if (
187
+ path.node.arguments.length == 3 &&
188
+ path.node.arguments.every((arg) => arg.type === 'StringLiteral')
189
+ ) {
190
+ const [cond, ifTrue, ifFalse] = path.node.arguments;
191
+ if (isServer(state.opts)) {
192
+ // Make module pass lazy in ssr
193
+ const identUid = path.scope.generateUid(
194
+ `${cond.value}$${ifTrue.value}$${ifFalse.value}`,
195
+ );
196
+ state.importNodes ??= [];
197
+ state.importNodes.push(
198
+ ...buildServerObject(identUid, cond, ifTrue, ifFalse),
199
+ );
200
+ // Replace call expression with reference to lazy object getter
201
+ path.replaceWith(
202
+ t.memberExpression(t.identifier(identUid), t.identifier('load')),
203
+ );
204
+ }
205
+ }
206
+ }
207
+ };
208
+ return {
209
+ name: '@atlaspack/babel-plugin-transform-contextual-imports',
210
+ visitor: {
211
+ CallExpression: {
212
+ enter(path, state) {
213
+ // Preserve server behaviour in deletable code
214
+ checkIsServer(path, state);
215
+ const node = path.node;
216
+ if (isImportCondCallExpression(node)) {
217
+ const [cond, ifTrue, ifFalse] = node.arguments;
218
+ if (!isNode(state.opts)) {
219
+ // Replace the importCond call with a conditional require import, as a fallback for environments that don't support Atlaspack
220
+ path.replaceWith(buildCondFunction(cond, ifTrue, ifFalse));
221
+ }
222
+ }
223
+ },
224
+ },
225
+ VariableDeclaration: {
226
+ enter(path, state) {
227
+ if (isNode(state.opts)) {
228
+ if (
229
+ path.node.declarations.length === 1 &&
230
+ path.node.declarations[0].type === 'VariableDeclarator' &&
231
+ path.node.declarations[0].id.type === 'Identifier'
232
+ ) {
233
+ const importId = path.node.declarations[0].id;
234
+ const call = path.node.declarations[0].init;
235
+ // Mark identifier for object so we don't add the load property to it
236
+ state.visitedIdentifiers?.add(importId);
237
+ if (call && isImportCondCallExpression(call)) {
238
+ const [cond, ifTrue, ifFalse] = call.arguments;
239
+ // Replace with object containing imports and lazy getter, which allows us to load the correct import based on the condition at runtime
240
+ path.replaceWithMultiple(
241
+ buildNodeObject(importId, cond, ifTrue, ifFalse),
242
+ );
243
+ // Add identifier name to set so we can mutate all import usages in the exit pass
244
+ state.conditionalImportIdentifiers?.add(importId.name);
245
+ }
246
+ }
247
+ }
248
+ },
249
+ },
250
+ Identifier: {
251
+ exit(path, state) {
252
+ const identifier = state.conditionalImportIdentifiers?.has(
253
+ path.node.name,
254
+ );
255
+ if (identifier && !state.visitedIdentifiers?.has(path.node)) {
256
+ // Add load property to the import usage
257
+ const newIdentifer = t.identifier(path.node.name);
258
+ path.replaceWith(
259
+ t.memberExpression(newIdentifer, t.identifier('load')),
260
+ );
261
+ state.visitedIdentifiers?.add(newIdentifer);
262
+ }
263
+ },
264
+ },
265
+ Program: {
266
+ enter(_, state) {
267
+ state.conditionalImportIdentifiers = new Set();
268
+ state.visitedIdentifiers = new Set();
269
+ },
270
+ exit(path, state) {
271
+ if (state.importNodes) {
272
+ // If there's an import node, add it to the top of the body
273
+ path.unshiftContainer('body', state.importNodes);
274
+ }
275
+ },
276
+ },
277
+ },
278
+ };
279
+ });
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@atlaspack/babel-plugin-transform-contextual-imports",
3
- "version": "2.14.2-noselfbuild-8c516162e.0",
3
+ "version": "2.14.2-noselfbuild-71fe9e998.0",
4
4
  "license": "(MIT OR Apache-2.0)",
5
+ "type": "commonjs",
5
6
  "publishConfig": {
6
7
  "access": "public"
7
8
  },
@@ -9,11 +10,27 @@
9
10
  "type": "git",
10
11
  "url": "https://github.com/atlassian-labs/atlaspack.git"
11
12
  },
12
- "main": "./lib/index.js",
13
- "source": "./src/index.ts",
13
+ "main": "lib/index.js",
14
+ "types": "lib/index.d.mts",
15
+ "exports": {
16
+ ".": {
17
+ "atlaspack::sources": "./src/index.mts",
18
+ "types": [
19
+ "./lib/index.d.mts",
20
+ "./src/index.mts"
21
+ ],
22
+ "import": "./lib/index.mjs",
23
+ "require": "./lib/index.js",
24
+ "default": "./lib/index.js"
25
+ },
26
+ "./*": "./*"
27
+ },
14
28
  "engines": {
15
29
  "node": ">= 16.0.0"
16
30
  },
31
+ "scripts": {
32
+ "build-tsc": "node ../../../scripts/build-tsc.mjs"
33
+ },
17
34
  "dependencies": {
18
35
  "@babel/core": "^7.12.2",
19
36
  "@babel/helper-plugin-utils": "^7.12.2"
@@ -22,6 +39,5 @@
22
39
  "@types/babel__core": "^7.12.2",
23
40
  "@types/babel__helper-plugin-utils": "^7.10.3"
24
41
  },
25
- "type": "commonjs",
26
- "gitHead": "8c516162e3109bbebe535130a7de57e9e59a4eb8"
42
+ "gitHead": "71fe9e998256a417234fd5f388a7428aa0d6fd60"
27
43
  }
package/tsconfig.json CHANGED
@@ -1,12 +1,4 @@
1
1
  {
2
- "compilerOptions": {
3
- "target": "es2016",
4
- "module": "commonjs",
5
- "esModuleInterop": true,
6
- "forceConsistentCasingInFileNames": true,
7
- "strict": true,
8
- "skipLibCheck": true
9
- },
10
- "include": ["src/*"],
11
- "exclude": ["node_modules"]
2
+ "extends": "../../../tsconfig.json",
3
+ "include": ["src"]
12
4
  }
File without changes