Skip to content

Commit 68bcec6

Browse files
DST-1321 Prop opt out (#152)
* Added the ability to ignore properties * docs(changeset): Added the ability to 'ignore' a property to avoid the missing converter error. To ignore a property add a comment above the prop and prefix it with @ert-ignore. * 🚨 Add testcase for type props * 🔨 Output raw type to props as a string * 🔨 rename unsupported to raw
1 parent 5f1ff91 commit 68bcec6

File tree

6 files changed

+163
-46
lines changed

6 files changed

+163
-46
lines changed

.changeset/wise-bulldogs-repeat.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'extract-react-types': minor
3+
'babel-plugin-extract-react-types': patch
4+
'kind2string': patch
5+
---
6+
7+
Added a safe bail-out for when extract-react-types encounters an unsupported keyword or syntax.
8+
In that case, the type will be output as a raw string and summary type will be `raw`.

packages/babel-plugin-extract-react-types/index.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ module.exports = babel => {
99
.map(plugin => (Array.isArray(plugin) ? plugin[0] : plugin))
1010
.find(plugin => plugin === 'flow' || plugin === 'typescript');
1111

12-
if (typeSystem) {
13-
try {
14-
let components = findExportedComponents(programPath, typeSystem, state.file.filename);
15-
components.forEach(({ name, component }) => {
12+
if (!typeSystem) return;
13+
14+
try {
15+
findExportedComponents(programPath, typeSystem, state.file.filename).forEach(
16+
({ name, component }) => {
1617
// TODO: handle when name is null
1718
// it will only happen when it's the default export
1819
// generate something like this
@@ -28,10 +29,10 @@ module.exports = babel => {
2829
)
2930
);
3031
}
31-
});
32-
/* eslint-disable no-empty */
33-
} catch (e) {}
34-
}
32+
}
33+
);
34+
/* eslint-disable no-empty */
35+
} catch (e) {}
3536
}
3637
}
3738
};

packages/extract-react-types/__snapshots__/converters-typescript.test.js.snap

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,78 @@ Object {
161161
}
162162
`;
163163

164+
exports[`TypeScript: Types fallback to raw source when an unsupported type us used (interface) 1`] = `
165+
Object {
166+
"kind": "generic",
167+
"name": Object {
168+
"kind": "id",
169+
"name": "Component",
170+
"type": null,
171+
},
172+
"value": Object {
173+
"kind": "object",
174+
"members": Array [
175+
Object {
176+
"key": Object {
177+
"kind": "id",
178+
"name": "bar",
179+
},
180+
"kind": "property",
181+
"leadingComments": Array [
182+
Object {
183+
"raw": " bar property docs ",
184+
"type": "commentBlock",
185+
"value": "bar property docs",
186+
},
187+
],
188+
"optional": false,
189+
"value": Object {
190+
"kind": "raw",
191+
"name": "keyof Bar",
192+
},
193+
},
194+
],
195+
"referenceIdName": "BarProps",
196+
},
197+
}
198+
`;
199+
200+
exports[`TypeScript: Types fallback to raw source when an unsupported type us used (type) 1`] = `
201+
Object {
202+
"kind": "generic",
203+
"name": Object {
204+
"kind": "id",
205+
"name": "Component",
206+
"type": null,
207+
},
208+
"value": Object {
209+
"kind": "object",
210+
"members": Array [
211+
Object {
212+
"key": Object {
213+
"kind": "id",
214+
"name": "bar",
215+
},
216+
"kind": "property",
217+
"leadingComments": Array [
218+
Object {
219+
"raw": " bar property docs ",
220+
"type": "commentBlock",
221+
"value": "bar property docs",
222+
},
223+
],
224+
"optional": false,
225+
"value": Object {
226+
"kind": "raw",
227+
"name": "keyof Bar",
228+
},
229+
},
230+
],
231+
"referenceIdName": "BarProps",
232+
},
233+
}
234+
`;
235+
164236
exports[`TypeScript: follow export default export 1`] = `
165237
Object {
166238
"kind": "generic",

packages/extract-react-types/converters-typescript.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ const TESTS = [
2727
class Component extends React.Component<Props> {}
2828
`
2929
},
30+
{
31+
name: 'Types fallback to raw source when an unsupported type us used (interface)',
32+
typeSystem: 'typescript',
33+
code: `
34+
interface BarProps {
35+
/* bar property docs */
36+
bar: keyof Bar;
37+
}
38+
39+
class Component extends React.Component<BarProps> {}
40+
`
41+
},
42+
{
43+
name: 'Types fallback to raw source when an unsupported type us used (type)',
44+
typeSystem: 'typescript',
45+
code: `
46+
type BarProps = {
47+
/* bar property docs */
48+
bar: keyof Bar;
49+
}
50+
51+
class Component extends React.Component<BarProps> {}
52+
`
53+
},
3054
{
3155
name: 'React.ComponentType',
3256
typeSystem: 'typescript',

packages/extract-react-types/src/index.js

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ converters.TypeCastExpression = (path, context): K.TypeCastExpression => ({
539539

540540
converters.NumericLiteral = (path): K.Number => ({ kind: 'number', value: path.node.value });
541541

542-
converters.NullLiteral = (path): K.Null => ({ kind: 'null' });
542+
converters.NullLiteral = (): K.Null => ({ kind: 'null' });
543543

544544
converters.BooleanLiteral = (path): K.Boolean => ({ kind: 'boolean', value: path.node.value });
545545

@@ -908,6 +908,17 @@ converters.TSFunctionType = (path, context): K.Generic => ({
908908
}
909909
});
910910

911+
function convertMethodCall(path, context): K.Func {
912+
const parameters = path.get('parameters').map(p => convertParameter(p, context));
913+
const returnType = convert(path.get('typeAnnotation'), context);
914+
915+
return {
916+
kind: 'function',
917+
returnType,
918+
parameters
919+
};
920+
}
921+
911922
converters.TSMethodSignature = (path, context): K.Property => ({
912923
kind: 'property',
913924
optional: !!path.node.optional,
@@ -1217,31 +1228,11 @@ converters.TSTypeQuery = (path, context): K.TypeQuery => ({
12171228
exprName: convert(path.get('exprName'), { ...context, mode: 'value' })
12181229
});
12191230

1220-
function convertMethodCall(path, context): K.Func {
1221-
const parameters = path.get('parameters').map(p => convertParameter(p, context));
1222-
const returnType = convert(path.get('typeAnnotation'), context);
1223-
1224-
return {
1225-
kind: 'function',
1226-
returnType,
1227-
parameters
1228-
};
1229-
}
1230-
1231-
function mapComment(comment) {
1232-
return {
1233-
type: comment.type === 'CommentLine' ? 'commentLine' : 'commentBlock',
1234-
value: normalizeComment(comment),
1235-
raw: comment.value
1236-
};
1237-
}
1238-
12391231
function attachCommentProperty(source, dest, name) {
12401232
if (!source || !source[name]) return;
12411233
if (!dest[name]) dest[name] = [];
12421234

1243-
let comments = source[name].map(mapComment);
1244-
dest[name] = dest[name].concat(comments);
1235+
dest[name] = dest[name].concat(parseComment(source[name]));
12451236
}
12461237

12471238
function attachComments(source, dest) {
@@ -1250,6 +1241,14 @@ function attachComments(source, dest) {
12501241
attachCommentProperty(source, dest, 'innerComments');
12511242
}
12521243

1244+
function parseComment(commentProperty) {
1245+
return commentProperty.map(comment => ({
1246+
type: comment.type === 'CommentLine' ? 'commentLine' : 'commentBlock',
1247+
value: normalizeComment(comment),
1248+
raw: comment.value
1249+
}));
1250+
}
1251+
12531252
// This function is from mdn:
12541253
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#Examples
12551254
const getCircularReplacer = () => {
@@ -1274,8 +1273,27 @@ function convert(path, context) {
12741273
}
12751274

12761275
const converter = converters[path.type];
1277-
if (!converter) throw new Error(`Missing converter for: ${path.type}`);
1276+
1277+
if (!converter) {
1278+
const propertySignature = path.find(p => p.isTSPropertySignature() || p.isObjectTypeProperty());
1279+
1280+
// Fallback to a raw string if property uses a type without a matching converter
1281+
if (propertySignature && propertySignature.node) {
1282+
return {
1283+
kind: 'raw',
1284+
name: path.getSource()
1285+
};
1286+
}
1287+
1288+
throw new Error(
1289+
`Missing converter for: ${
1290+
path.type
1291+
}, see: https://github.com/atlassian/extract-react-types/issues/150`
1292+
);
1293+
}
1294+
12781295
const result = converter(path, context);
1296+
12791297
attachComments(path.node, result);
12801298
return result;
12811299
}
@@ -1304,10 +1322,7 @@ function getContext(
13041322
}
13051323

13061324
/* $FlowFixMe - need to update types in babylon-options */
1307-
const parserOpts = createBabylonOptions({
1308-
stage: 2,
1309-
plugins
1310-
});
1325+
const parserOpts = createBabylonOptions({ stage: 2, plugins });
13111326

13121327
return { resolveOptions, parserOpts };
13131328
}
@@ -1320,7 +1335,6 @@ export function extractReactTypes(
13201335
) {
13211336
const { resolveOptions, parserOpts } = getContext(typeSystem, filename, inputResolveOptions);
13221337
const file = createBabelFile(code, { parserOpts, filename });
1323-
13241338
return convert(file.path, { resolveOptions, parserOpts });
13251339
}
13261340

@@ -1388,11 +1402,7 @@ function exportedComponents(programPath, componentsToFind: 'all' | 'default', co
13881402
context,
13891403
firstArg.get('params.0.typeAnnotation')
13901404
);
1391-
components.push({
1392-
name,
1393-
path,
1394-
component
1395-
});
1405+
components.push({ name, path, component });
13961406
return;
13971407
}
13981408

packages/kind2string/src/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ const converters = {
6565
custom: (type: any, mode: string): string => type.value.toString(),
6666
any: (type: K.Any, mode: string): string => type.kind,
6767
void: (type: K.Void, mode: string): 'undefined' => 'undefined',
68-
literal: (type: any, mode: string): string => `${type.kind}`,
68+
literal: (type: any, mode: string): string => type.kind,
6969
mixed: (type: K.Mixed, mode: string): string => type.kind,
7070
null: (type: K.Null, mode: string): 'null' => 'null',
71+
unknown: (type: K.Unknown): string => type.kind,
7172
logicalExpression: (type, mode: string): string => {
7273
return `${convert(type.left)} ${type.operator} ${convert(type.right)}`;
7374
},
@@ -76,9 +77,7 @@ const converters = {
7677
return `${type.operator}${space}${convert(type.argument)}`;
7778
},
7879

79-
id: (type: K.Id, mode: string): string => {
80-
return type.name;
81-
},
80+
id: (type: K.Id, mode: string): string => type.name,
8281
// TODO - this is not right and needs to be improved
8382
opaqueType: (type: K.OpaqueType, mode: string): string => {
8483
return convert(type.id);
@@ -314,7 +313,10 @@ from file: ${convert(type.source, mode)}`
314313
tuple: (type: K.Tuple, mode: string): string => `[${mapConvertAndJoin(type.types)}]`,
315314
typeQuery: (type: K.TypeQuery): string => {
316315
return type.exprName ? `typeof ${type.exprName.name}` : `${type.kind}`;
317-
}
316+
},
317+
318+
// ERT - Misc
319+
raw: (type: any): string => type.name
318320
};
319321

320322
function convert(type: any, mode: string = 'value') {

0 commit comments

Comments
 (0)