UNPKG

4.94 kBJavaScriptView Raw
1/*
2 *
3 * AST Manipulation
4 *
5 */
6
7
8const types = require('babel-types');
9
10import {assertInput} from './errors';
11import generate from './generation';
12import {options} from './options';
13
14
15// does this callExpression node represent a call to `i18n()`
16export function isFunctionMarker(callExpression) {
17 return callExpression.callee.name === options.functionMarker;
18}
19
20
21// Element markers (`<I18N> ... </I18N>`)
22
23export function nodeName(node) {
24 return node.name && generate(node.name);
25}
26
27export function elementName(jsxElement) {
28 return nodeName(jsxElement.openingElement);
29}
30
31export function attributeName(jsxAttribute) {
32 return nodeName(jsxAttribute);
33}
34
35export function elementNamespaceOrName(jsxElement) {
36 if (hasNamespacedName(jsxElement)) {
37 return jsxElement.openingElement.name.namespace.name;
38 } else {
39 return elementName(jsxElement);
40 }
41}
42
43export function elementAttributes(jsxElement) {
44 return jsxElement.openingElement.attributes;
45}
46
47export function isElementMarker(jsxElement) {
48 return (
49 isElement(jsxElement) &&
50 elementName(jsxElement) === options.elementMarker
51 );
52}
53
54export function isElement(node) {
55 return node.type === 'JSXElement';
56}
57
58export function isTag(jsxElement) {
59 return /^[a-z]|\-/.test(elementName(jsxElement));
60}
61
62export function isComponent(jsxElement) {
63 return !isTag(jsxElement);
64}
65
66export function isSimpleExpression(expression) {
67 if (expression.type === 'Identifier') {
68 return true;
69 } else if (expression.type === 'ThisExpression') {
70 return true;
71 } else if (expression.type === 'MemberExpression') {
72 return !expression.computed && isSimpleExpression(expression.object);
73 } else {
74 return false;
75 }
76}
77
78export function hasNamespacedName(jsxElement) {
79 return jsxElement.openingElement.name.type === 'JSXNamespacedName';
80}
81
82export function hasI18nId(jsxElement) {
83 return (
84 hasNamespacedName(jsxElement) ||
85 hasI18nIdAttribute(jsxElement)
86 );
87}
88
89export function hasI18nIdAttribute(jsxElement) {
90 return elementAttributes(jsxElement).map(attributeName).indexOf('i18n-id') !== -1;
91}
92
93export function filterAttributes(jsxElement, condition) {
94 jsxElement.openingElement.attributes = jsxElement.openingElement.attributes.filter(
95 a => condition(jsxElement, a)
96 );
97}
98
99export function i18nId(jsxElement) {
100 if (hasNamespacedName(jsxElement)) {
101 // It's names all the way down
102 return jsxElement.openingElement.name.name.name;
103 } else {
104 const attr = elementAttributes(jsxElement)
105 .find(a => attributeName(a) === 'i18n-id');
106 if (attr) {
107 assertInput(attr.value.type === 'StringLiteral',
108 "i18n-id attribute found with non-StringLiteral value",
109 jsxElement
110 );
111 return attr.value.value;
112 }
113 }
114}
115
116export function removeIdAttribute(jsxElement) {
117 filterAttributes(jsxElement, (_, a) => attributeName(a) !== 'i18n-id');
118}
119
120export function stripI18nId(jsxElement) {
121 if (jsxElement.openingElement.name.type === 'JSXNamespacedName') {
122 const newName = jsxElement.openingElement.name.namespace.name;
123 jsxElement.openingElement.name.type = 'JSXIdentifier';
124 jsxElement.openingElement.name.name = newName;
125 delete jsxElement.openingElement.name.object;
126
127 if (jsxElement.closingElement) {
128 jsxElement.closingElement.name.type = 'JSXIdentifier';
129 jsxElement.closingElement.name.name = newName;
130 delete jsxElement.closingElement.name.object;
131 }
132 } else {
133 removeIdAttribute(jsxElement);
134 }
135}
136
137export function convertToNamespacedName(jsxElement) {
138 if (!hasNamespacedName(jsxElement)) {
139 const name = elementName(jsxElement);
140 const id = i18nId(jsxElement);
141 if (id) {
142 removeIdAttribute(jsxElement);
143 const nameAst = types.JSXNamespacedName(
144 types.JSXIdentifier(name),
145 types.JSXIdentifier(id)
146 );
147 jsxElement.openingElement.name = nameAst;
148 if (jsxElement.closingElement) {
149 jsxElement.closingElement.name = nameAst;
150 }
151 }
152 }
153
154 return elementName(jsxElement);
155}
156
157export function convertNamespacedNameToIdAttribute(jsxElement) {
158 if (jsxElement.openingElement.name.type === 'JSXNamespacedName') {
159 const i18nId = jsxElement.openingElement.name.name.name;
160 stripI18nId(jsxElement);
161
162 jsxElement.openingElement.attributes.push(
163 types.JSXAttribute(
164 types.JSXIdentifier('i18n-id'),
165 types.StringLiteral(i18nId)
166 )
167 );
168 }
169}
170
171export function idOrComponentName(jsxElement) {
172 let id = i18nId(jsxElement);
173 if (!id && isComponent(jsxElement)) {
174 id = elementName(jsxElement);
175 }
176 return id;
177};