@saykit/transform-js 0.9.0 → 0.9.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/dist/index.mjs +2 -3
- package/dist/parser.d.mts +18 -1
- package/dist/parser.mjs +36 -5
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateSayCallExpression } from "./generator.mjs";
|
|
2
|
-
import { isEquivalentPlaceholder, parseExpression } from "./parser.mjs";
|
|
2
|
+
import { collectLeadingComments, isEquivalentPlaceholder, parseExpression } from "./parser.mjs";
|
|
3
3
|
import { generate } from "@babel/generator";
|
|
4
4
|
import * as parser from "@babel/parser";
|
|
5
5
|
import traverse_ from "@babel/traverse";
|
|
@@ -41,7 +41,7 @@ function createJsTransformer() {
|
|
|
41
41
|
const program = createProgram(code, id);
|
|
42
42
|
const messages = [];
|
|
43
43
|
traverse(program, { Expression(path) {
|
|
44
|
-
path.node.leadingComments = path
|
|
44
|
+
path.node.leadingComments = collectLeadingComments(path);
|
|
45
45
|
const message = parseExpression(path.node);
|
|
46
46
|
if (message) {
|
|
47
47
|
assignSequenceIdentifiers(message, { current: 0 }, isEquivalentPlaceholder);
|
|
@@ -61,7 +61,6 @@ function createJsTransformer() {
|
|
|
61
61
|
transform(code, id) {
|
|
62
62
|
const program = createProgram(code, id);
|
|
63
63
|
traverse(program, { Expression(path) {
|
|
64
|
-
path.node.leadingComments = path.node.leadingComments ?? [];
|
|
65
64
|
const message = parseExpression(path.node);
|
|
66
65
|
if (message) {
|
|
67
66
|
assignSequenceIdentifiers(message, { current: 0 }, isEquivalentPlaceholder);
|
package/dist/parser.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NodePath } from "@babel/traverse";
|
|
1
2
|
import { AUTO_INCREMENT_IDENTIFIER, ArgumentMessage, CompositeMessage } from "@saykit/config/features/messages";
|
|
2
3
|
import * as t from "@babel/types";
|
|
3
4
|
//#region src/parser.d.ts
|
|
@@ -28,5 +29,21 @@ declare function unwrapPlaceholder(expression: t.Expression): [string | typeof A
|
|
|
28
29
|
declare function isEquivalentPlaceholder(a: any, b: any): boolean;
|
|
29
30
|
declare function parseExpression(expression: t.Expression, fallback?: false): CompositeMessage | null;
|
|
30
31
|
declare function parseExpression(expression: t.Expression, fallback: true): CompositeMessage | ArgumentMessage;
|
|
32
|
+
/**
|
|
33
|
+
* The notes a translator is meant to read, taken from the comments written
|
|
34
|
+
* above a message — `// TRANSLATORS: keep this under 20 characters`. A comment
|
|
35
|
+
* that does not open with the marker is a note to whoever is reading the code,
|
|
36
|
+
* and stays there.
|
|
37
|
+
*/
|
|
38
|
+
declare function getTranslatorComments(comments: readonly t.Comment[] | null | undefined): string[];
|
|
39
|
+
/**
|
|
40
|
+
* The comments written in front of a message, in the order they were written.
|
|
41
|
+
*
|
|
42
|
+
* A comment on its own line is attached by Babel to whatever node happens to
|
|
43
|
+
* begin at it — `const a = say\`Hi\`` puts it on the declaration, not on the
|
|
44
|
+
* template — so a message is rarely the node holding its own notes. Walking out
|
|
45
|
+
* to the statement gathers them from wherever they landed.
|
|
46
|
+
*/
|
|
47
|
+
declare function collectLeadingComments(path: NodePath<t.Node>): t.Comment[];
|
|
31
48
|
//#endregion
|
|
32
|
-
export { isEquivalentPlaceholder, parseCallExpression, parseExpression, parseTaggedTemplateExpression, processExpression, unwrapPlaceholder };
|
|
49
|
+
export { collectLeadingComments, getTranslatorComments, isEquivalentPlaceholder, parseCallExpression, parseExpression, parseTaggedTemplateExpression, processExpression, unwrapPlaceholder };
|
package/dist/parser.mjs
CHANGED
|
@@ -10,7 +10,7 @@ function parseTaggedTemplateExpression(tagged) {
|
|
|
10
10
|
return new CompositeMessage({
|
|
11
11
|
id: descriptor ? findPropertyValueIfStringLiteralAsString(descriptor, "id") : void 0,
|
|
12
12
|
context: descriptor ? findPropertyValueIfStringLiteralAsString(descriptor, "context") : void 0
|
|
13
|
-
}, getTranslatorComments(tagged.leadingComments
|
|
13
|
+
}, getTranslatorComments(tagged.leadingComments), tagged.loc ? [`${tagged.loc.filename}:${tagged.loc.start.line}`] : [], children, accessor);
|
|
14
14
|
}
|
|
15
15
|
function buildTemplateChildren(template) {
|
|
16
16
|
return template.quasis.reduce((c, q, i) => {
|
|
@@ -28,7 +28,7 @@ function parseCallExpression(call) {
|
|
|
28
28
|
const wrap = (children) => new CompositeMessage({
|
|
29
29
|
id: descriptorId,
|
|
30
30
|
context: descriptorContext
|
|
31
|
-
},
|
|
31
|
+
}, getTranslatorComments(call.leadingComments), call.loc ? [`${call.loc.filename}:${call.loc.start.line}`] : [], children, accessor);
|
|
32
32
|
if (typeof kind === "string" && [
|
|
33
33
|
"select",
|
|
34
34
|
"ordinal",
|
|
@@ -174,12 +174,43 @@ function findPropertyValueIfStringLiteralAsString(object, key) {
|
|
|
174
174
|
if (t.isIdentifier(property.key) && property.key.name === key && t.isStringLiteral(property.value)) return property.value.value;
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
|
+
const TRANSLATOR_COMMENT_PREFIX = "translators:";
|
|
177
178
|
function getTranslatorComments(comments) {
|
|
178
|
-
return comments.reduce((a, c) => {
|
|
179
|
+
return (comments ?? []).reduce((a, c) => {
|
|
179
180
|
const text = c.value.trim();
|
|
180
|
-
if (text.toLowerCase().startsWith(
|
|
181
|
+
if (text.toLowerCase().startsWith(TRANSLATOR_COMMENT_PREFIX)) a.push(text.slice(12).trim());
|
|
181
182
|
return a;
|
|
182
183
|
}, []);
|
|
183
184
|
}
|
|
185
|
+
function collectLeadingComments(path) {
|
|
186
|
+
const levels = [];
|
|
187
|
+
let current = path;
|
|
188
|
+
while (current) {
|
|
189
|
+
levels.push(current.node.leadingComments ?? []);
|
|
190
|
+
const parent = current.parentPath;
|
|
191
|
+
/* v8 ignore next */
|
|
192
|
+
if (!parent) break;
|
|
193
|
+
if (t.isJSXElement(parent.node) || t.isJSXFragment(parent.node)) {
|
|
194
|
+
levels.push(getPrecedingJSXComments(parent.node, current.node));
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
if (t.isStatement(current.node) && !t.isExportDeclaration(parent.node)) break;
|
|
198
|
+
current = parent;
|
|
199
|
+
}
|
|
200
|
+
return [...new Set(levels.reverse().flat())];
|
|
201
|
+
}
|
|
202
|
+
function getPrecedingJSXComments(parent, node) {
|
|
203
|
+
const index = parent.children.indexOf(node);
|
|
204
|
+
/* v8 ignore next */
|
|
205
|
+
if (index === -1) return [];
|
|
206
|
+
const comments = [];
|
|
207
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
208
|
+
const sibling = parent.children[i];
|
|
209
|
+
if (t.isJSXText(sibling) && !sibling.value.trim()) continue;
|
|
210
|
+
if (!t.isJSXExpressionContainer(sibling) || !t.isJSXEmptyExpression(sibling.expression)) break;
|
|
211
|
+
comments.unshift(...sibling.expression.innerComments ?? []);
|
|
212
|
+
}
|
|
213
|
+
return comments;
|
|
214
|
+
}
|
|
184
215
|
//#endregion
|
|
185
|
-
export { isEquivalentPlaceholder, parseCallExpression, parseExpression, parseTaggedTemplateExpression, processExpression, unwrapPlaceholder };
|
|
216
|
+
export { collectLeadingComments, getTranslatorComments, isEquivalentPlaceholder, parseCallExpression, parseExpression, parseTaggedTemplateExpression, processExpression, unwrapPlaceholder };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saykit/transform-js",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "JavaScript and TypeScript transformer for SayKit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@babel/parser": "^7.29.7",
|
|
48
48
|
"@babel/traverse": "^7.29.7",
|
|
49
49
|
"@babel/types": "^7.29.7",
|
|
50
|
-
"@saykit/config": "^0.9.
|
|
50
|
+
"@saykit/config": "^0.9.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@babel/core": "^7.29.7",
|