@atlaskit/form 12.1.1 → 12.2.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/CHANGELOG.md +16 -0
- package/codemods/__tests__/not-yet-migrate-to-simplified-form.test.tsx +613 -0
- package/codemods/not-yet-migrate-to-simplified-form.tsx +173 -0
- package/codemods/utils/helpers.tsx +327 -0
- package/dist/cjs/form.js +16 -8
- package/dist/es2019/form.js +18 -8
- package/dist/esm/form.js +16 -8
- package/dist/types/form.d.ts +13 -0
- package/dist/types-ts4.5/form.d.ts +13 -0
- package/package.json +12 -8
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type API,
|
|
3
|
+
type FileInfo,
|
|
4
|
+
type JSCodeshift,
|
|
5
|
+
type JSXElement,
|
|
6
|
+
type Options,
|
|
7
|
+
type Property,
|
|
8
|
+
} from 'jscodeshift';
|
|
9
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
addJSXAttributeToJSXElement,
|
|
13
|
+
getImportDeclarationCollection,
|
|
14
|
+
getImportDefaultSpecifierCollection,
|
|
15
|
+
getImportDefaultSpecifierName,
|
|
16
|
+
hasImportDeclaration,
|
|
17
|
+
} from './utils/helpers';
|
|
18
|
+
|
|
19
|
+
const importPath = '@atlaskit/form';
|
|
20
|
+
|
|
21
|
+
const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
22
|
+
const importDeclarationCollection = getImportDeclarationCollection(j, collection, importPath);
|
|
23
|
+
const defaultImport = getImportDefaultSpecifierCollection(j, importDeclarationCollection);
|
|
24
|
+
const defaultImportName = getImportDefaultSpecifierName(defaultImport);
|
|
25
|
+
|
|
26
|
+
// if no default import is present, exit early
|
|
27
|
+
if (defaultImportName === null) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
collection.findJSXElements(defaultImportName).forEach((jsxElementPath) => {
|
|
32
|
+
const node = jsxElementPath.node;
|
|
33
|
+
// If no children, exit early
|
|
34
|
+
if (!node.children || node.children.length === 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// if component but child is not a function, exit early
|
|
39
|
+
const children = node.children.filter((child) => child.type === 'JSXExpressionContainer');
|
|
40
|
+
if (children.length === 0 || children.length > 1) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If expression child is not a function, exit early
|
|
45
|
+
const childFunction = children[0];
|
|
46
|
+
if (
|
|
47
|
+
childFunction.type !== 'JSXExpressionContainer' ||
|
|
48
|
+
childFunction.expression.type !== 'ArrowFunctionExpression'
|
|
49
|
+
) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// if function child but more than just `fieldProps`, exit early
|
|
54
|
+
const args = childFunction.expression.params
|
|
55
|
+
.filter((arg) => arg.type === 'ObjectPattern' && 'properties' in arg)
|
|
56
|
+
.flatMap((arg) => arg.properties)
|
|
57
|
+
.filter((property) => property.type === 'ObjectProperty');
|
|
58
|
+
if (
|
|
59
|
+
args.length !== 1 ||
|
|
60
|
+
args[0].key.type !== 'Identifier' ||
|
|
61
|
+
args[0].value.type !== 'Identifier'
|
|
62
|
+
) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (args[0].key.name !== 'formProps') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// This is the name that is used within, e.g. if something like
|
|
70
|
+
// `{({ formProps: fooBar }) => ()}` is used, this will be `fooBar`
|
|
71
|
+
const argName = args[0].value.name;
|
|
72
|
+
|
|
73
|
+
// get HTML form inside the child function
|
|
74
|
+
const body = childFunction.expression.body;
|
|
75
|
+
let htmlForm: JSXElement | null = null;
|
|
76
|
+
const q: any[] = [body];
|
|
77
|
+
while (q.length > 0) {
|
|
78
|
+
// pop child from end of q
|
|
79
|
+
const child = q.pop();
|
|
80
|
+
// if children, add children to q
|
|
81
|
+
if (!child || child.type !== 'JSXElement') {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
child.children?.forEach((el: any) => q.push(el));
|
|
85
|
+
// if child is a JSXElement with an openingElement of `form`, save to htmlForm and exit loop
|
|
86
|
+
if (child.type === 'JSXElement' && child.openingElement.name.name === 'form') {
|
|
87
|
+
htmlForm = child;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// if no HTML form, exit early
|
|
93
|
+
if (htmlForm === null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// make new object and add each attribute on HTML `form` that is not a spread of `formProps` to new object
|
|
98
|
+
let otherSpreadPropsSeen = false;
|
|
99
|
+
// We are required to do it this way instead of a map to make the types work correctly.
|
|
100
|
+
const nonFormPropsAttributes: Property[] = [];
|
|
101
|
+
htmlForm?.openingElement?.attributes?.forEach((attr) => {
|
|
102
|
+
if (otherSpreadPropsSeen) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
107
|
+
if (attr.argument.type === 'Identifier' && attr.argument.name === argName) {
|
|
108
|
+
return;
|
|
109
|
+
} else {
|
|
110
|
+
otherSpreadPropsSeen = true;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (attr.name.type !== 'JSXIdentifier') {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (attr.value === undefined) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let value;
|
|
124
|
+
if (attr.value === null) {
|
|
125
|
+
value = j.nullLiteral();
|
|
126
|
+
} else {
|
|
127
|
+
value = attr.value;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
nonFormPropsAttributes.push(j.property('init', attr.name, value));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// We don't know how to handle other spread props in the formProps object, so ignore it
|
|
134
|
+
if (otherSpreadPropsSeen) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (nonFormPropsAttributes.length !== 0) {
|
|
139
|
+
// make new attribute for parent `Form` default import called `formProps` and set new attribute to new object
|
|
140
|
+
const formPropsAttr = j.jsxAttribute(
|
|
141
|
+
j.jsxIdentifier('formProps'),
|
|
142
|
+
j.jsxExpressionContainer(j.objectExpression(nonFormPropsAttributes.filter(Boolean))),
|
|
143
|
+
);
|
|
144
|
+
addJSXAttributeToJSXElement(j, jsxElementPath, formPropsAttr, 1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// replace functional child with inner (all children of HTML `form`)
|
|
148
|
+
const htmlFormChildren = htmlForm.children?.filter((child) => child.type !== 'JSXText');
|
|
149
|
+
if (!htmlFormChildren) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
node.children.splice(0);
|
|
154
|
+
node.children.splice(0, 0, ...htmlFormChildren);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default function transformer(fileInfo: FileInfo, { jscodeshift: j }: API, options: Options) {
|
|
161
|
+
const { source } = fileInfo;
|
|
162
|
+
const collection = j(source);
|
|
163
|
+
|
|
164
|
+
// If our component is not here, skip the file
|
|
165
|
+
if (!hasImportDeclaration(j, collection, importPath)) {
|
|
166
|
+
return source;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Convert form if possible
|
|
170
|
+
convertToSimpleForm(j, collection);
|
|
171
|
+
|
|
172
|
+
return collection.toSource(options.printOptions || { quote: 'single' });
|
|
173
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ASTPath,
|
|
3
|
+
CallExpression,
|
|
4
|
+
default as core,
|
|
5
|
+
Identifier,
|
|
6
|
+
ImportDeclaration,
|
|
7
|
+
ImportDefaultSpecifier,
|
|
8
|
+
ImportSpecifier,
|
|
9
|
+
JSCodeshift,
|
|
10
|
+
JSXAttribute,
|
|
11
|
+
JSXElement,
|
|
12
|
+
ObjectProperty,
|
|
13
|
+
StringLiteral,
|
|
14
|
+
} from 'jscodeshift';
|
|
15
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
16
|
+
|
|
17
|
+
import { addCommentToStartOfFile, getNamedSpecifier } from '@atlaskit/codemod-utils';
|
|
18
|
+
|
|
19
|
+
export function hasImportDeclaration(
|
|
20
|
+
j: JSCodeshift,
|
|
21
|
+
collection: Collection<any>,
|
|
22
|
+
importPath: string,
|
|
23
|
+
) {
|
|
24
|
+
return getImportDeclarationCollection(j, collection, importPath).length > 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getImportDeclarationCollection(
|
|
28
|
+
j: JSCodeshift,
|
|
29
|
+
collection: Collection<any>,
|
|
30
|
+
importPath: string,
|
|
31
|
+
) {
|
|
32
|
+
return collection
|
|
33
|
+
.find(j.ImportDeclaration)
|
|
34
|
+
.filter((importDeclarationPath) => importDeclarationPath.node.source.value === importPath);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function hasDynamicImport(j: JSCodeshift, collection: Collection<any>, importPath: string) {
|
|
38
|
+
return getDynamicImportCollection(j, collection, importPath).length > 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getDynamicImportCollection(
|
|
42
|
+
j: JSCodeshift,
|
|
43
|
+
collection: Collection<any>,
|
|
44
|
+
importPath: string,
|
|
45
|
+
) {
|
|
46
|
+
return collection.find(j.CallExpression).filter((callExpressionPath) => {
|
|
47
|
+
const { callee, arguments: callExpressionArguments } = callExpressionPath.node;
|
|
48
|
+
|
|
49
|
+
return !!(
|
|
50
|
+
isCallExpressionCalleeImportType(callee) &&
|
|
51
|
+
isCallExpressionArgumentStringLiteralType(callExpressionArguments) &&
|
|
52
|
+
isCallExpressionArgumentValueMatches(callExpressionArguments[0], j, importPath)
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function isCallExpressionCalleeImportType(callee: CallExpression['callee']) {
|
|
57
|
+
return callee && callee.type === 'Import';
|
|
58
|
+
}
|
|
59
|
+
function isCallExpressionArgumentStringLiteralType(
|
|
60
|
+
callExpressionArguments: CallExpression['arguments'],
|
|
61
|
+
) {
|
|
62
|
+
return (
|
|
63
|
+
callExpressionArguments &&
|
|
64
|
+
callExpressionArguments.length &&
|
|
65
|
+
callExpressionArguments[0].type === 'StringLiteral'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function isCallExpressionArgumentValueMatches(
|
|
69
|
+
callExpressionArgument: CallExpression['arguments'][0],
|
|
70
|
+
j: JSCodeshift,
|
|
71
|
+
value: string,
|
|
72
|
+
) {
|
|
73
|
+
return j(callExpressionArgument).some((path) => path.node.value === value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getImportDefaultSpecifierCollection(
|
|
77
|
+
j: JSCodeshift,
|
|
78
|
+
importDeclarationCollection: Collection<ImportDeclaration>,
|
|
79
|
+
) {
|
|
80
|
+
return importDeclarationCollection.find(j.ImportDefaultSpecifier);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getImportSpecifierCollection(
|
|
84
|
+
j: JSCodeshift,
|
|
85
|
+
importDeclarationCollection: Collection<ImportDeclaration>,
|
|
86
|
+
importName: string,
|
|
87
|
+
) {
|
|
88
|
+
return importDeclarationCollection
|
|
89
|
+
.find(j.ImportSpecifier)
|
|
90
|
+
.filter((importSpecifierPath) => importSpecifierPath.node.imported.name === importName);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getImportDefaultSpecifierName(
|
|
94
|
+
importSpecifierCollection: Collection<ImportDefaultSpecifier>,
|
|
95
|
+
) {
|
|
96
|
+
if (importSpecifierCollection.length === 0) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return importSpecifierCollection.nodes()[0]!.local!.name;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getImportSpecifierName(importSpecifierCollection: Collection<ImportSpecifier>) {
|
|
104
|
+
if (importSpecifierCollection.length === 0) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return importSpecifierCollection.nodes()[0]!.local!.name;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function isVariableDeclaratorIdentifierPresent(
|
|
112
|
+
j: JSCodeshift,
|
|
113
|
+
collection: Collection<any>,
|
|
114
|
+
variableName: string,
|
|
115
|
+
) {
|
|
116
|
+
return collection
|
|
117
|
+
.find(j.VariableDeclaration)
|
|
118
|
+
.find(j.VariableDeclarator)
|
|
119
|
+
.some((variableDeclaratorPath) => {
|
|
120
|
+
const { id } = variableDeclaratorPath.node;
|
|
121
|
+
|
|
122
|
+
return !!(id && id.type === 'Identifier' && (id as Identifier).name === variableName);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function isFunctionDeclarationIdentifierPresent(
|
|
127
|
+
j: JSCodeshift,
|
|
128
|
+
collection: Collection<any>,
|
|
129
|
+
variableName: string,
|
|
130
|
+
) {
|
|
131
|
+
return collection.find(j.FunctionDeclaration).some((functionDeclarationPath) => {
|
|
132
|
+
const { id } = functionDeclarationPath.node;
|
|
133
|
+
|
|
134
|
+
return !!(id && id.type === 'Identifier' && (id as Identifier).name === variableName);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function isClassDeclarationIdentifierPresent(
|
|
139
|
+
j: JSCodeshift,
|
|
140
|
+
collection: Collection<any>,
|
|
141
|
+
variableName: string,
|
|
142
|
+
) {
|
|
143
|
+
return collection.find(j.ClassDeclaration).some((classDeclarationPath) => {
|
|
144
|
+
const { id } = classDeclarationPath.node;
|
|
145
|
+
|
|
146
|
+
return !!(id && id.type === 'Identifier' && (id as Identifier).name === variableName);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function isImportDeclarationIdentifierPresent(
|
|
151
|
+
j: JSCodeshift,
|
|
152
|
+
collection: Collection<any>,
|
|
153
|
+
variableName: string,
|
|
154
|
+
) {
|
|
155
|
+
return collection
|
|
156
|
+
.find(j.ImportDeclaration)
|
|
157
|
+
.find(j.Identifier)
|
|
158
|
+
.some((identifierPath) => identifierPath.node.name === variableName);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function getJSXAttributesByName(
|
|
162
|
+
j: JSCodeshift,
|
|
163
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
164
|
+
attributeName: string,
|
|
165
|
+
): Collection<JSXAttribute> {
|
|
166
|
+
return j(jsxElementPath)
|
|
167
|
+
.find(j.JSXOpeningElement)
|
|
168
|
+
.find(j.JSXAttribute)
|
|
169
|
+
.filter((jsxAttributePath) =>
|
|
170
|
+
j(jsxAttributePath)
|
|
171
|
+
.find(j.JSXIdentifier)
|
|
172
|
+
.some((jsxIdentifierPath) => jsxIdentifierPath.node.name === attributeName),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function getJSXSpreadIdentifierAttributesByName(
|
|
177
|
+
j: JSCodeshift,
|
|
178
|
+
collection: Collection<any>,
|
|
179
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
180
|
+
attributeName: string,
|
|
181
|
+
): Collection<ObjectProperty> | null {
|
|
182
|
+
const identifierCollection = j(jsxElementPath)
|
|
183
|
+
.find(j.JSXOpeningElement)
|
|
184
|
+
.find(j.JSXSpreadAttribute)
|
|
185
|
+
.filter((jsxSpreadAttributePath) => jsxSpreadAttributePath.node.argument.type === 'Identifier')
|
|
186
|
+
.find(j.Identifier);
|
|
187
|
+
|
|
188
|
+
if (identifierCollection.length === 0) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return collection
|
|
193
|
+
.find(j.VariableDeclarator)
|
|
194
|
+
.filter((variableDeclaratorPath) => {
|
|
195
|
+
const { id } = variableDeclaratorPath.node;
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
id.type === 'Identifier' &&
|
|
199
|
+
identifierCollection.some((identifierPath) => identifierPath.node.name === id.name)
|
|
200
|
+
);
|
|
201
|
+
})
|
|
202
|
+
.find(j.ObjectExpression)
|
|
203
|
+
.find(j.ObjectProperty)
|
|
204
|
+
.filter((objectPropertyPath) =>
|
|
205
|
+
j(objectPropertyPath)
|
|
206
|
+
.find(j.Identifier)
|
|
207
|
+
.some((identifierPath) => identifierPath.node.name === attributeName),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function getJSXSpreadObjectExpressionAttributesByName(
|
|
212
|
+
j: JSCodeshift,
|
|
213
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
214
|
+
attributeName: string,
|
|
215
|
+
) {
|
|
216
|
+
return j(jsxElementPath)
|
|
217
|
+
.find(j.JSXOpeningElement)
|
|
218
|
+
.find(j.JSXSpreadAttribute)
|
|
219
|
+
.find(j.ObjectExpression)
|
|
220
|
+
.find(j.ObjectProperty)
|
|
221
|
+
.filter((objectPropertyPath) =>
|
|
222
|
+
j(objectPropertyPath)
|
|
223
|
+
.find(j.Identifier)
|
|
224
|
+
.some((identifierPath) => identifierPath.node.name === attributeName),
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const createRemoveFuncFor =
|
|
229
|
+
(component: string, importName: string, prop: string, comment?: string) =>
|
|
230
|
+
(j: core.JSCodeshift, source: Collection<Node>) => {
|
|
231
|
+
const specifier = getNamedSpecifier(j, source, component, importName);
|
|
232
|
+
|
|
233
|
+
if (!specifier) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
source.findJSXElements(specifier).forEach((element) => {
|
|
238
|
+
getJSXAttributesByName(j, element, prop).forEach((attribute: any) => {
|
|
239
|
+
j(attribute).remove();
|
|
240
|
+
if (comment) {
|
|
241
|
+
addCommentToStartOfFile({ j, base: source, message: comment });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export const getJSXAttributeByName = (
|
|
248
|
+
j: JSCodeshift,
|
|
249
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
250
|
+
attributeName: string,
|
|
251
|
+
): JSXAttribute | undefined => {
|
|
252
|
+
const attributes: JSXAttribute[] = j(jsxElementPath).find(j.JSXAttribute).nodes();
|
|
253
|
+
|
|
254
|
+
return attributes?.find((attr) => attr.name && attr.name.name === attributeName);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export const addJSXAttributeToJSXElement = (
|
|
258
|
+
j: JSCodeshift,
|
|
259
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
260
|
+
jsxAttribute: JSXAttribute,
|
|
261
|
+
limit?: number,
|
|
262
|
+
) => {
|
|
263
|
+
j(jsxElementPath)
|
|
264
|
+
.find(j.JSXOpeningElement)
|
|
265
|
+
.forEach((openingElement, i) => {
|
|
266
|
+
if (!limit || i < limit) {
|
|
267
|
+
openingElement.node.attributes?.push(jsxAttribute);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export const removeJSXAttributeByName = (
|
|
273
|
+
j: JSCodeshift,
|
|
274
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
275
|
+
attrName: string,
|
|
276
|
+
) => {
|
|
277
|
+
const attributes = getJSXAttributes(jsxElementPath);
|
|
278
|
+
const attr = getJSXAttributeByName(j, jsxElementPath, attrName);
|
|
279
|
+
if (attr) {
|
|
280
|
+
attributes?.splice(attributes.indexOf(attr), 1);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
export const getJSXAttributes = (jsxElementPath: ASTPath<JSXElement>) =>
|
|
285
|
+
jsxElementPath.node.openingElement.attributes as JSXAttribute[];
|
|
286
|
+
|
|
287
|
+
export const removeJSXAttributeObjectPropertyByName = (
|
|
288
|
+
j: JSCodeshift,
|
|
289
|
+
jsxElementPath: ASTPath<JSXElement>,
|
|
290
|
+
attrName: string,
|
|
291
|
+
propertyToRemove: string,
|
|
292
|
+
) => {
|
|
293
|
+
const attr = getJSXAttributeByName(j, jsxElementPath, attrName);
|
|
294
|
+
|
|
295
|
+
if (!attr) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const attrCollection = getJSXAttributesByName(j, jsxElementPath, attrName);
|
|
300
|
+
|
|
301
|
+
const removeMatchingNodes = (p: ASTPath<Identifier | StringLiteral>) => {
|
|
302
|
+
const name = p.node.type === 'Identifier' ? p.node?.name : p.node?.value;
|
|
303
|
+
// Need to account for quoted properties
|
|
304
|
+
const nameMatches = propertyToRemove.match(new RegExp(`['"]?${name}['"]?`));
|
|
305
|
+
// This will otherwise try to remove values of properties since they are literals
|
|
306
|
+
const isKey = p.parent.value?.type === 'ObjectProperty';
|
|
307
|
+
// Sorry about all the parents. This is the easiest way to get the name
|
|
308
|
+
// of the attribute name. And I always know the depth of the object
|
|
309
|
+
// property here.
|
|
310
|
+
const parentNameMatches = attrName === p.parent.parent.parent.parent.node?.name?.name;
|
|
311
|
+
if (isKey && nameMatches && parentNameMatches) {
|
|
312
|
+
j(p.parent).remove();
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// Remove all the now migrated object properties
|
|
317
|
+
const objectProperties = attrCollection.find(j.ObjectProperty);
|
|
318
|
+
objectProperties.find(j.Identifier).forEach(removeMatchingNodes);
|
|
319
|
+
objectProperties.find(j.StringLiteral).forEach(removeMatchingNodes);
|
|
320
|
+
|
|
321
|
+
// @ts-ignore -- Property 'expression' does not exist on type 'LiteralKind | JSXElement | JSXExpressionContainer | JSXFragment'. Property 'expression' does not exist on type 'Literal'.
|
|
322
|
+
const attrProperties = attr.value?.expression.properties;
|
|
323
|
+
|
|
324
|
+
if (attrProperties && attrProperties?.length === 0) {
|
|
325
|
+
removeJSXAttributeByName(j, jsxElementPath, attrName);
|
|
326
|
+
}
|
|
327
|
+
};
|
package/dist/cjs/form.js
CHANGED
|
@@ -7,11 +7,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
});
|
|
8
8
|
exports.IsDisabledContext = exports.FormContext = void 0;
|
|
9
9
|
exports.default = Form;
|
|
10
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
10
11
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
13
|
var _finalForm = require("final-form");
|
|
13
14
|
var _finalFormFocus = _interopRequireDefault(require("final-form-focus"));
|
|
14
15
|
var _set = _interopRequireDefault(require("lodash/set"));
|
|
16
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
15
17
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
16
18
|
/**
|
|
17
19
|
* __Form context__
|
|
@@ -37,9 +39,11 @@ var FormContext = exports.FormContext = /*#__PURE__*/(0, _react.createContext)({
|
|
|
37
39
|
*/
|
|
38
40
|
var IsDisabledContext = exports.IsDisabledContext = /*#__PURE__*/(0, _react.createContext)(false);
|
|
39
41
|
function Form(props) {
|
|
42
|
+
var userProvidedFormProps = props.formProps,
|
|
43
|
+
onSubmit = props.onSubmit;
|
|
40
44
|
var formRef = (0, _react.useRef)(null);
|
|
41
|
-
var onSubmitRef = (0, _react.useRef)(
|
|
42
|
-
onSubmitRef.current =
|
|
45
|
+
var onSubmitRef = (0, _react.useRef)(onSubmit);
|
|
46
|
+
onSubmitRef.current = onSubmit;
|
|
43
47
|
var _useState = (0, _react.useState)(function () {
|
|
44
48
|
// Types here would break the existing API
|
|
45
49
|
var finalForm = (0, _finalForm.createForm)({
|
|
@@ -137,14 +141,17 @@ function Form(props) {
|
|
|
137
141
|
subscribe: form.subscribe
|
|
138
142
|
};
|
|
139
143
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
144
|
+
|
|
145
|
+
// Abstracting so we can use the same for both rendering patterns
|
|
146
|
+
var formProps = {
|
|
147
|
+
onKeyDown: handleKeyDown,
|
|
148
|
+
onSubmit: handleSubmit,
|
|
149
|
+
ref: formRef
|
|
150
|
+
};
|
|
140
151
|
var childrenContent = function () {
|
|
141
152
|
if (typeof children === 'function') {
|
|
142
153
|
var result = children.length > 0 ? children({
|
|
143
|
-
formProps:
|
|
144
|
-
onSubmit: handleSubmit,
|
|
145
|
-
ref: formRef,
|
|
146
|
-
onKeyDown: handleKeyDown
|
|
147
|
-
},
|
|
154
|
+
formProps: formProps,
|
|
148
155
|
dirty: dirty,
|
|
149
156
|
reset: handleReset,
|
|
150
157
|
submitting: submitting,
|
|
@@ -158,8 +165,9 @@ function Form(props) {
|
|
|
158
165
|
setFieldValue: form.change
|
|
159
166
|
}) : children();
|
|
160
167
|
return result === undefined ? null : result;
|
|
168
|
+
} else {
|
|
169
|
+
return (0, _platformFeatureFlags.fg)('platform_design-system-team_form-upgrade') ? /*#__PURE__*/_react.default.createElement("form", (0, _extends2.default)({}, formProps, userProvidedFormProps), children) : children;
|
|
161
170
|
}
|
|
162
|
-
return children;
|
|
163
171
|
}();
|
|
164
172
|
return /*#__PURE__*/_react.default.createElement(FormContext.Provider, {
|
|
165
173
|
value: FormContextValue
|
package/dist/es2019/form.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
1
2
|
import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
3
|
import { createForm } from 'final-form';
|
|
3
4
|
import createDecorator from 'final-form-focus';
|
|
4
5
|
import set from 'lodash/set';
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
7
|
/**
|
|
6
8
|
* __Form context__
|
|
7
9
|
*
|
|
@@ -24,9 +26,13 @@ export const FormContext = /*#__PURE__*/createContext({
|
|
|
24
26
|
*/
|
|
25
27
|
export const IsDisabledContext = /*#__PURE__*/createContext(false);
|
|
26
28
|
export default function Form(props) {
|
|
29
|
+
const {
|
|
30
|
+
formProps: userProvidedFormProps,
|
|
31
|
+
onSubmit
|
|
32
|
+
} = props;
|
|
27
33
|
const formRef = useRef(null);
|
|
28
|
-
const onSubmitRef = useRef(
|
|
29
|
-
onSubmitRef.current =
|
|
34
|
+
const onSubmitRef = useRef(onSubmit);
|
|
35
|
+
onSubmitRef.current = onSubmit;
|
|
30
36
|
const [form] = useState(() => {
|
|
31
37
|
// Types here would break the existing API
|
|
32
38
|
const finalForm = createForm({
|
|
@@ -116,14 +122,17 @@ export default function Form(props) {
|
|
|
116
122
|
subscribe: form.subscribe
|
|
117
123
|
};
|
|
118
124
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
125
|
+
|
|
126
|
+
// Abstracting so we can use the same for both rendering patterns
|
|
127
|
+
const formProps = {
|
|
128
|
+
onKeyDown: handleKeyDown,
|
|
129
|
+
onSubmit: handleSubmit,
|
|
130
|
+
ref: formRef
|
|
131
|
+
};
|
|
119
132
|
const childrenContent = (() => {
|
|
120
133
|
if (typeof children === 'function') {
|
|
121
134
|
const result = children.length > 0 ? children({
|
|
122
|
-
formProps
|
|
123
|
-
onSubmit: handleSubmit,
|
|
124
|
-
ref: formRef,
|
|
125
|
-
onKeyDown: handleKeyDown
|
|
126
|
-
},
|
|
135
|
+
formProps,
|
|
127
136
|
dirty,
|
|
128
137
|
reset: handleReset,
|
|
129
138
|
submitting,
|
|
@@ -133,8 +142,9 @@ export default function Form(props) {
|
|
|
133
142
|
setFieldValue: form.change
|
|
134
143
|
}) : children();
|
|
135
144
|
return result === undefined ? null : result;
|
|
145
|
+
} else {
|
|
146
|
+
return fg('platform_design-system-team_form-upgrade') ? /*#__PURE__*/React.createElement("form", _extends({}, formProps, userProvidedFormProps), children) : children;
|
|
136
147
|
}
|
|
137
|
-
return children;
|
|
138
148
|
})();
|
|
139
149
|
return /*#__PURE__*/React.createElement(FormContext.Provider, {
|
|
140
150
|
value: FormContextValue
|
package/dist/esm/form.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
1
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
3
|
import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
4
|
import { createForm } from 'final-form';
|
|
4
5
|
import createDecorator from 'final-form-focus';
|
|
5
6
|
import set from 'lodash/set';
|
|
7
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
8
|
/**
|
|
7
9
|
* __Form context__
|
|
8
10
|
*
|
|
@@ -27,9 +29,11 @@ export var FormContext = /*#__PURE__*/createContext({
|
|
|
27
29
|
*/
|
|
28
30
|
export var IsDisabledContext = /*#__PURE__*/createContext(false);
|
|
29
31
|
export default function Form(props) {
|
|
32
|
+
var userProvidedFormProps = props.formProps,
|
|
33
|
+
onSubmit = props.onSubmit;
|
|
30
34
|
var formRef = useRef(null);
|
|
31
|
-
var onSubmitRef = useRef(
|
|
32
|
-
onSubmitRef.current =
|
|
35
|
+
var onSubmitRef = useRef(onSubmit);
|
|
36
|
+
onSubmitRef.current = onSubmit;
|
|
33
37
|
var _useState = useState(function () {
|
|
34
38
|
// Types here would break the existing API
|
|
35
39
|
var finalForm = createForm({
|
|
@@ -127,14 +131,17 @@ export default function Form(props) {
|
|
|
127
131
|
subscribe: form.subscribe
|
|
128
132
|
};
|
|
129
133
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
134
|
+
|
|
135
|
+
// Abstracting so we can use the same for both rendering patterns
|
|
136
|
+
var formProps = {
|
|
137
|
+
onKeyDown: handleKeyDown,
|
|
138
|
+
onSubmit: handleSubmit,
|
|
139
|
+
ref: formRef
|
|
140
|
+
};
|
|
130
141
|
var childrenContent = function () {
|
|
131
142
|
if (typeof children === 'function') {
|
|
132
143
|
var result = children.length > 0 ? children({
|
|
133
|
-
formProps:
|
|
134
|
-
onSubmit: handleSubmit,
|
|
135
|
-
ref: formRef,
|
|
136
|
-
onKeyDown: handleKeyDown
|
|
137
|
-
},
|
|
144
|
+
formProps: formProps,
|
|
138
145
|
dirty: dirty,
|
|
139
146
|
reset: handleReset,
|
|
140
147
|
submitting: submitting,
|
|
@@ -148,8 +155,9 @@ export default function Form(props) {
|
|
|
148
155
|
setFieldValue: form.change
|
|
149
156
|
}) : children();
|
|
150
157
|
return result === undefined ? null : result;
|
|
158
|
+
} else {
|
|
159
|
+
return fg('platform_design-system-team_form-upgrade') ? /*#__PURE__*/React.createElement("form", _extends({}, formProps, userProvidedFormProps), children) : children;
|
|
151
160
|
}
|
|
152
|
-
return children;
|
|
153
161
|
}();
|
|
154
162
|
return /*#__PURE__*/React.createElement(FormContext.Provider, {
|
|
155
163
|
value: FormContextValue
|
package/dist/types/form.d.ts
CHANGED
|
@@ -35,12 +35,25 @@ type FormChildrenArgs<FormValues> = {
|
|
|
35
35
|
setFieldValue: (name: string, value: any) => void;
|
|
36
36
|
reset: (initialValues?: FormValues) => void;
|
|
37
37
|
};
|
|
38
|
+
type ExcludeReservedFormProps = {
|
|
39
|
+
onKeyDown?: never;
|
|
40
|
+
onSubmit?: never;
|
|
41
|
+
ref?: never;
|
|
42
|
+
};
|
|
38
43
|
export interface FormProps<FormValues> {
|
|
39
44
|
/**
|
|
40
45
|
* The contents rendered inside of the form. This is a function where the props will be passed from the form. The function props you can access are `dirty`, `submitting` and `disabled`.
|
|
41
46
|
* You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
|
|
42
47
|
*/
|
|
43
48
|
children: ((args: FormChildrenArgs<FormValues>) => ReactNode) | (() => void) | ReactNode;
|
|
49
|
+
/**
|
|
50
|
+
* When `Form` renders JSX children directly and not using a function to
|
|
51
|
+
* spread `formProps` manually, the properties in this `formProps` prop will
|
|
52
|
+
* be spread on an internally rendered HTML `form` element.
|
|
53
|
+
*/
|
|
54
|
+
formProps?: {
|
|
55
|
+
[x: string]: any;
|
|
56
|
+
} & ExcludeReservedFormProps;
|
|
44
57
|
/**
|
|
45
58
|
* Event handler called when the form is submitted. Fields must be free of validation errors.
|
|
46
59
|
*/
|