aboutsummaryrefslogtreecommitdiff
path: root/node_modules/pogen
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-24 15:10:37 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-24 15:11:17 +0200
commit7a3df06eb573d36142bd1a8e03c5ce8752d300b3 (patch)
tree70bfaea8884c374876f607774850a3a51c0cb381 /node_modules/pogen
parentaca1143cb9eed16cf37f04e475e4257418dd18ac (diff)
downloadwallet-core-7a3df06eb573d36142bd1a8e03c5ce8752d300b3.tar.xz
fix build issues and add typedoc
Diffstat (limited to 'node_modules/pogen')
-rw-r--r--node_modules/pogen/.gitignore1
-rw-r--r--node_modules/pogen/dumpTree.ts51
-rw-r--r--node_modules/pogen/example/messages.po107
-rw-r--r--node_modules/pogen/example/test.ts63
-rw-r--r--node_modules/pogen/example/test2.tsx15
-rw-r--r--node_modules/pogen/package.json13
-rw-r--r--node_modules/pogen/pogen.js340
-rw-r--r--node_modules/pogen/pogen.ts393
-rw-r--r--node_modules/pogen/tsconfig.json11
9 files changed, 994 insertions, 0 deletions
diff --git a/node_modules/pogen/.gitignore b/node_modules/pogen/.gitignore
new file mode 100644
index 000000000..a6c7c2852
--- /dev/null
+++ b/node_modules/pogen/.gitignore
@@ -0,0 +1 @@
+*.js
diff --git a/node_modules/pogen/dumpTree.ts b/node_modules/pogen/dumpTree.ts
new file mode 100644
index 000000000..958c79416
--- /dev/null
+++ b/node_modules/pogen/dumpTree.ts
@@ -0,0 +1,51 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+
+/**
+ * Print the syntax tree of a TypeScript program.
+ *
+ * @author Florian Dold
+ */
+
+/// <reference path="../decl/node.d.ts" />
+
+"use strict";
+
+import {readFileSync} from "fs";
+import {execSync} from "child_process";
+import * as ts from "typescript";
+
+
+export function processFile(sourceFile: ts.SourceFile) {
+ processNode(sourceFile);
+
+ function processNode(node: ts.Node, level=0) {
+ let indent = "";
+ for (let i = 0; i < level; i++) {
+ indent = indent + " ";
+ }
+ console.log(indent + ts.SyntaxKind[node.kind]);
+ ts.forEachChild(node, (n) => processNode(n, level+1));
+ }
+}
+
+const fileNames = process.argv.slice(2);
+
+fileNames.forEach(fileName => {
+ let sourceFile = ts.createSourceFile(fileName, readFileSync(fileName).toString(), ts.ScriptTarget.ES2016, /*setParentNodes */ true);
+ processFile(sourceFile);
+});
diff --git a/node_modules/pogen/example/messages.po b/node_modules/pogen/example/messages.po
new file mode 100644
index 000000000..1addae3f2
--- /dev/null
+++ b/node_modules/pogen/example/messages.po
@@ -0,0 +1,107 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2016-01-27 01:51+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: example/test.ts:3
+#, csharp-format
+msgid "Hello1, World"
+msgstr ""
+
+#: example/test.ts:4
+#, csharp-format
+msgid "Hello2, World"
+msgstr ""
+
+#: example/test.ts:5
+#, csharp-format
+msgid "Hello3, World"
+msgstr ""
+
+#. This is a comment and should be included
+#: example/test.ts:9
+#, csharp-format
+msgid "Hello4, World"
+msgstr ""
+
+#: example/test.ts:12
+#, csharp-format
+msgid "Hello5, World"
+msgstr ""
+
+#: example/test.ts:13
+#, csharp-format
+msgid "Hello6,{0} World"
+msgstr ""
+
+#. This one has a multi line comment.
+#. It has multiple lines, and a trailing empty line.
+#.
+#: example/test.ts:20
+#, csharp-format
+msgid "Hello7,{0} World{1}"
+msgstr ""
+
+#: example/test.ts:21
+#, csharp-format
+msgid "{0}Hello8,{1} World{2}"
+msgstr ""
+
+#.
+#. This one has a multi line comment.
+#. It has multiple lines, and a leading empty line.
+#: example/test.ts:28
+#, csharp-format
+msgid "Hello9,\" '\" World"
+msgstr ""
+
+#: example/test.ts:32
+#, csharp-format
+msgid ""
+"Hello10\n"
+" ,\" '\" Wo\n"
+" rld"
+msgstr ""
+
+#: example/test.ts:37
+#, csharp-format
+msgid ""
+"Hello11 this is a long long string\n"
+"it will go over multiple lines and in the pofile\n"
+"it should be wrapped and stuff"
+msgstr ""
+
+#. This is a single line comment
+#: example/test.ts:42
+#, csharp-format
+msgid ""
+"Hello12 this is a long long string it will go over multiple lines and in the "
+"pofile it should be wrapped and stuff. asdf asdf asdf asdf asdf asdf asdf asdf "
+"adsf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf "
+"asdf"
+msgstr ""
+
+#: example/test.ts:42
+#, csharp-format
+msgid "This message appears twice"
+msgstr ""
+
+#: example/test.ts:45
+#, csharp-format
+msgid "This message appears twice"
+msgstr ""
+
diff --git a/node_modules/pogen/example/test.ts b/node_modules/pogen/example/test.ts
new file mode 100644
index 000000000..d7d5d88d6
--- /dev/null
+++ b/node_modules/pogen/example/test.ts
@@ -0,0 +1,63 @@
+declare var i18n: any;
+
+console.log(i18n`Hello1, World`);
+console.log(i18n.foo()`Hello2, World`);
+console.log(i18n.foo()`Hello3, World`);
+
+
+/* This is a comment and should be included */
+console.log(i18n().foo()`Hello4, World`);
+
+
+console.log(i18n.foo`Hello5, World`);
+console.log(i18n.foo`Hello6,${123} World`);
+
+/*
+This one has a multi line comment.
+It has multiple lines, and a trailing empty line.
+
+*/
+console.log(/*lol*/i18n.foo`Hello7,${123} World${42}`);
+
+
+i18n.plural(i18n`one ${"foo"}`, i18`many ${"bar"}`);
+
+i18n.plural(i18n.foo`one bla ${"foo"}`, i18.foo`many bla ${"bar"}`);
+
+let x = 42;
+
+i18n.plural(i18n`I have ${x} apple`, i18n`I have ${x} apples`);
+
+console.log(i18n`${"foo"}Hello8,${123} World${42}`);
+
+/*
+
+This one has a multi line comment.
+It has multiple lines, and a leading empty line.
+*/
+console.log(i18n`Hello9," '" World`);
+
+// Comments with space inbetween do not count
+
+console.log(i18n`Hello10
+ ," '" Wo
+ rld`);
+
+
+console.log(i18n`Hello11 this is a long long string
+it will go over multiple lines and in the pofile
+it should be wrapped and stuff`);
+
+// This is a single line comment
+console.log(i18n`Hello12 this is a long long string it will go over multiple lines and in the pofile it should be wrapped and stuff. asdf asdf asdf asdf asdf asdf asdf asdf adsf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf`);
+
+function foo(...args: any[]) {
+}
+
+console.log(foo`Another string, must be excluded`);
+
+
+// First occurence
+console.log(i18n`This message appears twice`);
+// Second occurence
+console.log(i18n`This message appears twice`);
diff --git a/node_modules/pogen/example/test2.tsx b/node_modules/pogen/example/test2.tsx
new file mode 100644
index 000000000..4133f86fb
--- /dev/null
+++ b/node_modules/pogen/example/test2.tsx
@@ -0,0 +1,15 @@
+let x = <i18n.Translate>foo
+{bar} {" foo "} baz</i18n.Translate>
+
+
+let y = (
+ <i18n.TranslateSwitch>
+ <i18n.TranslateSingular>
+ singular form
+ second line
+ </i18n.TranslateSingular>
+ <i18n.TranslatePlural>
+ plural form
+ </i18n.TranslatePlural>
+ </i18n.TranslateSwitch>
+);
diff --git a/node_modules/pogen/package.json b/node_modules/pogen/package.json
new file mode 100644
index 000000000..7b8b5008f
--- /dev/null
+++ b/node_modules/pogen/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "pogen",
+ "version": "1.0.0",
+ "main": "pogen.js",
+ "author": "Florian Dold",
+ "license": "GPL-2.0+",
+ "scripts": {
+ "build": "tsc"
+ },
+ "devDependencies": {
+ "typescript": "^2.2.2"
+ }
+}
diff --git a/node_modules/pogen/pogen.js b/node_modules/pogen/pogen.js
new file mode 100644
index 000000000..6cb5e4ed9
--- /dev/null
+++ b/node_modules/pogen/pogen.js
@@ -0,0 +1,340 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * Generate .po file from list of source files.
+ *
+ * Note that duplicate message IDs are NOT merged, to get the same output as
+ * you would from xgettext, just run msguniq.
+ *
+ * @author Florian Dold
+ */
+/// <reference path="../decl/node.d.ts" />
+"use strict";
+var fs_1 = require("fs");
+var ts = require("typescript");
+function wordwrap(str, width) {
+ if (width === void 0) { width = 80; }
+ var regex = '.{1,' + width + '}(\\s|$)|\\S+(\\s|$)';
+ return str.match(RegExp(regex, 'g'));
+}
+function processFile(sourceFile) {
+ processNode(sourceFile);
+ var lastTokLine = 0;
+ var preLastTokLine = 0;
+ function getTemplate(node) {
+ switch (node.kind) {
+ case ts.SyntaxKind.FirstTemplateToken:
+ return node.text;
+ case ts.SyntaxKind.TemplateExpression:
+ var te = node;
+ var textFragments = [te.head.text];
+ for (var _i = 0, _a = te.templateSpans; _i < _a.length; _i++) {
+ var tsp = _a[_i];
+ textFragments.push("%" + ((textFragments.length - 1) / 2 + 1) + "$s");
+ textFragments.push(tsp.literal.text.replace(/%/g, "%%"));
+ }
+ return textFragments.join('');
+ default:
+ return "(pogen.ts: unable to parse)";
+ }
+ }
+ function getComment(node) {
+ var lc = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
+ var lastComments;
+ for (var l = preLastTokLine; l < lastTokLine; l++) {
+ var pos = ts.getPositionOfLineAndCharacter(sourceFile, l, 0);
+ var comments = ts.getTrailingCommentRanges(sourceFile.text, pos);
+ if (comments) {
+ lastComments = comments;
+ }
+ }
+ if (!lastComments) {
+ return;
+ }
+ var candidate = lastComments[lastComments.length - 1];
+ var candidateEndLine = ts.getLineAndCharacterOfPosition(sourceFile, candidate.end).line;
+ if (candidateEndLine != lc.line - 1) {
+ return;
+ }
+ var text = sourceFile.text.slice(candidate.pos, candidate.end);
+ switch (candidate.kind) {
+ case ts.SyntaxKind.SingleLineCommentTrivia:
+ // Remove comment leader
+ text = text.replace(/^[/][/]\s*/, "");
+ break;
+ case ts.SyntaxKind.MultiLineCommentTrivia:
+ // Remove comment leader and trailer,
+ // handling white space just like xgettext.
+ text = text
+ .replace(/^[/][*](\s*?\n|\s*)?/, "")
+ .replace(/(\n[ \t]*?)?[*][/]$/, "");
+ break;
+ }
+ return text;
+ }
+ function getPath(node) {
+ switch (node.kind) {
+ case ts.SyntaxKind.PropertyAccessExpression:
+ var pae = node;
+ return Array.prototype.concat(getPath(pae.expression), [pae.name.text]);
+ case ts.SyntaxKind.Identifier:
+ var id = node;
+ return [id.text];
+ }
+ return ["(other)"];
+ }
+ function arrayEq(a1, a2) {
+ if (a1.length != a2.length) {
+ return false;
+ }
+ for (var i = 0; i < a1.length; i++) {
+ if (a1[i] != a2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ function processTaggedTemplateExpression(tte) {
+ var lc = ts.getLineAndCharacterOfPosition(sourceFile, tte.pos);
+ if (lc.line != lastTokLine) {
+ preLastTokLine = lastTokLine;
+ lastTokLine = lc.line;
+ }
+ var path = getPath(tte.tag);
+ var res = {
+ path: path,
+ line: lc.line,
+ comment: getComment(tte),
+ template: getTemplate(tte.template).replace(/"/g, '\\"'),
+ };
+ return res;
+ }
+ function formatMsgComment(line, comment) {
+ if (comment) {
+ for (var _i = 0, _a = comment.split('\n'); _i < _a.length; _i++) {
+ var cl = _a[_i];
+ console.log("#. " + cl);
+ }
+ }
+ console.log("#: " + sourceFile.fileName + ":" + (line + 1));
+ console.log("#, c-format");
+ }
+ function formatMsgLine(head, msg) {
+ // Do escaping, wrap break at newlines
+ var parts = msg
+ .match(/(.*\n|.+$)/g)
+ .map(function (x) { return x.replace(/\n/g, '\\n'); })
+ .map(function (p) { return wordwrap(p); })
+ .reduce(function (a, b) { return a.concat(b); });
+ if (parts.length == 1) {
+ console.log(head + " \"" + parts[0] + "\"");
+ }
+ else {
+ console.log(head + " \"\"");
+ for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
+ var p = parts_1[_i];
+ console.log("\"" + p + "\"");
+ }
+ }
+ }
+ function getJsxElementPath(node) {
+ var path;
+ var process = function (childNode) {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxOpeningElement:
+ {
+ var e = childNode;
+ return path = getPath(e.tagName);
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return path;
+ }
+ function translateJsxExpression(node, h) {
+ switch (node.kind) {
+ case ts.SyntaxKind.StringLiteral:
+ {
+ var e = node;
+ return e.text;
+ }
+ default:
+ return "%" + h[0]++ + "$s";
+ }
+ }
+ function trim(s) {
+ return s.replace(/^[ \n\t]*/, "").replace(/[ \n\t]*$/, "");
+ }
+ function getJsxContent(node) {
+ var fragments = [];
+ var holeNum = [1];
+ var process = function (childNode) {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxText:
+ {
+ var e = childNode;
+ var t = e.getText().split("\n").map(trim).join("\n");
+ fragments.push(t);
+ }
+ case ts.SyntaxKind.JsxOpeningElement:
+ break;
+ case ts.SyntaxKind.JsxElement:
+ fragments.push("%" + holeNum[0]++ + "$s");
+ break;
+ case ts.SyntaxKind.JsxExpression:
+ {
+ var e = childNode;
+ fragments.push(translateJsxExpression(e.expression, holeNum));
+ break;
+ }
+ case ts.SyntaxKind.JsxClosingElement:
+ break;
+ default:
+ var lc = ts.getLineAndCharacterOfPosition(childNode.getSourceFile(), childNode.getStart());
+ console.error("unrecognized syntax in JSX Element " + ts.SyntaxKind[childNode.kind] + " (" + childNode.getSourceFile().fileName + ":" + (lc.line + 1) + ":" + (lc.character + 1));
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return fragments.join("");
+ }
+ function getJsxSingular(node) {
+ var res;
+ var process = function (childNode) {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxElement:
+ {
+ var path = getJsxElementPath(childNode);
+ if (arrayEq(path, ["i18n", "TranslateSingular"])) {
+ res = getJsxContent(childNode);
+ }
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return res;
+ }
+ function getJsxPlural(node) {
+ var res;
+ var process = function (childNode) {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxElement:
+ {
+ var path = getJsxElementPath(childNode);
+ if (arrayEq(path, ["i18n", "TranslatePlural"])) {
+ res = getJsxContent(childNode);
+ }
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return res;
+ }
+ function processNode(node) {
+ switch (node.kind) {
+ case ts.SyntaxKind.JsxElement:
+ var path = getJsxElementPath(node);
+ if (arrayEq(path, ["i18n", "Translate"])) {
+ var content = getJsxContent(node);
+ var line = ts.getLineAndCharacterOfPosition(sourceFile, node.pos).line;
+ var comment = getComment(node);
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", content);
+ console.log("msgstr \"\"");
+ console.log();
+ return;
+ }
+ if (arrayEq(path, ["i18n", "TranslateSwitch"])) {
+ var line = ts.getLineAndCharacterOfPosition(sourceFile, node.pos).line;
+ var comment = getComment(node);
+ formatMsgComment(line, comment);
+ var singularForm = getJsxSingular(node);
+ if (!singularForm) {
+ console.error("singular form missing");
+ process.exit(1);
+ }
+ var pluralForm = getJsxPlural(node);
+ if (!pluralForm) {
+ console.error("plural form missing");
+ process.exit(1);
+ }
+ formatMsgLine("msgid", singularForm);
+ formatMsgLine("msgid_plural", pluralForm);
+ console.log("msgstr[0] \"\"");
+ console.log("msgstr[1] \"\"");
+ console.log();
+ return;
+ }
+ break;
+ case ts.SyntaxKind.CallExpression:
+ {
+ // might be i18n.plural(i18n[.X]`...`, i18n[.X]`...`)
+ var ce = node;
+ var path_1 = getPath(ce.expression);
+ if (!arrayEq(path_1, ["i18n", "plural"])) {
+ break;
+ }
+ if (ce.arguments[0].kind != ts.SyntaxKind.TaggedTemplateExpression) {
+ break;
+ }
+ if (ce.arguments[1].kind != ts.SyntaxKind.TaggedTemplateExpression) {
+ break;
+ }
+ var line = ts.getLineAndCharacterOfPosition(sourceFile, ce.pos).line;
+ var t1 = processTaggedTemplateExpression(ce.arguments[0]);
+ var t2 = processTaggedTemplateExpression(ce.arguments[1]);
+ var comment = getComment(ce);
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", t1.template);
+ formatMsgLine("msgid_plural", t2.template);
+ console.log("msgstr[0] \"\"");
+ console.log("msgstr[1] \"\"");
+ console.log();
+ // Important: no processing for child i18n expressions here
+ return;
+ }
+ case ts.SyntaxKind.TaggedTemplateExpression:
+ {
+ var tte = node;
+ var _a = processTaggedTemplateExpression(tte), comment = _a.comment, template = _a.template, line = _a.line, path_2 = _a.path;
+ if (path_2[0] != "i18n") {
+ break;
+ }
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", template);
+ console.log("msgstr \"\"");
+ console.log();
+ break;
+ }
+ }
+ ts.forEachChild(node, processNode);
+ }
+}
+exports.processFile = processFile;
+var fileNames = process.argv.slice(2);
+console.log("# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-23 00:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"");
+console.log();
+fileNames.sort();
+fileNames.forEach(function (fileName) {
+ var sourceFile = ts.createSourceFile(fileName, fs_1.readFileSync(fileName).toString(), ts.ScriptTarget.ES2016, /*setParentNodes */ true);
+ processFile(sourceFile);
+});
diff --git a/node_modules/pogen/pogen.ts b/node_modules/pogen/pogen.ts
new file mode 100644
index 000000000..1d31a878a
--- /dev/null
+++ b/node_modules/pogen/pogen.ts
@@ -0,0 +1,393 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+
+/**
+ * Generate .po file from list of source files.
+ *
+ * Note that duplicate message IDs are NOT merged, to get the same output as
+ * you would from xgettext, just run msguniq.
+ *
+ * @author Florian Dold
+ */
+
+/// <reference path="../decl/node.d.ts" />
+
+"use strict";
+
+import {readFileSync} from "fs";
+import * as ts from "typescript";
+
+
+function wordwrap(str: string, width: number = 80): string[] {
+ var regex = '.{1,' + width + '}(\\s|$)|\\S+(\\s|$)';
+ return str.match(RegExp(regex, 'g'));
+}
+
+export function processFile(sourceFile: ts.SourceFile) {
+ processNode(sourceFile);
+ let lastTokLine = 0;
+ let preLastTokLine = 0;
+
+ function getTemplate(node: ts.Node): string {
+ switch (node.kind) {
+ case ts.SyntaxKind.FirstTemplateToken:
+ return (<any>node).text;
+ case ts.SyntaxKind.TemplateExpression:
+ let te = <ts.TemplateExpression>node;
+ let textFragments = [te.head.text];
+ for (let tsp of te.templateSpans) {
+ textFragments.push(`%${(textFragments.length-1)/2+1}$s`);
+ textFragments.push(tsp.literal.text.replace(/%/g, "%%"));
+ }
+ return textFragments.join('');
+ default:
+ return "(pogen.ts: unable to parse)";
+ }
+ }
+
+ function getComment(node: ts.Node): string {
+ let lc = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
+ let lastComments;
+ for (let l = preLastTokLine; l < lastTokLine; l++) {
+ let pos = ts.getPositionOfLineAndCharacter(sourceFile, l, 0);
+ let comments = ts.getTrailingCommentRanges(sourceFile.text, pos);
+ if (comments) {
+ lastComments = comments;
+ }
+ }
+ if (!lastComments) {
+ return;
+ }
+ let candidate = lastComments[lastComments.length-1];
+ let candidateEndLine = ts.getLineAndCharacterOfPosition(sourceFile, candidate.end).line;
+ if (candidateEndLine != lc.line - 1) {
+ return;
+ }
+ let text = sourceFile.text.slice(candidate.pos, candidate.end);
+ switch (candidate.kind) {
+ case ts.SyntaxKind.SingleLineCommentTrivia:
+ // Remove comment leader
+ text = text.replace(/^[/][/]\s*/, "");
+ break;
+ case ts.SyntaxKind.MultiLineCommentTrivia:
+ // Remove comment leader and trailer,
+ // handling white space just like xgettext.
+ text = text
+ .replace(/^[/][*](\s*?\n|\s*)?/, "")
+ .replace(/(\n[ \t]*?)?[*][/]$/, "");
+ break;
+ }
+ return text;
+ }
+
+ function getPath(node: ts.Node): string[] {
+ switch (node.kind) {
+ case ts.SyntaxKind.PropertyAccessExpression:
+ let pae = <ts.PropertyAccessExpression>node;
+ return Array.prototype.concat(getPath(pae.expression), [pae.name.text]);
+ case ts.SyntaxKind.Identifier:
+ let id = <ts.Identifier>node;
+ return [id.text];
+ }
+ return ["(other)"];
+ }
+
+ function arrayEq<T>(a1: T[], a2: T[]) {
+ if (a1.length != a2.length) {
+ return false;
+ }
+ for (let i = 0; i < a1.length; i++) {
+ if (a1[i] != a2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ interface TemplateResult {
+ comment: string;
+ path: string[];
+ template: string;
+ line: number;
+ }
+
+ function processTaggedTemplateExpression(tte: ts.TaggedTemplateExpression): TemplateResult {
+ let lc = ts.getLineAndCharacterOfPosition(sourceFile, tte.pos);
+ if (lc.line != lastTokLine) {
+ preLastTokLine = lastTokLine;
+ lastTokLine = lc.line;
+ }
+ let path = getPath(tte.tag)
+ let res: TemplateResult = {
+ path,
+ line: lc.line,
+ comment: getComment(tte),
+ template: getTemplate(tte.template).replace(/"/g, '\\"'),
+ };
+ return res;
+ }
+
+ function formatMsgComment(line: number, comment?: string) {
+ if (comment) {
+ for (let cl of comment.split('\n')) {
+ console.log(`#. ${cl}`);
+ }
+ }
+ console.log(`#: ${sourceFile.fileName}:${line+1}`);
+ console.log(`#, c-format`);
+ }
+
+ function formatMsgLine(head: string, msg: string) {
+ // Do escaping, wrap break at newlines
+ let parts = msg
+ .match(/(.*\n|.+$)/g)
+ .map((x) => x.replace(/\n/g, '\\n'))
+ .map((p) => wordwrap(p))
+ .reduce((a,b) => a.concat(b));
+ if (parts.length == 1) {
+ console.log(`${head} "${parts[0]}"`);
+ } else {
+ console.log(`${head} ""`);
+ for (let p of parts) {
+ console.log(`"${p}"`);
+ }
+ }
+ }
+
+ interface JsxProcessingContext {
+
+ }
+
+ function getJsxElementPath(node: ts.Node) {
+ let path;
+ let process = (childNode) => {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxOpeningElement:
+ {
+ let e = childNode as ts.JsxOpeningElement;
+ return path = getPath(e.tagName);
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return path;
+ }
+
+ function translateJsxExpression(node: ts.Node, h) {
+ switch (node.kind) {
+ case ts.SyntaxKind.StringLiteral:
+ {
+ let e = node as ts.StringLiteral;
+ return e.text;
+ }
+ default:
+ return `%${h[0]++}$s`;
+ }
+ }
+
+ function trim(s) {
+ return s.replace(/^[ \n\t]*/, "").replace(/[ \n\t]*$/, "");
+ }
+
+ function getJsxContent(node: ts.Node) {
+ let fragments = [];
+ let holeNum = [1];
+ let process = (childNode) => {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxText:
+ {
+ let e = childNode as ts.JsxText;
+ let t = e.getText().split("\n").map(trim).join("\n");
+ fragments.push(t);
+ }
+ case ts.SyntaxKind.JsxOpeningElement:
+ break;
+ case ts.SyntaxKind.JsxElement:
+ fragments.push(`%${holeNum[0]++}$s`);
+ break;
+ case ts.SyntaxKind.JsxExpression:
+ {
+ let e = childNode as ts.JsxExpression;
+ fragments.push(translateJsxExpression(e.expression, holeNum));
+ break;
+ }
+ case ts.SyntaxKind.JsxClosingElement:
+ break;
+ default:
+ let lc = ts.getLineAndCharacterOfPosition(childNode.getSourceFile(), childNode.getStart());
+ console.error(`unrecognized syntax in JSX Element ${ts.SyntaxKind[childNode.kind]} (${childNode.getSourceFile().fileName}:${lc.line+1}:${lc.character+1}`);
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return fragments.join("");
+ }
+
+ function getJsxSingular(node: ts.Node) {
+ let res;
+ let process = (childNode) => {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxElement:
+ {
+ let path = getJsxElementPath(childNode);
+ if (arrayEq(path, ["i18n", "TranslateSingular"])) {
+ res = getJsxContent(childNode);
+ }
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return res;
+ }
+
+ function getJsxPlural(node: ts.Node) {
+ let res;
+ let process = (childNode) => {
+ switch (childNode.kind) {
+ case ts.SyntaxKind.JsxElement:
+ {
+ let path = getJsxElementPath(childNode);
+ if (arrayEq(path, ["i18n", "TranslatePlural"])) {
+ res = getJsxContent(childNode);
+ }
+ }
+ default:
+ break;
+ }
+ };
+ ts.forEachChild(node, process);
+ return res;
+ }
+
+
+ function processNode(node: ts.Node) {
+ switch (node.kind) {
+ case ts.SyntaxKind.JsxElement:
+ let path = getJsxElementPath(node);
+ if (arrayEq(path, ["i18n", "Translate"])) {
+ let content = getJsxContent(node);
+ let {line} = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
+ let comment = getComment(node);
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", content);
+ console.log(`msgstr ""`);
+ console.log();
+ return;
+ }
+ if (arrayEq(path, ["i18n", "TranslateSwitch"])) {
+ let {line} = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
+ let comment = getComment(node);
+ formatMsgComment(line, comment);
+ let singularForm = getJsxSingular(node);
+ if (!singularForm) {
+ console.error("singular form missing");
+ process.exit(1);
+ }
+ let pluralForm = getJsxPlural(node);
+ if (!pluralForm) {
+ console.error("plural form missing");
+ process.exit(1);
+ }
+ formatMsgLine("msgid", singularForm);
+ formatMsgLine("msgid_plural", pluralForm);
+ console.log(`msgstr[0] ""`);
+ console.log(`msgstr[1] ""`);
+ console.log();
+ return;
+ }
+ break;
+ case ts.SyntaxKind.CallExpression:
+ {
+ // might be i18n.plural(i18n[.X]`...`, i18n[.X]`...`)
+ let ce = <ts.CallExpression>node;
+ let path = getPath(ce.expression);
+ if (!arrayEq(path, ["i18n", "plural"])) {
+ break;
+ }
+ if (ce.arguments[0].kind != ts.SyntaxKind.TaggedTemplateExpression) {
+ break;
+ }
+ if (ce.arguments[1].kind != ts.SyntaxKind.TaggedTemplateExpression) {
+ break;
+ }
+ let {line} = ts.getLineAndCharacterOfPosition(sourceFile, ce.pos);
+ let t1 = processTaggedTemplateExpression(<ts.TaggedTemplateExpression>ce.arguments[0]);
+ let t2 = processTaggedTemplateExpression(<ts.TaggedTemplateExpression>ce.arguments[1]);
+ let comment = getComment(ce);
+
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", t1.template);
+ formatMsgLine("msgid_plural", t2.template);
+ console.log(`msgstr[0] ""`);
+ console.log(`msgstr[1] ""`);
+ console.log();
+
+ // Important: no processing for child i18n expressions here
+ return;
+ }
+ case ts.SyntaxKind.TaggedTemplateExpression:
+ {
+ let tte = <ts.TaggedTemplateExpression>node;
+ let {comment, template, line, path} = processTaggedTemplateExpression(tte);
+ if (path[0] != "i18n") {
+ break;
+ }
+ formatMsgComment(line, comment);
+ formatMsgLine("msgid", template);
+ console.log(`msgstr ""`);
+ console.log();
+ break;
+ }
+ }
+
+ ts.forEachChild(node, processNode);
+ }
+}
+
+const fileNames = process.argv.slice(2);
+
+console.log(
+`# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"Report-Msgid-Bugs-To: \\n"
+"POT-Creation-Date: 2016-11-23 00:00+0100\\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
+"Language-Team: LANGUAGE <LL@li.org>\\n"
+"Language: \\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"`);
+console.log()
+
+fileNames.sort();
+
+fileNames.forEach(fileName => {
+ let sourceFile = ts.createSourceFile(fileName, readFileSync(fileName).toString(), ts.ScriptTarget.ES2016, /*setParentNodes */ true);
+ processFile(sourceFile);
+});
diff --git a/node_modules/pogen/tsconfig.json b/node_modules/pogen/tsconfig.json
new file mode 100644
index 000000000..3d2b2c002
--- /dev/null
+++ b/node_modules/pogen/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "es5",
+ "noImplicitAny": false,
+ "sourceMap": false
+ },
+ "files": [
+ "pogen.ts"
+ ]
+}