@ssets/babel 1.0.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.
@@ -0,0 +1,4 @@
1
+ import { type Node } from "@babel/types";
2
+ export default function annotateAsPure(pathOrNode: Node | {
3
+ node: Node;
4
+ }): void;
@@ -0,0 +1,13 @@
1
+ import { addComment } from "@babel/types";
2
+ const PURE_ANNOTATION = "#__PURE__";
3
+ const isPureAnnotated = ({ leadingComments }) => !!leadingComments &&
4
+ leadingComments.some((comment) => /[@#]__PURE__/.test(comment.value));
5
+ export default function annotateAsPure(pathOrNode) {
6
+ const node =
7
+ // @ts-expect-error Node will not have `node` property
8
+ (pathOrNode.node || pathOrNode);
9
+ if (isPureAnnotated(node)) {
10
+ return;
11
+ }
12
+ addComment(node, "leading", PURE_ANNOTATION);
13
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Given a string `str` and an array of candidates `arr`,
3
+ * return the first of elements in candidates that has minimal
4
+ * Levenshtein distance with `str`.
5
+ * @export
6
+ * @param {string} str
7
+ * @param {string[]} arr
8
+ * @returns {string}
9
+ */
10
+ export declare function findSuggestion(str: string, arr: readonly string[]): string;
11
+ export declare class OptionValidator {
12
+ descriptor: string;
13
+ constructor(descriptor: string);
14
+ /**
15
+ * Validate if the given `options` follow the name of keys defined in the `TopLevelOptionShape`
16
+ *
17
+ * @param {Object} options
18
+ * @param {Object} TopLevelOptionShape
19
+ * An object with all the valid key names that `options` should be allowed to have
20
+ * The property values of `TopLevelOptionShape` can be arbitrary
21
+ * @memberof OptionValidator
22
+ */
23
+ validateTopLevelOptions(options: object, TopLevelOptionShape: object): void;
24
+ validateBooleanOption<T extends boolean>(name: string, value?: boolean, defaultValue?: T): boolean | T;
25
+ validateStringOption<T extends string>(name: string, value?: string, defaultValue?: T): string | T;
26
+ /**
27
+ * A helper interface copied from the `invariant` npm package.
28
+ * It throws given `message` when `condition` is not met
29
+ *
30
+ * @param {boolean} condition
31
+ * @param {string} message
32
+ * @memberof OptionValidator
33
+ */
34
+ invariant(condition: boolean, message: string): void;
35
+ formatMessage(message: string): string;
36
+ }
@@ -0,0 +1,100 @@
1
+ const { min } = Math;
2
+ // a minimal leven distance implementation
3
+ // balanced maintainability with code size
4
+ // It is not blazingly fast but should be okay for Babel user case
5
+ // where it will be run for at most tens of time on strings
6
+ // that have less than 20 ASCII characters
7
+ // https://rosettacode.org/wiki/Levenshtein_distance#ES5
8
+ function levenshtein(a, b) {
9
+ let t = [], u = [], i, j;
10
+ const m = a.length, n = b.length;
11
+ if (!m) {
12
+ return n;
13
+ }
14
+ if (!n) {
15
+ return m;
16
+ }
17
+ for (j = 0; j <= n; j++) {
18
+ t[j] = j;
19
+ }
20
+ for (i = 1; i <= m; i++) {
21
+ for (u = [i], j = 1; j <= n; j++) {
22
+ u[j] =
23
+ a[i - 1] === b[j - 1] ? t[j - 1] : min(t[j - 1], t[j], u[j - 1]) + 1;
24
+ }
25
+ t = u;
26
+ }
27
+ return u[n];
28
+ }
29
+ /**
30
+ * Given a string `str` and an array of candidates `arr`,
31
+ * return the first of elements in candidates that has minimal
32
+ * Levenshtein distance with `str`.
33
+ * @export
34
+ * @param {string} str
35
+ * @param {string[]} arr
36
+ * @returns {string}
37
+ */
38
+ export function findSuggestion(str, arr) {
39
+ const distances = arr.map((el) => levenshtein(el, str));
40
+ return arr[distances.indexOf(min(...distances))];
41
+ }
42
+ export class OptionValidator {
43
+ constructor(descriptor) {
44
+ this.descriptor = descriptor;
45
+ }
46
+ /**
47
+ * Validate if the given `options` follow the name of keys defined in the `TopLevelOptionShape`
48
+ *
49
+ * @param {Object} options
50
+ * @param {Object} TopLevelOptionShape
51
+ * An object with all the valid key names that `options` should be allowed to have
52
+ * The property values of `TopLevelOptionShape` can be arbitrary
53
+ * @memberof OptionValidator
54
+ */
55
+ validateTopLevelOptions(options, TopLevelOptionShape) {
56
+ const validOptionNames = Object.keys(TopLevelOptionShape);
57
+ for (const option of Object.keys(options)) {
58
+ if (!validOptionNames.includes(option)) {
59
+ throw new Error(this.formatMessage(`'${option}' is not a valid top-level option.
60
+ - Did you mean '${findSuggestion(option, validOptionNames)}'?`));
61
+ }
62
+ }
63
+ }
64
+ // note: we do not consider rewrite them to high order functions
65
+ // until we have to support `validateNumberOption`.
66
+ validateBooleanOption(name, value, defaultValue) {
67
+ if (value === undefined) {
68
+ return defaultValue;
69
+ }
70
+ else {
71
+ this.invariant(typeof value === "boolean", `'${name}' option must be a boolean.`);
72
+ }
73
+ return value;
74
+ }
75
+ validateStringOption(name, value, defaultValue) {
76
+ if (value === undefined) {
77
+ return defaultValue;
78
+ }
79
+ else {
80
+ this.invariant(typeof value === "string", `'${name}' option must be a string.`);
81
+ }
82
+ return value;
83
+ }
84
+ /**
85
+ * A helper interface copied from the `invariant` npm package.
86
+ * It throws given `message` when `condition` is not met
87
+ *
88
+ * @param {boolean} condition
89
+ * @param {string} message
90
+ * @memberof OptionValidator
91
+ */
92
+ invariant(condition, message) {
93
+ if (!condition) {
94
+ throw new Error(this.formatMessage(message));
95
+ }
96
+ }
97
+ formatMessage(message) {
98
+ return `${this.descriptor}: ${message}`;
99
+ }
100
+ }
@@ -0,0 +1,9 @@
1
+ import babel from "@babel/core";
2
+ interface AllowedCallees {
3
+ [moduleName: string]: string[];
4
+ }
5
+ export interface PluginOptions {
6
+ allowedCallees?: AllowedCallees;
7
+ }
8
+ declare const _default: (api: object, options: PluginOptions | null | undefined, dirname: string) => babel.PluginObj<babel.PluginPass>;
9
+ export default _default;
@@ -0,0 +1,339 @@
1
+ import { declare } from "@babel/helper-plugin-utils";
2
+ // remember to set `cacheDirectory` to `false` when modifying this plugin
3
+ const DEFAULT_ALLOWED_CALLEES = {
4
+ react: ["createContext", "forwardRef", "memo"],
5
+ };
6
+ const calleeModuleMapping = new Map(); // Mapping of callee name to module name
7
+ const seenDisplayNames = new Set();
8
+ /**
9
+ * Applies allowed callees mapping to the internal calleeModuleMapping.
10
+ */
11
+ function applyAllowedCallees(mapping) {
12
+ Object.entries(mapping).forEach(([moduleName, methodNames]) => {
13
+ methodNames.forEach((methodName) => {
14
+ const moduleNames = calleeModuleMapping.get(methodName) ?? [];
15
+ moduleNames.push(moduleName);
16
+ calleeModuleMapping.set(methodName, moduleNames);
17
+ });
18
+ });
19
+ }
20
+ export default declare((api, options) => {
21
+ api.assertVersion(7);
22
+ calleeModuleMapping.clear();
23
+ applyAllowedCallees(DEFAULT_ALLOWED_CALLEES);
24
+ if (options.allowedCallees) {
25
+ applyAllowedCallees(options.allowedCallees);
26
+ }
27
+ const t = api.types;
28
+ return {
29
+ name: "@probablyup/babel-plugin-react-displayname",
30
+ visitor: {
31
+ Program() {
32
+ // We allow duplicate names across files,
33
+ // so we clear when we're transforming on a new file
34
+ seenDisplayNames.clear();
35
+ },
36
+ "FunctionExpression|ArrowFunctionExpression|ObjectMethod": (path) => {
37
+ // if the parent is a call expression, make sure it's an allowed one
38
+ if (path.parentPath && path.parentPath.isCallExpression()
39
+ ? isAllowedCallExpression(t, path.parentPath)
40
+ : true) {
41
+ if (doesReturnJSX(t, path.node.body)) {
42
+ addDisplayNamesToFunctionComponent(t, path);
43
+ }
44
+ }
45
+ },
46
+ CallExpression(path) {
47
+ if (isAllowedCallExpression(t, path)) {
48
+ addDisplayNamesToFunctionComponent(t, path);
49
+ }
50
+ },
51
+ },
52
+ };
53
+ });
54
+ /**
55
+ * Checks if this function returns JSX nodes.
56
+ * It does not do type-checking, which means calling
57
+ * other functions that return JSX will still return `false`.
58
+ */
59
+ function doesReturnJSX(t, node) {
60
+ if (!node) {
61
+ return false;
62
+ }
63
+ const body = t.toBlock(node).body;
64
+ if (!body) {
65
+ return false;
66
+ }
67
+ return body.some((statement) => {
68
+ let currentNode;
69
+ if (t.isReturnStatement(statement)) {
70
+ currentNode = statement.argument;
71
+ }
72
+ else if (t.isExpressionStatement(statement) &&
73
+ !t.isCallExpression(statement.expression)) {
74
+ currentNode = statement.expression;
75
+ }
76
+ else {
77
+ return false;
78
+ }
79
+ if (t.isCallExpression(currentNode) &&
80
+ // detect *.createElement and count it as returning JSX
81
+ // this could be improved a lot but will work for the 99% case
82
+ t.isMemberExpression(currentNode.callee) &&
83
+ t.isIdentifier(currentNode.callee.property) &&
84
+ currentNode.callee.property.name === "createElement") {
85
+ return true;
86
+ }
87
+ if (t.isConditionalExpression(currentNode)) {
88
+ return (isJSX(t, currentNode.consequent) || isJSX(t, currentNode.alternate));
89
+ }
90
+ if (t.isLogicalExpression(currentNode)) {
91
+ return isJSX(t, currentNode.left) || isJSX(t, currentNode.right);
92
+ }
93
+ if (t.isArrayExpression(currentNode)) {
94
+ return currentNode.elements.some((ele) => isJSX(t, ele));
95
+ }
96
+ return isJSX(t, currentNode);
97
+ });
98
+ }
99
+ /**
100
+ * Checks if this node is JSXElement or JSXFragment,
101
+ * which are the root nodes of react components.
102
+ */
103
+ function isJSX(t, node) {
104
+ return t.isJSXElement(node) || t.isJSXFragment(node);
105
+ }
106
+ /**
107
+ * Checks if this path is an allowed CallExpression.
108
+ */
109
+ function isAllowedCallExpression(t, path) {
110
+ const calleePath = path.get("callee");
111
+ const callee = path.node
112
+ .callee;
113
+ const calleeName = callee.name || callee.property?.name;
114
+ const moduleNames = calleeName && calleeModuleMapping.get(calleeName);
115
+ if (!moduleNames) {
116
+ return false;
117
+ }
118
+ // If the callee is an identifier expression, then check if it matches
119
+ // a named import, e.g. `import {createContext} from 'react'`.
120
+ if (calleePath.isIdentifier()) {
121
+ return moduleNames.some((moduleName) => calleePath.referencesImport(moduleName, calleeName));
122
+ }
123
+ // Otherwise, check if the member expression's object matches
124
+ // a default import (e.g. `import React from 'react'`)
125
+ // or namespace import (e.g. `import * as React from 'react')
126
+ if (calleePath.isMemberExpression()) {
127
+ const object = calleePath.get("object");
128
+ return moduleNames.some((moduleName) => object.referencesImport(moduleName, "default") ||
129
+ object.referencesImport(moduleName, "*"));
130
+ }
131
+ return false;
132
+ }
133
+ /**
134
+ * Adds displayName to the function component if it is:
135
+ * - assigned to a variable or object path
136
+ * - not within other JSX elements
137
+ * - not called by a react hook or _createClass helper
138
+ */
139
+ function addDisplayNamesToFunctionComponent(t, path) {
140
+ const componentIdentifiers = [];
141
+ if (path.node.key) {
142
+ componentIdentifiers.push({ id: path.node.key });
143
+ }
144
+ let assignmentPath;
145
+ let hasCallee = false;
146
+ let hasObjectProperty = false;
147
+ const scopePath = path.scope.parent && path.scope.parent.path;
148
+ path.find((parentPath) => {
149
+ // we've hit the scope, stop going further up
150
+ if (parentPath === scopePath) {
151
+ return true;
152
+ }
153
+ // Ignore functions within jsx
154
+ if (isJSX(t, parentPath.node)) {
155
+ return true;
156
+ }
157
+ if (parentPath.isCallExpression()) {
158
+ // Ignore immediately invoked function expressions (IIFEs)
159
+ const callee = parentPath.node.callee;
160
+ if (t.isArrowFunctionExpression(callee) ||
161
+ t.isFunctionExpression(callee)) {
162
+ return true;
163
+ }
164
+ // Ignore instances where displayNames are disallowed
165
+ // _createClass(() => <Element />)
166
+ // useMemo(() => <Element />)
167
+ const calleeName = t.isIdentifier(callee) ? callee.name : undefined;
168
+ if (calleeName &&
169
+ (calleeName.startsWith("_") || calleeName.startsWith("use"))) {
170
+ return true;
171
+ }
172
+ hasCallee = true;
173
+ }
174
+ // componentIdentifier = <Element />
175
+ if (parentPath.isAssignmentExpression()) {
176
+ assignmentPath = parentPath.parentPath;
177
+ componentIdentifiers.unshift({
178
+ id: parentPath.node.left,
179
+ });
180
+ return true;
181
+ }
182
+ // const componentIdentifier = <Element />
183
+ if (parentPath.isVariableDeclarator()) {
184
+ // Ternary expression
185
+ if (t.isConditionalExpression(parentPath.node.init)) {
186
+ const { consequent, alternate } = parentPath.node.init;
187
+ const isConsequentFunction = t.isArrowFunctionExpression(consequent) ||
188
+ t.isFunctionExpression(consequent);
189
+ const isAlternateFunction = t.isArrowFunctionExpression(alternate) ||
190
+ t.isFunctionExpression(alternate);
191
+ // Only add display name if variable is a function
192
+ if (!isConsequentFunction || !isAlternateFunction) {
193
+ return false;
194
+ }
195
+ }
196
+ assignmentPath = parentPath.parentPath;
197
+ componentIdentifiers.unshift({
198
+ id: parentPath.node.id,
199
+ });
200
+ return true;
201
+ }
202
+ // if this is not a continuous object key: value pair, stop processing it
203
+ if (hasObjectProperty &&
204
+ !(parentPath.isObjectProperty() || parentPath.isObjectExpression())) {
205
+ return true;
206
+ }
207
+ // { componentIdentifier: <Element /> }
208
+ if (parentPath.isObjectProperty()) {
209
+ hasObjectProperty = true;
210
+ const node = parentPath.node;
211
+ componentIdentifiers.unshift({
212
+ id: node.key,
213
+ computed: node.computed,
214
+ });
215
+ }
216
+ return false;
217
+ });
218
+ if (!assignmentPath || componentIdentifiers.length === 0) {
219
+ return;
220
+ }
221
+ const name = generateDisplayName(t, componentIdentifiers);
222
+ const pattern = `${name}.displayName`;
223
+ // disallow duplicate names if they were assigned in different scopes
224
+ if (seenDisplayNames.has(name) &&
225
+ !hasBeenAssignedPrev(t, assignmentPath, pattern, name)) {
226
+ return;
227
+ }
228
+ // skip unnecessary addition of name if it is reassigned later on
229
+ if (hasBeenAssignedNext(t, assignmentPath, pattern)) {
230
+ return;
231
+ }
232
+ // at this point we're ready to start pushing code
233
+ if (hasCallee) {
234
+ // if we're getting called by some wrapper function,
235
+ // give this function a name
236
+ setInternalFunctionName(t, path, name);
237
+ }
238
+ const displayNameStatement = createDisplayNameStatement(t, componentIdentifiers, name);
239
+ assignmentPath.insertAfter(displayNameStatement);
240
+ seenDisplayNames.add(name);
241
+ }
242
+ /**
243
+ * Generate a displayName string based on the ids collected.
244
+ */
245
+ function generateDisplayName(t, componentIdentifiers) {
246
+ let displayName = "";
247
+ componentIdentifiers.forEach((componentIdentifier) => {
248
+ const node = componentIdentifier.id;
249
+ if (!node) {
250
+ return;
251
+ }
252
+ const name = generateNodeDisplayName(t, node);
253
+ displayName += componentIdentifier.computed ? `[${name}]` : `.${name}`;
254
+ });
255
+ return displayName.slice(1);
256
+ }
257
+ /**
258
+ * Generate a displayName string based on the node.
259
+ */
260
+ function generateNodeDisplayName(t, node) {
261
+ if (t.isIdentifier(node)) {
262
+ return node.name;
263
+ }
264
+ if (t.isMemberExpression(node)) {
265
+ const objectDisplayName = generateNodeDisplayName(t, node.object);
266
+ const propertyDisplayName = generateNodeDisplayName(t, node.property);
267
+ const res = node.computed
268
+ ? `${objectDisplayName}[${propertyDisplayName}]`
269
+ : `${objectDisplayName}.${propertyDisplayName}`;
270
+ return res;
271
+ }
272
+ return "";
273
+ }
274
+ /**
275
+ * Checks if this path has been previously assigned to a particular value.
276
+ */
277
+ function hasBeenAssignedPrev(t, assignmentPath, pattern, value) {
278
+ return assignmentPath.getAllPrevSiblings().some((sibling) => {
279
+ const expression = sibling.get("expression");
280
+ if (!t.isAssignmentExpression(expression.node, { operator: "=" })) {
281
+ return false;
282
+ }
283
+ if (!t.isStringLiteral(expression.node.right, { value })) {
284
+ return false;
285
+ }
286
+ return expression.get("left").matchesPattern(pattern);
287
+ });
288
+ }
289
+ /**
290
+ * Checks if this path will be assigned later in the scope.
291
+ */
292
+ function hasBeenAssignedNext(t, assignmentPath, pattern) {
293
+ return assignmentPath.getAllNextSiblings().some((sibling) => {
294
+ const expression = sibling.get("expression");
295
+ if (!t.isAssignmentExpression(expression.node, { operator: "=" })) {
296
+ return false;
297
+ }
298
+ return expression.get("left").matchesPattern(pattern);
299
+ });
300
+ }
301
+ /**
302
+ * Generate a displayName ExpressionStatement node based on the ids.
303
+ */
304
+ function createDisplayNameStatement(t, componentIdentifiers, displayName) {
305
+ const node = createMemberExpression(t, componentIdentifiers);
306
+ const expression = t.assignmentExpression("=", t.memberExpression(node, t.identifier("displayName")), t.stringLiteral(displayName));
307
+ const ifStatement = t.ifStatement(t.binaryExpression("!==", t.memberExpression(t.memberExpression(t.identifier("process"), t.identifier("env")), t.identifier("NODE_ENV")), t.stringLiteral("production")), t.expressionStatement(expression));
308
+ return ifStatement;
309
+ }
310
+ /**
311
+ * Helper that creates a MemberExpression node from the ids.
312
+ */
313
+ function createMemberExpression(t, componentIdentifiers) {
314
+ let node = componentIdentifiers[0].id;
315
+ if (componentIdentifiers.length > 1) {
316
+ for (let i = 1; i < componentIdentifiers.length; i += 1) {
317
+ const { id, computed } = componentIdentifiers[i];
318
+ node = t.memberExpression(node, id, computed);
319
+ }
320
+ }
321
+ return node;
322
+ }
323
+ /**
324
+ * Changes the arrow function to a function expression and gives it a name.
325
+ * `name` will be changed to ensure that it is unique within the scope. e.g. `helper` -> `_helper`
326
+ */
327
+ function setInternalFunctionName(t, path, name) {
328
+ if (!name ||
329
+ ("id" in path.node && path.node.id != null) ||
330
+ ("key" in path.node && path.node.key != null)) {
331
+ return;
332
+ }
333
+ const id = path.scope.generateUidIdentifier(name);
334
+ if (path.isArrowFunctionExpression()) {
335
+ path.arrowFunctionToExpression();
336
+ }
337
+ // @ts-expect-error Not really an error
338
+ path.node.id = id;
339
+ }
@@ -0,0 +1,8 @@
1
+ import babel, { PluginObj } from "@babel/core";
2
+ type Options = {
3
+ outExtension?: string | null;
4
+ };
5
+ export default function plugin({ types }: {
6
+ types: typeof babel.types;
7
+ }, { outExtension }?: Options): PluginObj;
8
+ export {};
@@ -0,0 +1,62 @@
1
+ import nodePath from "node:path";
2
+ import resolve from "resolve/sync.js";
3
+ function toPosixPath(importPath) {
4
+ return nodePath
5
+ .normalize(importPath)
6
+ .split(nodePath.sep)
7
+ .join(nodePath.posix.sep);
8
+ }
9
+ function pathToNodeImportSpecifier(importPath) {
10
+ const normalized = toPosixPath(importPath);
11
+ return normalized.startsWith("/") || normalized.startsWith(".")
12
+ ? normalized
13
+ : `./${normalized}`;
14
+ }
15
+ export default function plugin({ types }, { outExtension } = {}) {
16
+ const cache = new Map();
17
+ const extensions = [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx"];
18
+ const extensionsSet = new Set(extensions);
19
+ function doResolve(importSource, state) {
20
+ const importedPath = importSource.node.value;
21
+ if (extensionsSet.has(nodePath.extname(importedPath)) ||
22
+ importedPath.endsWith(".css") ||
23
+ !importedPath.startsWith(".")) {
24
+ return;
25
+ }
26
+ const importerDir = nodePath.dirname(state.filename);
27
+ const absoluteImportPath = nodePath.resolve(importerDir, importedPath);
28
+ let resolvedPath = cache.get(absoluteImportPath);
29
+ if (!resolvedPath) {
30
+ try {
31
+ resolvedPath = resolve(absoluteImportPath, { extensions });
32
+ if (outExtension &&
33
+ extensionsSet.has(nodePath.extname(resolvedPath))) {
34
+ const dir = nodePath.dirname(resolvedPath);
35
+ const ext = nodePath.extname(resolvedPath);
36
+ const base = nodePath.basename(resolvedPath, ext);
37
+ resolvedPath = nodePath.resolve(dir, base + outExtension);
38
+ }
39
+ cache.set(absoluteImportPath, resolvedPath);
40
+ }
41
+ catch (e) {
42
+ throw new Error(`Could not resolve "${importedPath}" from "${state.filename}"`);
43
+ }
44
+ }
45
+ const relativeResolvedPath = nodePath.relative(importerDir, resolvedPath);
46
+ importSource.replaceWith(types.stringLiteral(pathToNodeImportSpecifier(relativeResolvedPath)));
47
+ }
48
+ return {
49
+ visitor: {
50
+ ImportDeclaration(path, state) {
51
+ doResolve(path.get("source"), state);
52
+ },
53
+ ExportNamedDeclaration(path, state) {
54
+ if (path.get("source").isStringLiteral())
55
+ doResolve(path.get("source"), state);
56
+ },
57
+ ExportAllDeclaration(path, state) {
58
+ doResolve(path.get("source"), state);
59
+ },
60
+ },
61
+ };
62
+ }
@@ -0,0 +1,7 @@
1
+ export interface Options {
2
+ disallowAmbiguousJSXLike?: boolean;
3
+ dts?: boolean;
4
+ isTSX?: boolean;
5
+ }
6
+ declare const _default: (api: object, options: Options | null | undefined, dirname: string) => import("@babel/core").PluginObj<import("@babel/core").PluginPass>;
7
+ export default _default;
@@ -0,0 +1,15 @@
1
+ // @ts-nocheck
2
+ import { declare } from "@babel/helper-plugin-utils";
3
+ export default declare((api, opts) => {
4
+ api.assertVersion("^7.0.0-0 || ^8.0.0");
5
+ const { disallowAmbiguousJSXLike, dts } = opts;
6
+ return {
7
+ name: "syntax-typescript",
8
+ manipulateOptions(opts, parserOpts) {
9
+ parserOpts.plugins.push([
10
+ "typescript",
11
+ { disallowAmbiguousJSXLike, dts },
12
+ ]);
13
+ },
14
+ };
15
+ });
@@ -0,0 +1,9 @@
1
+ import { types as t } from "@babel/core";
2
+ declare const _default: (api: object, options: Record<string, any> | null | undefined, dirname: string) => {
3
+ name: string;
4
+ visitor: {
5
+ ExportDefaultDeclaration(this: import("@babel/core").PluginPass, { node }: import("@babel/traverse").NodePath<t.ExportDefaultDeclaration>, state: import("@babel/core").PluginPass): void;
6
+ CallExpression(this: import("@babel/core").PluginPass, path: import("@babel/traverse").NodePath<t.CallExpression>): void;
7
+ };
8
+ };
9
+ export default _default;
@@ -0,0 +1,97 @@
1
+ import { declare } from "@babel/helper-plugin-utils";
2
+ import path from "node:path";
3
+ import { types as t } from "@babel/core";
4
+ export default declare((api) => {
5
+ api.assertVersion(7);
6
+ function addDisplayName(id, call) {
7
+ const props = call.arguments[0].properties;
8
+ let safe = true;
9
+ for (let i = 0; i < props.length; i++) {
10
+ const prop = props[i];
11
+ if (t.isSpreadElement(prop)) {
12
+ continue;
13
+ }
14
+ const key = t.toComputedKey(prop);
15
+ if (t.isStringLiteral(key, { value: "displayName" })) {
16
+ safe = false;
17
+ break;
18
+ }
19
+ }
20
+ if (safe) {
21
+ props.unshift(t.objectProperty(t.identifier("displayName"), t.stringLiteral(id)));
22
+ }
23
+ }
24
+ const isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
25
+ const isCreateClassAddon = (callee) => t.isIdentifier(callee, { name: "createReactClass" });
26
+ function isCreateClass(node) {
27
+ if (!node || !t.isCallExpression(node))
28
+ return false;
29
+ // not createReactClass nor React.createClass call member object
30
+ if (!isCreateClassCallExpression(node.callee) &&
31
+ !isCreateClassAddon(node.callee)) {
32
+ return false;
33
+ }
34
+ // no call arguments
35
+ const args = node.arguments;
36
+ if (args.length !== 1)
37
+ return false;
38
+ // first node arg is not an object
39
+ const first = args[0];
40
+ if (!t.isObjectExpression(first))
41
+ return false;
42
+ return true;
43
+ }
44
+ return {
45
+ name: "transform-react-display-name",
46
+ visitor: {
47
+ ExportDefaultDeclaration({ node }, state) {
48
+ if (isCreateClass(node.declaration)) {
49
+ const filename = state.filename || "unknown";
50
+ let displayName = path.basename(filename, path.extname(filename));
51
+ // ./{module name}/index.js
52
+ if (displayName === "index") {
53
+ displayName = path.basename(path.dirname(filename));
54
+ }
55
+ addDisplayName(displayName, node.declaration);
56
+ }
57
+ },
58
+ CallExpression(path) {
59
+ const { node } = path;
60
+ if (!isCreateClass(node))
61
+ return;
62
+ let id;
63
+ // crawl up the ancestry looking for possible candidates for displayName inference
64
+ path.find(function (path) {
65
+ if (path.isAssignmentExpression()) {
66
+ id = path.node.left;
67
+ }
68
+ else if (path.isObjectProperty()) {
69
+ id = path.node.key;
70
+ }
71
+ else if (path.isVariableDeclarator()) {
72
+ id = path.node.id;
73
+ }
74
+ else if (path.isStatement()) {
75
+ // we've hit a statement, we should stop crawling up
76
+ return true;
77
+ }
78
+ // we've got an id! no need to continue
79
+ if (id)
80
+ return true;
81
+ return false;
82
+ });
83
+ // ensure that we have an identifier we can inherit from
84
+ if (!id)
85
+ return;
86
+ // foo.bar -> bar
87
+ if (t.isMemberExpression(id)) {
88
+ id = id.property;
89
+ }
90
+ // identifiers are the only thing we can reliably get a name from
91
+ if (t.isIdentifier(id)) {
92
+ addDisplayName(id.name, node);
93
+ }
94
+ },
95
+ },
96
+ };
97
+ });
@@ -0,0 +1,8 @@
1
+ import { types as t, type NodePath } from "@babel/core";
2
+ declare const _default: (api: object, options: Record<string, any> | null | undefined, dirname: string) => {
3
+ name: string;
4
+ visitor: {
5
+ CallExpression(this: import("@babel/core").PluginPass, path: NodePath<t.CallExpression>): void;
6
+ };
7
+ };
8
+ export default _default;
@@ -0,0 +1,69 @@
1
+ import { declare } from "@babel/helper-plugin-utils";
2
+ import annotateAsPure from "../helper/annotate-as-pure";
3
+ import { types as t } from "@babel/core";
4
+ // Mapping of React top-level methods that are pure.
5
+ // This plugin adds a /*#__PURE__#/ annotation to calls to these methods,
6
+ // so that terser and other minifiers can safely remove them during dead
7
+ // code elimination.
8
+ // See https://reactjs.org/docs/react-api.html
9
+ const PURE_CALLS = [
10
+ [
11
+ "react",
12
+ new Set([
13
+ "cloneElement",
14
+ "createContext",
15
+ "createElement",
16
+ "createFactory",
17
+ "createRef",
18
+ "forwardRef",
19
+ "isValidElement",
20
+ "memo",
21
+ "lazy",
22
+ ]),
23
+ ],
24
+ ["react-dom", new Set(["createPortal"])],
25
+ ];
26
+ export default declare((api) => {
27
+ api.assertVersion(7);
28
+ return {
29
+ name: "transform-react-pure-annotations",
30
+ visitor: {
31
+ CallExpression(path) {
32
+ if (isReactCall(path)) {
33
+ annotateAsPure(path);
34
+ }
35
+ },
36
+ },
37
+ };
38
+ });
39
+ function isReactCall(path) {
40
+ // If the callee is not a member expression, then check if it matches
41
+ // a named import, e.g. `import {forwardRef} from 'react'`.
42
+ const calleePath = path.get("callee");
43
+ if (!calleePath.isMemberExpression()) {
44
+ for (const [module, methods] of PURE_CALLS) {
45
+ for (const method of methods) {
46
+ if (calleePath.referencesImport(module, method)) {
47
+ return true;
48
+ }
49
+ }
50
+ }
51
+ return false;
52
+ }
53
+ // Otherwise, check if the member expression's object matches
54
+ // a default import (`import React from 'react'`) or namespace
55
+ // import (`import * as React from 'react'), and check if the
56
+ // property matches one of the pure methods.
57
+ const object = calleePath.get("object");
58
+ const callee = calleePath.node;
59
+ if (!callee.computed && t.isIdentifier(callee.property)) {
60
+ const propertyName = callee.property.name;
61
+ for (const [module, methods] of PURE_CALLS) {
62
+ if (object.referencesImport(module, "default") ||
63
+ object.referencesImport(module, "*")) {
64
+ return methods.has(propertyName);
65
+ }
66
+ }
67
+ }
68
+ return false;
69
+ }
@@ -0,0 +1 @@
1
+ export { default } from "babel-plugin-transform-remove-imports";
@@ -0,0 +1 @@
1
+ export { default } from "babel-plugin-transform-remove-imports";
@@ -0,0 +1 @@
1
+ export { default } from "@babel/plugin-transform-runtime";
@@ -0,0 +1 @@
1
+ export { default } from "@babel/plugin-transform-runtime";
@@ -0,0 +1,2 @@
1
+ export { default } from "@babel/preset-env";
2
+ export * from "@babel/preset-env";
@@ -0,0 +1,2 @@
1
+ export { default } from "@babel/preset-env";
2
+ export * from "@babel/preset-env";
@@ -0,0 +1,14 @@
1
+ export interface Options {
2
+ development?: boolean;
3
+ developmentSourceSelf?: boolean;
4
+ importSource?: string;
5
+ pragma?: string;
6
+ pragmaFrag?: string;
7
+ pure?: string;
8
+ runtime?: "automatic" | "classic";
9
+ throwIfNamespace?: boolean;
10
+ useBuiltIns?: boolean;
11
+ useSpread?: boolean;
12
+ }
13
+ declare const _default: (api: object, options: Options | null | undefined, dirname: string) => import("@babel/core").PluginObj<import("@babel/core").PluginPass>;
14
+ export default _default;
@@ -0,0 +1,34 @@
1
+ import { declare } from "@babel/helper-plugin-utils";
2
+ import transformReactJSX from "@babel/plugin-transform-react-jsx";
3
+ import createReactJSXPlugin from "@babel/plugin-transform-react-jsx/lib/create-plugin";
4
+ import transformReactDisplayName from "../../plugin/transform-react-display-name";
5
+ import transformReactPure from "../../plugin/transform-react-pure-annotations";
6
+ import normalizeOptions from "./normalize-options";
7
+ export default declare((api, opts) => {
8
+ api.assertVersion("7");
9
+ const { development = api.env((env) => env === "development"), developmentSourceSelf, importSource, pragma, pragmaFrag, pure, runtime, throwIfNamespace, } = normalizeOptions(opts);
10
+ return {
11
+ visitor: {},
12
+ plugins: [
13
+ [
14
+ development
15
+ ? createReactJSXPlugin({
16
+ name: "transform-react-jsx/development",
17
+ development: true,
18
+ developmentSourceSelf,
19
+ })
20
+ : transformReactJSX,
21
+ {
22
+ importSource,
23
+ pragma,
24
+ pragmaFrag,
25
+ runtime,
26
+ throwIfNamespace,
27
+ pure,
28
+ },
29
+ ],
30
+ transformReactDisplayName,
31
+ pure !== false && transformReactPure,
32
+ ].filter(Boolean),
33
+ };
34
+ });
@@ -0,0 +1,10 @@
1
+ export default function normalizeOptions(options?: any): {
2
+ development: boolean;
3
+ developmentSourceSelf: boolean;
4
+ importSource: string;
5
+ pragma: string;
6
+ pragmaFrag: string;
7
+ pure: boolean;
8
+ runtime: string;
9
+ throwIfNamespace: boolean;
10
+ };
@@ -0,0 +1,60 @@
1
+ import { OptionValidator, findSuggestion } from "../../helper/validator-option";
2
+ const v = new OptionValidator("@babel/preset-react");
3
+ export default function normalizeOptions(options = {}) {
4
+ if ("useSpread" in options) {
5
+ throw new Error('@babel/preset-react: Since Babel 8, an inline object with spread elements is always used, and the "useSpread" option is no longer available. Please remove it from your config.');
6
+ }
7
+ if ("useBuiltIns" in options) {
8
+ const useBuiltInsFormatted = JSON.stringify(options.useBuiltIns);
9
+ throw new Error(`@babel/preset-react: Since "useBuiltIns" is removed in Babel 8, you can remove it from the config.
10
+ - Babel 8 now transforms JSX spread to object spread. If you need to transpile object spread with
11
+ \`useBuiltIns: ${useBuiltInsFormatted}\`, you can use the following config
12
+ {
13
+ "plugins": [
14
+ ["@babel/plugin-transform-object-rest-spread", { "loose": true, "useBuiltIns": ${useBuiltInsFormatted} }]
15
+ ],
16
+ "presets": ["@babel/preset-react"]
17
+ }`);
18
+ }
19
+ const TopLevelOptions = {
20
+ development: "development",
21
+ developmentSourceSelf: "developmentSourceSelf",
22
+ importSource: "importSource",
23
+ pragma: "pragma",
24
+ pragmaFrag: "pragmaFrag",
25
+ pure: "pure",
26
+ runtime: "runtime",
27
+ throwIfNamespace: "throwIfNamespace",
28
+ };
29
+ v.validateTopLevelOptions(options, TopLevelOptions);
30
+ const development = v.validateBooleanOption(TopLevelOptions.development, options.development);
31
+ const developmentSourceSelf = v.validateBooleanOption(TopLevelOptions.developmentSourceSelf, options.developmentSourceSelf, false);
32
+ let importSource = v.validateStringOption(TopLevelOptions.importSource, options.importSource);
33
+ let pragma = v.validateStringOption(TopLevelOptions.pragma, options.pragma);
34
+ let pragmaFrag = v.validateStringOption(TopLevelOptions.pragmaFrag, options.pragmaFrag);
35
+ const pure = v.validateBooleanOption(TopLevelOptions.pure, options.pure);
36
+ const runtime = v.validateStringOption(TopLevelOptions.runtime, options.runtime, "automatic");
37
+ const throwIfNamespace = v.validateBooleanOption(TopLevelOptions.throwIfNamespace, options.throwIfNamespace, true);
38
+ const validRuntime = ["classic", "automatic"];
39
+ if (runtime === "classic") {
40
+ pragma = pragma || "React.createElement";
41
+ pragmaFrag = pragmaFrag || "React.Fragment";
42
+ }
43
+ else if (runtime === "automatic") {
44
+ importSource = importSource || "react";
45
+ }
46
+ else {
47
+ throw new Error(`@babel/preset-react: 'runtime' must be one of ['automatic', 'classic'] but we have '${runtime}'\n` +
48
+ `- Did you mean '${findSuggestion(runtime, validRuntime)}'?`);
49
+ }
50
+ return {
51
+ development,
52
+ developmentSourceSelf,
53
+ importSource,
54
+ pragma,
55
+ pragmaFrag,
56
+ pure,
57
+ runtime,
58
+ throwIfNamespace,
59
+ };
60
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@ssets/babel",
3
+ "version": "1.0.0",
4
+ "description": "Babel for SSE SSE UI Builder",
5
+ "type": "module",
6
+ "exports": {
7
+ "./plugin/*": {
8
+ "import": "./dist/plugin/*.js",
9
+ "types": "./dist/plugin/*.d.ts"
10
+ },
11
+ "./preset/*": {
12
+ "import": "./dist/preset/*.js",
13
+ "types": "./dist/preset/*.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json"
21
+ },
22
+ "author": "SSE Official",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@babel/core": "^7.29.0",
26
+ "@babel/helper-plugin-utils": "^7.28.6",
27
+ "@babel/plugin-transform-react-jsx": "^7.28.6",
28
+ "@babel/plugin-transform-runtime": "^7.29.0",
29
+ "@babel/preset-env": "^7.29.0",
30
+ "@babel/types": "^7.29.0",
31
+ "@types/babel__plugin-transform-runtime": "^7.9.5",
32
+ "@types/babel__preset-env": "^7.10.0",
33
+ "babel-plugin-transform-remove-imports": "^1.8.1",
34
+ "resolve": "^1.22.11"
35
+ },
36
+ "devDependencies": {
37
+ "@types/babel__helper-plugin-utils": "^7.10.3"
38
+ }
39
+ }