UNPKG

4.99 kBJavaScriptView Raw
1const _ = require('lodash');
2const objectHash = require('object-hash');
3const flowTypes = require('./flow-types');
4
5const shouldOmit = {
6 optional: true,
7 variance: true,
8 exact: true,
9 static: true
10};
11const {omit, collectAllNodes, setTo} = require('./annotation-utils');
12
13function rustTypeBorrows(annotation) {
14 switch (annotation.type) {
15 case 'GenericTypeAnnotation':
16 case 'ObjectTypeAnnotation':
17 case 'UnionTypeAnnotation':
18 return true;
19 default:
20 return false;
21 }
22}
23
24function isHashMap(annotation) {
25 return annotation.type === 'ObjectTypeAnnotation' && annotation.indexers.length === 1;
26}
27
28function isStruct(annotation) {
29 return annotation.type === 'ObjectTypeAnnotation' && annotation.indexers.length === 0;
30}
31
32/*eslint no-fallthrough:0*/
33function flowAnnotationToRustType(annotation) {
34 const fail = () => {
35 throw new Error(`unknown annotation ${JSON.stringify(annotation, null, 2)}`);
36 };
37 switch (annotation.type) {
38 case 'NullableTypeAnnotation':
39 return `Option<${flowAnnotationToRustType(annotation.typeAnnotation)}>`;
40 case 'VoidTypeAnnotation':
41 return '()';
42 case 'BooleanTypeAnnotation':
43 return 'bool';
44 case 'StringTypeAnnotation':
45 return 'StringSymbol';
46 case 'NumberTypeAnnotation':
47 return 'f64';
48 case 'NullLiteralTypeAnnotation':
49 return 'Option<f64>';
50 case 'UnionTypeAnnotation':
51 return `enum ${annotation.name} {
52 ${annotation.types
53 .map((type, index) => {
54 const name = _.upperFirst(_.get(type, 'name.id', `e${index}`));
55 return `${name}(${flowAnnotationToRustType(type)})`;
56 })
57 .join('\n')}
58 }`;
59 case 'GenericTypeAnnotation':
60 return annotation.id.name;
61 case 'ObjectTypeProperty':
62 return `#[serde(deserialize_state)]
63#[serde(serialize_state)]
64${annotation.key.name}: ${flowAnnotationToRustType(annotation.value)},`;
65 case 'ObjectTypeAnnotation':
66 if (annotation.indexers.length === 0) {
67 return `
68#[derive(Debug, DeserializeState,SerializeState, Default)]
69#[serde(de_parameters = "S")]
70#[serde(bound(deserialize = "S: ToSymbol"))]
71#[serde(deserialize_state = "S")]
72#[serde(serialize_state = "StringInterner<StringSymbol>")]
73struct ${annotation.name} {
74${annotation.properties.map(t => flowAnnotationToRustType(t)).join('\n')}
75}`;
76 } else if (annotation.indexers.length === 1) {
77 return `HashMap<${flowAnnotationToRustType(annotation.indexers[0].key)},${flowAnnotationToRustType(
78 annotation.indexers[0].value
79 )}>`;
80 }
81 fail();
82 default:
83 fail();
84 }
85}
86
87function sortUnionsAndProperties({expr, types}) {
88 collectAllNodes({expr, types}, node => node.type === 'UnionTypeAnnotation').forEach(node =>
89 setTo(node, Object.assign({}, node, {types: _.sortBy(node.types, objectHash)}))
90 );
91 collectAllNodes({expr, types}, node => node.type === 'ObjectTypeAnnotation').forEach(node =>
92 setTo(node, Object.assign({}, node, {properties: _.sortBy(node.properties, objectHash)}))
93 );
94 return {expr, types};
95}
96
97function replaceTypeRefsWithFull({expr, types}) {
98 collectAllNodes(
99 {expr, types},
100 node => node.type === 'GenericTypeAnnotation' && node.id.type === 'Identifier' && types[node.id.name]
101 ).forEach(node => {
102 setTo(node, _.cloneDeep(types[node.id.name]));
103 });
104 return {expr, types};
105}
106
107function replaceFullWithTypeRefs({expr, types}) {
108 const hashToTypes = _(types)
109 .mapValues(type => objectHash(type))
110 .invert()
111 .value();
112 const cnt = 0;
113 const allNodesWithTypes = collectAllNodes(
114 {expr, types},
115 node => node.type === 'UnionTypeAnnotation' || node.type === 'ObjectTypeAnnotation' && node.indexers.length === 0
116 );
117
118 const allNodesHashed = allNodesWithTypes.map(node => objectHash(node));
119
120 allNodesWithTypes.forEach((node, idx) => {
121 const hash = allNodesHashed[idx];
122 if (!hashToTypes[hash]) {
123 const typeName = `Type${hash}`;
124 hashToTypes[hash] = `Type${hash}`;
125 types[typeName] = node;
126 }
127 });
128 allNodesWithTypes.forEach((node, idx) => {
129 const hash = allNodesHashed[idx];
130 if (node !== types[hashToTypes[hash]]) {
131 setTo(node, {
132 type: 'GenericTypeAnnotation',
133 typeParameters: null,
134 id: {type: 'Identifier', name: hashToTypes[hash]}
135 });
136 }
137 });
138 _.forEach(types, (type, name) => type.name = name); //eslint-disable-line no-return-assign
139 return {expr, types};
140}
141
142const extractionPipeline = [replaceTypeRefsWithFull, sortUnionsAndProperties, replaceFullWithTypeRefs];
143
144function extractAllTypeDeclerations(annotations) {
145 for (let i = 0; i < extractionPipeline.length; i++) {
146 annotations = extractionPipeline[i](_.cloneDeep(annotations));
147 }
148 // require('fs').writeFileSync('tmp.json', JSON.stringify(annotations, null, 2));
149 return annotations;
150}
151
152module.exports = {flowAnnotationToRustType, extractAllTypeDeclerations, rustTypeBorrows, isHashMap, isStruct};