Skip to content

Commit

Permalink
add embeddedAttrJsExtractor (#60)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: youthlin <youthlin.chen@bytedance.com>
  • Loading branch information
youthlin and youthlin authored Mar 13, 2023
1 parent c90eb9b commit 4276367
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 2 deletions.
36 changes: 36 additions & 0 deletions src/html/extractors/factories/embeddedAttributeJs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Attribute } from 'parse5';
import { JsParser } from '../../../js/parser';
import { Validate } from '../../../utils/validate';
import { Element, IHtmlExtractorFunction, Node } from '../../parser';

export type AttributePredicate = (attribute: Attribute) => boolean;

export function embeddedAttributeJsExtractor(filter: RegExp | AttributePredicate, jsParser: JsParser): IHtmlExtractorFunction {
Validate.required.argument({ filter });
Validate.required.argument({ jsParser });
let test: AttributePredicate;
if (typeof filter === 'function') {
test = filter;
} else {
test = attr => filter.test(attr.name);
}

return (node: Node, fileName: string, _, lineNumberStart) => {
if (typeof (node as Element).tagName !== 'string') {
return;
}

const element = node as Element;

element.attrs.filter(test).forEach((attr) => {
const startLine = element.sourceCodeLocation?.attrs[attr.name]?.startLine;
if (startLine) {
lineNumberStart = lineNumberStart + startLine - 1;
}
jsParser.parseString(attr.value, fileName, {
lineNumberStart
});
});

};
}
4 changes: 3 additions & 1 deletion src/html/extractors/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { elementContentExtractor } from './factories/elementContent';
import { elementAttributeExtractor } from './factories/elementAttribute';
import { elementContentExtractor } from './factories/elementContent';
import { embeddedAttributeJsExtractor } from './factories/embeddedAttributeJs';
import { embeddedJsExtractor } from './factories/embeddedJs';

export abstract class HtmlExtractors {
public static elementContent: typeof elementContentExtractor = elementContentExtractor;
public static elementAttribute: typeof elementAttributeExtractor = elementAttributeExtractor;
public static embeddedJs: typeof embeddedJsExtractor = embeddedJsExtractor;
public static embeddedAttributeJs: typeof embeddedAttributeJsExtractor = embeddedAttributeJsExtractor;
}
24 changes: 24 additions & 0 deletions tests/e2e/fixtures/html/linenumberStart.expected.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"

#: tests/e2e/fixtures/html/linenumberStart.html:23
msgid "%{n} apple"
msgid_plural "%{n} apples"
msgstr[0] ""
msgstr[1] ""

#: tests/e2e/fixtures/html/linenumberStart.html:22
msgid "msg 1"
msgstr ""

#: tests/e2e/fixtures/html/linenumberStart.html:24
msgid "msg 2"
msgstr ""

#: tests/e2e/fixtures/html/linenumberStart.html:19
msgctxt "title"
msgid "%{n} apple"
msgid_plural "%{n} apples"
msgstr[0] ""
msgstr[1] ""
18 changes: 18 additions & 0 deletions tests/e2e/fixtures/html/linenumberStart.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>

<head>
<script src="app.js"></script>
</head>

<body>
<div class="app-container" :title="_xn('title', '%{n} apple', '%{n} apples', n, {n:''+n})"
data-name="__('whatever')"></div>
<script>
console.log(__('msg 1'));
console.log(_n('%{n} apple', '%{n} apples', n, { n: '' + n }));
console.log(__('msg 2'));
</script>
</body>

</html>
19 changes: 18 additions & 1 deletion tests/e2e/html.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GettextExtractor, HtmlExtractors, JsExtractors } from '../../dist';
import * as fs from 'fs';
import { GettextExtractor, HtmlExtractors, JsExtractors } from '../../dist';

describe('HTML E2E', () => {

Expand Down Expand Up @@ -59,4 +59,21 @@ describe('HTML E2E', () => {

expect(extractor.getPotString()).toBe(fs.readFileSync(__dirname + '/fixtures/html/embeddedJs.expected.pot').toString());
});

test('line number start 11', () => {
const extractor = new GettextExtractor();
const jsParser = extractor.createJsParser([
JsExtractors.callExpression('__', { arguments: { text: 0, } }),
JsExtractors.callExpression('_n', { arguments: { text: 0, textPlural: 1 } }),
JsExtractors.callExpression('_xn', { arguments: { context: 0, text: 1, textPlural: 2 } }),
]);
const htmlParser = extractor.createHtmlParser([
HtmlExtractors.embeddedAttributeJs(/:title/, jsParser),
HtmlExtractors.embeddedJs('script', jsParser),
]);
htmlParser.parseFile('tests/e2e/fixtures/html/linenumberStart.html', { lineNumberStart: 11 });
expect(extractor.getPotString())
.toBe(fs.readFileSync(__dirname + '/fixtures/html/linenumberStart.expected.pot').toString())
});

});
63 changes: 63 additions & 0 deletions tests/html/extractors/factories/embeddedAttributeJs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { embeddedAttributeJsExtractor } from '../../../../src/html/extractors/factories/embeddedAttributeJs';
import { HtmlParser } from '../../../../src/html/parser';
import { JsParser } from '../../../../src/js/parser';

describe('HTML: Attribute Value as Embedded JS Extractor', () => {
describe('calling js parser', () => {
let jsParserMock: JsParser;

beforeEach(() => {
jsParserMock = <any>{
parseString: jest.fn(),
};
});

test('use regex filter / with line number start', () => {
const htmlParser = new HtmlParser(undefined!, [
embeddedAttributeJsExtractor(/:title/, jsParserMock),
]);
htmlParser.parseString(
`<span :title="__('msg id')" :class="abc">content</span>`,
'foo.html',
{ lineNumberStart: 10 }
);
expect(jsParserMock.parseString).toHaveBeenCalledWith(
`__('msg id')`,
'foo.html',
{
lineNumberStart: 10,
}
);
});

test('use filter function', () => {
const htmlParser = new HtmlParser(undefined!, [
embeddedAttributeJsExtractor((e) => {
return e.name.startsWith(':');
}, jsParserMock),
]);
htmlParser.parseString(
`<span :title="__('title')" class="title">Hello</span>`,
'foo.html'
);
expect(jsParserMock.parseString).toHaveBeenCalledWith(
`__('title')`,
'foo.html',
{ lineNumberStart: 1 }
);
});
});

describe('argument validation', () => {
test('filter: (none)', () => {
expect(() => {
(<any>embeddedAttributeJsExtractor)();
}).toThrowError(`Missing argument 'filter'`);
});
test('jsParser: (none)', () => {
expect(() => {
(<any>embeddedAttributeJsExtractor)(/:title/);
}).toThrowError(`Missing argument 'jsParser'`);
});
});
});

0 comments on commit 4276367

Please sign in to comment.