@truewatchtech/react-native-mobile-babel-plugin 0.4.3-alpha.1
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/README.md +185 -0
- package/lib/commonjs/actions/global.js +19 -0
- package/lib/commonjs/actions/global.js.map +1 -0
- package/lib/commonjs/actions/rum/components.js +81 -0
- package/lib/commonjs/actions/rum/components.js.map +1 -0
- package/lib/commonjs/actions/rum/content.js +168 -0
- package/lib/commonjs/actions/rum/content.js.map +1 -0
- package/lib/commonjs/actions/rum/index.js +68 -0
- package/lib/commonjs/actions/rum/index.js.map +1 -0
- package/lib/commonjs/actions/rum/memoization.js +88 -0
- package/lib/commonjs/actions/rum/memoization.js.map +1 -0
- package/lib/commonjs/actions/rum/metadata.js +63 -0
- package/lib/commonjs/actions/rum/metadata.js.map +1 -0
- package/lib/commonjs/actions/rum/tap.js +45 -0
- package/lib/commonjs/actions/rum/tap.js.map +1 -0
- package/lib/commonjs/constants.js +25 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/index.js +48 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/options.js +23 -0
- package/lib/commonjs/options.js.map +1 -0
- package/lib/commonjs/state.js +32 -0
- package/lib/commonjs/state.js.map +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/utils/jsx.js +43 -0
- package/lib/commonjs/utils/jsx.js.map +1 -0
- package/lib/module/actions/global.js +13 -0
- package/lib/module/actions/global.js.map +1 -0
- package/lib/module/actions/rum/components.js +73 -0
- package/lib/module/actions/rum/components.js.map +1 -0
- package/lib/module/actions/rum/content.js +161 -0
- package/lib/module/actions/rum/content.js.map +1 -0
- package/lib/module/actions/rum/index.js +61 -0
- package/lib/module/actions/rum/index.js.map +1 -0
- package/lib/module/actions/rum/memoization.js +82 -0
- package/lib/module/actions/rum/memoization.js.map +1 -0
- package/lib/module/actions/rum/metadata.js +56 -0
- package/lib/module/actions/rum/metadata.js.map +1 -0
- package/lib/module/actions/rum/tap.js +38 -0
- package/lib/module/actions/rum/tap.js.map +1 -0
- package/lib/module/constants.js +19 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/index.js +42 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/options.js +17 -0
- package/lib/module/options.js.map +1 -0
- package/lib/module/state.js +25 -0
- package/lib/module/state.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/jsx.js +36 -0
- package/lib/module/utils/jsx.js.map +1 -0
- package/lib/typescript/actions/global.d.ts +2 -0
- package/lib/typescript/actions/rum/components.d.ts +5 -0
- package/lib/typescript/actions/rum/content.d.ts +6 -0
- package/lib/typescript/actions/rum/index.d.ts +4 -0
- package/lib/typescript/actions/rum/memoization.d.ts +4 -0
- package/lib/typescript/actions/rum/metadata.d.ts +4 -0
- package/lib/typescript/actions/rum/tap.d.ts +6 -0
- package/lib/typescript/constants.d.ts +4 -0
- package/lib/typescript/index.d.ts +5 -0
- package/lib/typescript/options.d.ts +2 -0
- package/lib/typescript/state.d.ts +5 -0
- package/lib/typescript/types.d.ts +56 -0
- package/lib/typescript/utils/jsx.d.ts +4 -0
- package/package.json +68 -0
- package/src/actions/global.ts +48 -0
- package/src/actions/rum/components.ts +128 -0
- package/src/actions/rum/content.ts +274 -0
- package/src/actions/rum/index.ts +154 -0
- package/src/actions/rum/memoization.ts +136 -0
- package/src/actions/rum/metadata.ts +147 -0
- package/src/actions/rum/tap.ts +148 -0
- package/src/constants.ts +21 -0
- package/src/index.ts +50 -0
- package/src/options.ts +26 -0
- package/src/state.ts +39 -0
- package/src/types.ts +72 -0
- package/src/utils/jsx.ts +50 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Babel from '@babel/core';
|
|
7
|
+
import type { ActionMetadata, PluginState, TrackedHandler } from '../../types';
|
|
8
|
+
import { buildTargetObject } from './metadata';
|
|
9
|
+
|
|
10
|
+
const DEFAULT_ACTION_TYPE = 'click';
|
|
11
|
+
|
|
12
|
+
function normalizeActionType(actionType: TrackedHandler['actionType']): string {
|
|
13
|
+
return typeof actionType === 'string' && actionType.trim()
|
|
14
|
+
? actionType.trim()
|
|
15
|
+
: DEFAULT_ACTION_TYPE;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function buildOriginalInvocation(
|
|
19
|
+
t: typeof Babel.types,
|
|
20
|
+
originalExpression: Babel.types.Expression,
|
|
21
|
+
argsIdentifier: Babel.types.Identifier
|
|
22
|
+
): Babel.types.OptionalCallExpression {
|
|
23
|
+
return t.optionalCallExpression(
|
|
24
|
+
t.cloneNode(originalExpression, true),
|
|
25
|
+
[t.spreadElement(t.cloneNode(argsIdentifier))],
|
|
26
|
+
true
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildImmediateHandlerWrapper(
|
|
31
|
+
t: typeof Babel.types,
|
|
32
|
+
originalExpression: Babel.types.Expression,
|
|
33
|
+
metadata: ActionMetadata,
|
|
34
|
+
state: PluginState,
|
|
35
|
+
scope: Babel.NodePath['scope'],
|
|
36
|
+
actionType: TrackedHandler['actionType']
|
|
37
|
+
): Babel.types.ArrowFunctionExpression {
|
|
38
|
+
const handlerArgsIdentifier = scope.generateUidIdentifier('ftHandlerArgs');
|
|
39
|
+
const originalArgsIdentifier = scope.generateUidIdentifier('ftOriginalArgs');
|
|
40
|
+
const originalInvoker = t.arrowFunctionExpression(
|
|
41
|
+
[t.restElement(originalArgsIdentifier)],
|
|
42
|
+
buildOriginalInvocation(t, originalExpression, originalArgsIdentifier)
|
|
43
|
+
);
|
|
44
|
+
const instanceCall = t.callExpression(
|
|
45
|
+
t.memberExpression(
|
|
46
|
+
t.cloneNode(state._ftTrackingIdentifier),
|
|
47
|
+
t.identifier('getInstance')
|
|
48
|
+
),
|
|
49
|
+
[]
|
|
50
|
+
);
|
|
51
|
+
const wrappedHandler = t.callExpression(
|
|
52
|
+
t.memberExpression(instanceCall, t.identifier('wrapRumAction')),
|
|
53
|
+
[
|
|
54
|
+
originalInvoker,
|
|
55
|
+
t.stringLiteral(normalizeActionType(actionType)),
|
|
56
|
+
buildTargetObject(t, metadata, handlerArgsIdentifier, state),
|
|
57
|
+
]
|
|
58
|
+
);
|
|
59
|
+
return t.arrowFunctionExpression(
|
|
60
|
+
[t.restElement(handlerArgsIdentifier)],
|
|
61
|
+
t.callExpression(wrappedHandler, [
|
|
62
|
+
t.spreadElement(t.cloneNode(handlerArgsIdentifier)),
|
|
63
|
+
])
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Wraps a handler, or a handler factory when delayed mode is configured. */
|
|
68
|
+
export function buildHandlerWrapper(
|
|
69
|
+
t: typeof Babel.types,
|
|
70
|
+
originalExpression: Babel.types.Expression,
|
|
71
|
+
metadata: ActionMetadata,
|
|
72
|
+
state: PluginState,
|
|
73
|
+
scope: Babel.NodePath['scope'],
|
|
74
|
+
mode: TrackedHandler['mode'] = 'default',
|
|
75
|
+
actionType?: TrackedHandler['actionType']
|
|
76
|
+
): Babel.types.ArrowFunctionExpression {
|
|
77
|
+
if (mode !== 'delayed') {
|
|
78
|
+
return buildImmediateHandlerWrapper(
|
|
79
|
+
t,
|
|
80
|
+
originalExpression,
|
|
81
|
+
metadata,
|
|
82
|
+
state,
|
|
83
|
+
scope,
|
|
84
|
+
actionType
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const factoryArgsIdentifier = scope.generateUidIdentifier('ftFactoryArgs');
|
|
89
|
+
const handlerIdentifier = scope.generateUidIdentifier('ftDelayedHandler');
|
|
90
|
+
return t.arrowFunctionExpression(
|
|
91
|
+
[t.restElement(factoryArgsIdentifier)],
|
|
92
|
+
t.blockStatement([
|
|
93
|
+
t.variableDeclaration('const', [
|
|
94
|
+
t.variableDeclarator(
|
|
95
|
+
handlerIdentifier,
|
|
96
|
+
buildOriginalInvocation(t, originalExpression, factoryArgsIdentifier)
|
|
97
|
+
),
|
|
98
|
+
]),
|
|
99
|
+
t.returnStatement(
|
|
100
|
+
buildImmediateHandlerWrapper(
|
|
101
|
+
t,
|
|
102
|
+
handlerIdentifier,
|
|
103
|
+
metadata,
|
|
104
|
+
state,
|
|
105
|
+
scope,
|
|
106
|
+
actionType
|
|
107
|
+
)
|
|
108
|
+
),
|
|
109
|
+
])
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Resolves a conditional handler once at render time, preserving non-functions. */
|
|
114
|
+
export function buildGuardedHandlerWrapper(
|
|
115
|
+
t: typeof Babel.types,
|
|
116
|
+
originalExpression: Babel.types.Expression,
|
|
117
|
+
metadata: ActionMetadata,
|
|
118
|
+
state: PluginState,
|
|
119
|
+
scope: Babel.NodePath['scope'],
|
|
120
|
+
mode: TrackedHandler['mode'] = 'default',
|
|
121
|
+
actionType?: TrackedHandler['actionType']
|
|
122
|
+
): Babel.types.CallExpression {
|
|
123
|
+
const resolvedHandlerIdentifier =
|
|
124
|
+
scope.generateUidIdentifier('ftResolvedHandler');
|
|
125
|
+
return t.callExpression(
|
|
126
|
+
t.arrowFunctionExpression(
|
|
127
|
+
[resolvedHandlerIdentifier],
|
|
128
|
+
t.conditionalExpression(
|
|
129
|
+
t.binaryExpression(
|
|
130
|
+
'===',
|
|
131
|
+
t.unaryExpression('typeof', t.cloneNode(resolvedHandlerIdentifier)),
|
|
132
|
+
t.stringLiteral('function')
|
|
133
|
+
),
|
|
134
|
+
buildHandlerWrapper(
|
|
135
|
+
t,
|
|
136
|
+
resolvedHandlerIdentifier,
|
|
137
|
+
metadata,
|
|
138
|
+
state,
|
|
139
|
+
scope,
|
|
140
|
+
mode,
|
|
141
|
+
actionType
|
|
142
|
+
),
|
|
143
|
+
t.cloneNode(resolvedHandlerIdentifier)
|
|
144
|
+
)
|
|
145
|
+
),
|
|
146
|
+
[t.cloneNode(originalExpression, true)]
|
|
147
|
+
);
|
|
148
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const RUNTIME_PACKAGE = '@truewatchtech/react-native-mobile';
|
|
7
|
+
|
|
8
|
+
export const ACTION_NAME_ATTRIBUTE = 'ft-action-name';
|
|
9
|
+
|
|
10
|
+
export const PLUGIN_ENABLED_FLAG = '__FT_RN_BABEL_PLUGIN_ENABLED__';
|
|
11
|
+
|
|
12
|
+
export const NATIVE_COMPONENT_HANDLERS: Record<string, string[]> = {
|
|
13
|
+
Button: ['onPress'],
|
|
14
|
+
Pressable: ['onPress', 'onLongPress'],
|
|
15
|
+
TouchableOpacity: ['onPress'],
|
|
16
|
+
TouchableHighlight: ['onPress'],
|
|
17
|
+
TouchableWithoutFeedback: ['onPress'],
|
|
18
|
+
TouchableNativeFeedback: ['onPress'],
|
|
19
|
+
Switch: ['onValueChange'],
|
|
20
|
+
TextInput: ['onFocus'],
|
|
21
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Babel from '@babel/core';
|
|
7
|
+
import { declare } from '@babel/helper-plugin-utils';
|
|
8
|
+
import { insertPluginEnabledFlag } from './actions/global';
|
|
9
|
+
import { handleJSXElement, insertRuntimeImports } from './actions/rum';
|
|
10
|
+
import { mergeOptions } from './options';
|
|
11
|
+
import { initializePluginState, isSkippedFile } from './state';
|
|
12
|
+
import type { PluginAPI, PluginOptions, PluginState } from './types';
|
|
13
|
+
|
|
14
|
+
export type { PluginOptions, TrackedComponent, TrackedHandler } from './types';
|
|
15
|
+
|
|
16
|
+
const plugin = declare(
|
|
17
|
+
(api: PluginAPI, rawOptions: PluginOptions): Babel.PluginObj<PluginState> => {
|
|
18
|
+
api.assertVersion(7);
|
|
19
|
+
const t = api.types;
|
|
20
|
+
const options = mergeOptions(rawOptions);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
name: 'truewatch-react-native-action-name',
|
|
24
|
+
visitor: {
|
|
25
|
+
Program: {
|
|
26
|
+
enter(programPath, state) {
|
|
27
|
+
state._ftSkip = isSkippedFile(state);
|
|
28
|
+
if (state._ftSkip) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
initializePluginState(t, programPath, state, options);
|
|
32
|
+
insertPluginEnabledFlag(t, programPath);
|
|
33
|
+
},
|
|
34
|
+
exit(programPath, state) {
|
|
35
|
+
if (!state._ftSkip) {
|
|
36
|
+
insertRuntimeImports(t, programPath, state);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
JSXElement(path, state) {
|
|
41
|
+
if (!state._ftSkip) {
|
|
42
|
+
handleJSXElement(t, path, state, options);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export default plugin;
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NormalizedPluginOptions, PluginOptions } from './types';
|
|
7
|
+
|
|
8
|
+
export function mergeOptions(
|
|
9
|
+
options: PluginOptions = {}
|
|
10
|
+
): NormalizedPluginOptions {
|
|
11
|
+
const componentOptions = options.components || {};
|
|
12
|
+
return {
|
|
13
|
+
actionNameAttribute: options.actionNameAttribute,
|
|
14
|
+
components: {
|
|
15
|
+
tracked: componentOptions.tracked || [],
|
|
16
|
+
useContent:
|
|
17
|
+
componentOptions.useContent === undefined
|
|
18
|
+
? true
|
|
19
|
+
: componentOptions.useContent,
|
|
20
|
+
useNamePrefix:
|
|
21
|
+
componentOptions.useNamePrefix === undefined
|
|
22
|
+
? true
|
|
23
|
+
: componentOptions.useNamePrefix,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
package/src/state.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Babel from '@babel/core';
|
|
7
|
+
import { createTrackedComponents } from './actions/rum/components';
|
|
8
|
+
import type { NormalizedPluginOptions, PluginState } from './types';
|
|
9
|
+
|
|
10
|
+
export function isSkippedFile(state: PluginState): boolean {
|
|
11
|
+
const caller = state.file?.opts?.caller as { platform?: string } | undefined;
|
|
12
|
+
const filename = state.filename || state.file?.opts?.filename;
|
|
13
|
+
return (
|
|
14
|
+
caller?.platform === 'web' ||
|
|
15
|
+
Boolean(filename && filename.includes('node_modules'))
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Initializes per-file state; identifiers and memoization never leak across files. */
|
|
20
|
+
export function initializePluginState(
|
|
21
|
+
t: typeof Babel.types,
|
|
22
|
+
programPath: Babel.NodePath<Babel.types.Program>,
|
|
23
|
+
state: PluginState,
|
|
24
|
+
options: NormalizedPluginOptions
|
|
25
|
+
): void {
|
|
26
|
+
state._ftTrackedComponents = createTrackedComponents(t, programPath, options);
|
|
27
|
+
state._ftCustomNames = new Set(
|
|
28
|
+
options.components.tracked.map((component) => component.name)
|
|
29
|
+
);
|
|
30
|
+
state._ftMemoizedHandlers = new Set();
|
|
31
|
+
state._ftHasWrappedAction = false;
|
|
32
|
+
state._ftNeedsContentRuntime = false;
|
|
33
|
+
state._ftExtractTextIdentifier =
|
|
34
|
+
programPath.scope.generateUidIdentifier('ftExtractText');
|
|
35
|
+
state._ftReactIdentifier = programPath.scope.generateUidIdentifier('FTReact');
|
|
36
|
+
state._ftTrackingIdentifier = programPath.scope.generateUidIdentifier(
|
|
37
|
+
'FTBabelInteractionTracking'
|
|
38
|
+
);
|
|
39
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Babel from '@babel/core';
|
|
7
|
+
|
|
8
|
+
export type TrackedHandler = {
|
|
9
|
+
event: string;
|
|
10
|
+
actionType?: string;
|
|
11
|
+
mode?: 'default' | 'delayed';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type TrackedComponent = {
|
|
15
|
+
name: string;
|
|
16
|
+
useContent?: boolean;
|
|
17
|
+
useNamePrefix?: boolean;
|
|
18
|
+
contentProp?: string;
|
|
19
|
+
handlers: TrackedHandler[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type PluginOptions = {
|
|
23
|
+
actionNameAttribute?: string;
|
|
24
|
+
components?: {
|
|
25
|
+
useContent?: boolean;
|
|
26
|
+
useNamePrefix?: boolean;
|
|
27
|
+
tracked?: TrackedComponent[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type NormalizedPluginOptions = {
|
|
32
|
+
actionNameAttribute?: string;
|
|
33
|
+
components: {
|
|
34
|
+
useContent: boolean;
|
|
35
|
+
useNamePrefix: boolean;
|
|
36
|
+
tracked: TrackedComponent[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type TrackedComponentData = Omit<TrackedComponent, 'name'> & {
|
|
41
|
+
importedName?: string;
|
|
42
|
+
isCustom: boolean;
|
|
43
|
+
useContent: boolean;
|
|
44
|
+
useNamePrefix: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type ActionMetadata = {
|
|
48
|
+
accessibilityLabels: Babel.types.StringLiteral[];
|
|
49
|
+
actionNames: Babel.types.StringLiteral[];
|
|
50
|
+
component: TrackedComponentData;
|
|
51
|
+
componentName: string;
|
|
52
|
+
customActionNames: Babel.types.StringLiteral[];
|
|
53
|
+
getContent: Babel.types.ArrowFunctionExpression | null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type PluginState = Babel.PluginPass & {
|
|
57
|
+
_ftCustomNames: Set<string>;
|
|
58
|
+
_ftExtractTextIdentifier: Babel.types.Identifier;
|
|
59
|
+
_ftHasWrappedAction: boolean;
|
|
60
|
+
_ftMemoizedHandlers: Set<Babel.types.Node>;
|
|
61
|
+
_ftNeedsContentRuntime: boolean;
|
|
62
|
+
_ftReactIdentifier: Babel.types.Identifier;
|
|
63
|
+
_ftSkip: boolean;
|
|
64
|
+
_ftTrackedComponents: Record<string, TrackedComponentData>;
|
|
65
|
+
_ftTrackingIdentifier: Babel.types.Identifier;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type PluginAPI = typeof Babel & Babel.ConfigAPI;
|
|
69
|
+
|
|
70
|
+
export type JSXAttributePath = Babel.NodePath<
|
|
71
|
+
Babel.types.JSXAttribute | Babel.types.JSXSpreadAttribute
|
|
72
|
+
>;
|
package/src/utils/jsx.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions of this file are adapted from Datadog's dd-sdk-reactnative Babel
|
|
3
|
+
* interaction tracking implementation, licensed under Apache-2.0.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Babel from '@babel/core';
|
|
7
|
+
import type { JSXAttributePath } from '../types';
|
|
8
|
+
|
|
9
|
+
export function getNodeName(
|
|
10
|
+
t: typeof Babel.types,
|
|
11
|
+
node: Babel.types.Node | null | undefined
|
|
12
|
+
): string | null {
|
|
13
|
+
if (!node) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (t.isIdentifier(node) || t.isJSXIdentifier(node)) {
|
|
17
|
+
return node.name;
|
|
18
|
+
}
|
|
19
|
+
if (t.isStringLiteral(node)) {
|
|
20
|
+
return node.value;
|
|
21
|
+
}
|
|
22
|
+
if (t.isJSXNamespacedName(node)) {
|
|
23
|
+
return `${node.namespace.name}:${node.name.name}`;
|
|
24
|
+
}
|
|
25
|
+
if (t.isJSXMemberExpression(node)) {
|
|
26
|
+
let nodeName = node.property.name;
|
|
27
|
+
let nodeTracker:
|
|
28
|
+
| Babel.types.JSXIdentifier
|
|
29
|
+
| Babel.types.JSXMemberExpression = node.object;
|
|
30
|
+
|
|
31
|
+
while (t.isJSXMemberExpression(nodeTracker)) {
|
|
32
|
+
nodeName = `${nodeTracker.property.name}.${nodeName}`;
|
|
33
|
+
nodeTracker = nodeTracker.object;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return t.isJSXIdentifier(nodeTracker)
|
|
37
|
+
? `${nodeTracker.name}.${nodeName}`
|
|
38
|
+
: null;
|
|
39
|
+
}
|
|
40
|
+
if ('name' in node && node.name && typeof node.name !== 'string') {
|
|
41
|
+
return getNodeName(t, node.name);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getDirectAttributePaths(
|
|
47
|
+
path: Babel.NodePath<Babel.types.JSXElement>
|
|
48
|
+
): JSXAttributePath[] {
|
|
49
|
+
return path.get('openingElement.attributes') as JSXAttributePath[];
|
|
50
|
+
}
|