diff --git a/src/js/extractors/factories/htmlTemplate.ts b/src/js/extractors/factories/htmlTemplate.ts
new file mode 100644
index 0000000..5f1bfa9
--- /dev/null
+++ b/src/js/extractors/factories/htmlTemplate.ts
@@ -0,0 +1,22 @@
+import * as ts from 'typescript';
+
+import { IJsExtractorFunction } from '../../../js/parser';
+import { Validate } from '../../../utils/validate';
+import { HtmlParser } from '../../../html/parser';
+
+export function htmlTemplateExtractor(htmlParser: HtmlParser): IJsExtractorFunction {
+ Validate.required.argument({ htmlParser });
+
+ return (node: ts.Node, sourceFile: ts.SourceFile, _, lineNumberStart = 1) => {
+ if (ts.isStringLiteralLike(node)) {
+ const source = node.getText(sourceFile);
+ const location = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
+
+ htmlParser.parseString(
+ source,
+ sourceFile.fileName,
+ { lineNumberStart: lineNumberStart + location.line }
+ );
+ }
+ };
+}
diff --git a/src/js/extractors/index.ts b/src/js/extractors/index.ts
index 2486c0d..4c8bc6e 100644
--- a/src/js/extractors/index.ts
+++ b/src/js/extractors/index.ts
@@ -1,5 +1,7 @@
import { callExpressionExtractor } from './factories/callExpression';
+import { htmlTemplateExtractor } from './factories/htmlTemplate';
export abstract class JsExtractors {
public static callExpression: typeof callExpressionExtractor = callExpressionExtractor;
+ public static htmlTemplate: typeof htmlTemplateExtractor = htmlTemplateExtractor;
}
diff --git a/src/js/parser.ts b/src/js/parser.ts
index 7b2ec3b..7af25cf 100644
--- a/src/js/parser.ts
+++ b/src/js/parser.ts
@@ -3,7 +3,7 @@ import * as ts from 'typescript';
import { Parser, IAddMessageCallback, IParseOptions } from '../parser';
import { IMessage } from '../builder';
-export type IJsExtractorFunction = (node: ts.Node, sourceFile: ts.SourceFile, addMessage: IAddMessageCallback) => void;
+export type IJsExtractorFunction = (node: ts.Node, sourceFile: ts.SourceFile, addMessage: IAddMessageCallback, lineNumberStart: number) => void;
export interface IJsParseOptions extends IParseOptions {
scriptKind?: ts.ScriptKind;
@@ -24,7 +24,7 @@ export class JsParser extends Parser {
});
for (let extractor of this.extractors) {
- extractor(node, sourceFile, addMessageCallback);
+ extractor(node, sourceFile, addMessageCallback, lineNumberStart);
}
ts.forEachChild(node, n => {
diff --git a/tests/js/extractors/factories/htmlTemplate.test.ts b/tests/js/extractors/factories/htmlTemplate.test.ts
new file mode 100644
index 0000000..8e2c655
--- /dev/null
+++ b/tests/js/extractors/factories/htmlTemplate.test.ts
@@ -0,0 +1,148 @@
+import { htmlTemplateExtractor } from '../../../../src/js/extractors/factories/htmlTemplate'
+import { HtmlExtractors } from '../../../../src/html/extractors';
+import { JsParser } from '../../../../src/js/parser';
+import { HtmlParser } from '../../../../src/html/parser';
+import { CatalogBuilder, IMessage } from '../../../../src/builder';
+
+describe('JS: HTML template extractor', () => {
+ describe('calling html parser ', () => {
+ let builder: CatalogBuilder;
+ let messages: IMessage[]
+ let jsParser: JsParser;
+ let htmlParser: HtmlParser;
+
+ beforeEach(() => {
+ messages = [];
+
+ builder = {
+ addMessage: jest.fn((message: IMessage) => {
+ messages.push(message);
+ })
+ };
+
+ htmlParser = new HtmlParser(builder, [
+ HtmlExtractors.elementContent('translate')
+ ]);
+
+ jsParser = new JsParser(builder, [
+ htmlTemplateExtractor(htmlParser)
+ ]);
+ });
+
+ test('single line (regular string)', () => {
+ jsParser.parseString('let itBe = " test
"');
+ expect(messages).toEqual([
+ {
+ text: 'test'
+ }
+ ])
+ });
+
+ test('single line (template string)', () => {
+ jsParser.parseString('let itBe = " test
"');
+ expect(messages).toEqual([
+ {
+ text: 'test'
+ }
+ ])
+ });
+
+ test('with lineNumberStart option (regular string)', () => {
+ jsParser.parseString(
+ 'let itBe = " test
"',
+ 'test',
+ { lineNumberStart: 10 }
+ );
+
+ expect(messages).toEqual([
+ {
+ text: 'test',
+ references: ['test:10'],
+ },
+ ])
+ })
+
+ test('with lineNumberStart option (template string)', () => {
+ jsParser.parseString(
+ 'let itBe = " test
"',
+ 'test',
+ { lineNumberStart: 10 }
+ );
+
+ expect(messages).toEqual([
+ {
+ text: 'test',
+ references: ['test:10'],
+ },
+ ])
+ })
+
+ test('HTML inside a template literal with the correct line numbers', () => {
+ jsParser.parseString(`
+
+
+
+
+
+
+ let tuce = \`
+
+
First level
+
+
Second level
+
Third level
+
+
\`
+ `, 'test')
+
+ expect(messages).toEqual([
+ {
+ text: 'First level',
+ references: ['test:10'],
+ },
+ {
+ text: 'Second level',
+ references: ['test:12'],
+ },
+ {
+ text: 'Third level',
+ references: ['test:13'],
+ },
+ ])
+ })
+
+ test('HTML inside a template literal with correct line numbers and with lineNumberStart', () => {
+ jsParser.parseString(`
+
+
+
+
+
+
+ let tuce = \`
+
+
First level
+
+
Second level
+
Third level
+
+
\`
+ `, 'test', { lineNumberStart: 10 })
+
+ expect(messages).toEqual([
+ {
+ text: 'First level',
+ references: ['test:19'],
+ },
+ {
+ text: 'Second level',
+ references: ['test:21'],
+ },
+ {
+ text: 'Third level',
+ references: ['test:22'],
+ },
+ ])
+ })
+ })
+})
\ No newline at end of file