source: imaps-frontend/node_modules/jsx-ast-utils/__tests__/src/getProp-parser-test.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/* eslint-env mocha */
2import assert from 'assert';
3import entries from 'object.entries';
4import fromEntries from 'object.fromentries';
5import { getOpeningElement, setParserName, fallbackToBabylon } from '../helper';
6import getProp from '../../src/getProp';
7
8const literal = {
9 source: '<div {...{ id: "foo" }} />',
10 target: '<div id="foo" />',
11 offset: { keyOffset: -6, valueOffset: -7 },
12};
13
14const expression1 = {
15 source: '<div {...{ id }} />',
16 target: '<div id={id} />',
17 offset: { keyOffset: -6, valueOffset: -2 },
18};
19
20const expression2 = {
21 source: '<div {...{ id: `foo${bar}baz` }} />', // eslint-disable-line no-template-curly-in-string
22 target: '<div id={`foo${bar}baz`} />', // eslint-disable-line no-template-curly-in-string
23 offset: { keyOffset: -6, valueOffset: -6 },
24};
25
26describe('getProp', () => {
27 it('should create the correct AST for literal with flow parser', () => {
28 actualTest('flow', literal);
29 });
30 it('should create the correct AST for literal with babel parser', () => {
31 actualTest('babel', literal);
32 });
33 it('should create the correct AST for expression with flow parser (1)', () => {
34 actualTest('flow', expression1);
35 });
36 it('should create the correct AST for expression with babel parser (1)', () => {
37 actualTest('babel', expression1);
38 });
39 it('should create the correct AST for expression with flow parser (2)', () => {
40 actualTest('flow', expression2);
41 });
42 it('should create the correct AST for expression with babel parser (2)', () => {
43 actualTest('babel', expression2);
44 });
45});
46
47function actualTest(parserName, test) {
48 setParserName(parserName);
49 const { source, target, offset } = test;
50 const sourceProps = stripConstructors(getOpeningElement(source).attributes);
51 const targetProps = stripConstructors(getOpeningElement(target).attributes);
52 const prop = 'id';
53 const sourceResult = getProp(sourceProps, prop);
54 const targetResult = getProp(targetProps, prop);
55
56 if (fallbackToBabylon && parserName === 'babel' && test === literal) {
57 // Babylon (node < 6) adds an `extra: null` prop to a literal if it is parsed from a
58 // JSXAttribute, other literals don't get this.
59 sourceResult.value.extra = null;
60 }
61
62 assert.deepStrictEqual(
63 adjustLocations(sourceResult, offset),
64 adjustRange(targetResult),
65 );
66}
67
68function adjustRange({ name, value: { expression, ...value }, ...node }) {
69 return {
70 ...adjustNodeRange(node),
71 name: adjustNodeRange(name),
72 value: {
73 ...adjustNodeRange(value),
74 ...(expression ? { expression: adjustNodeRangeRecursively(expression) } : {}),
75 },
76 };
77}
78
79function adjustNodeRange(node) {
80 if (!node.loc) {
81 return node;
82 }
83
84 const [start, end] = node.range || [node.start, node.end];
85 return {
86 ...node,
87 end: undefined,
88 range: [start, end],
89 start: undefined,
90 };
91}
92
93function adjustNodeRangeRecursively(node) {
94 if (Array.isArray(node)) {
95 return node.map(adjustNodeRangeRecursively);
96 }
97
98 if (node && typeof node === 'object') {
99 return adjustNodeRange(mapValues(node, adjustNodeRangeRecursively));
100 }
101
102 return node;
103}
104
105function stripConstructors(value) {
106 return JSON.parse(JSON.stringify(value));
107}
108
109function adjustLocations(node, { keyOffset, valueOffset }) {
110 const hasExpression = !!node.value.expression;
111 return {
112 ...adjustNodeLocations(node, {
113 startOffset: keyOffset,
114 endOffset: valueOffset + (hasExpression ? 1 : 0),
115 }),
116 name: adjustNodeLocations(node.name, { startOffset: keyOffset, endOffset: keyOffset }),
117 value: {
118 ...adjustNodeLocations(node.value, {
119 startOffset: valueOffset - (hasExpression ? 1 : 0),
120 endOffset: valueOffset + (hasExpression ? 1 : 0),
121 }),
122 ...(hasExpression
123 ? {
124 expression: adjustLocationsRecursively(
125 node.value.expression,
126 { startOffset: valueOffset, endOffset: valueOffset },
127 ),
128 }
129 : {}
130 ),
131 },
132 };
133}
134
135function adjustNodeLocations(node, { startOffset, endOffset }) {
136 if (!node.loc) {
137 return node;
138 }
139
140 const [start, end] = node.range || [];
141 return {
142 ...node,
143 end: undefined,
144 loc: {
145 ...node.loc,
146 start: {
147 ...node.loc.start,
148 column: node.loc.start.column + startOffset,
149 },
150 end: {
151 ...node.loc.end,
152 column: node.loc.end.column + endOffset,
153 },
154 },
155 range: [start + startOffset, end + endOffset],
156 start: undefined,
157 };
158}
159
160function adjustLocationsRecursively(node, { startOffset, endOffset }) {
161 if (Array.isArray(node)) {
162 return node.map((x) => adjustLocationsRecursively(x, { startOffset, endOffset }));
163 }
164 if (node && typeof node === 'object') {
165 return adjustNodeLocations(
166 mapValues(node, (x) => adjustLocationsRecursively(x, { startOffset, endOffset })),
167 { startOffset, endOffset },
168 );
169 }
170
171 return node;
172}
173
174function mapValues(o, f) {
175 return fromEntries(entries(o).map(([k, v]) => [k, f(v)]));
176}
Note: See TracBrowser for help on using the repository browser.