commit 9bde1c510f3522cfaf533d741cd96f8256035e75
parent 9c58a866775525817851280056322bca25b69c30
Author: Florian Dold <florian@dold.me>
Date: Tue, 19 May 2026 14:25:00 +0200
pogen: use shared tsconfig, fix various issues
This package was previously compiled with less strict TypeScript
settings, leading to some missed typing issues in the code.
Diffstat:
5 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/packages/pogen/bin/pogen b/packages/pogen/bin/pogen
@@ -1,2 +1,2 @@
#!/usr/bin/env -S node --trace-deprecation
-require('../lib/pogen.js').main();
+(await import ('../lib/pogen.js')).main();
diff --git a/packages/pogen/package.json b/packages/pogen/package.json
@@ -11,6 +11,7 @@
"test": "tsc && ava",
"compile": "tsc"
},
+ "type": "module",
"devDependencies": {
"@types/gettext-parser": "^4.0.3",
"ava": "^8.0.0",
@@ -19,7 +20,8 @@
"dependencies": {
"@types/node": "^18.11.17",
"gettext-parser": "^8.0.0",
- "glob": "^13.0.6"
+ "glob": "^13.0.6",
+ "tslib": "^2.8.1"
},
"ava": {
"files": [
diff --git a/packages/pogen/src/potextract.ts b/packages/pogen/src/potextract.ts
@@ -17,9 +17,9 @@
/**
* Imports.
*/
-import * as ts from "typescript";
import * as fs from "node:fs";
import * as path from "node:path";
+import * as ts from "typescript";
const DEFAULT_PO_HEADER = `# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
@@ -42,7 +42,7 @@ msgstr ""
function wordwrap(str: string, width: number = 80): string[] {
var regex = ".{1," + width + "}(\\s|$)|\\S+(\\s|$)";
- return str.match(RegExp(regex, "g"));
+ return str.match(RegExp(regex, "g")) ?? [];
}
function getTemplate(node: ts.Node): string {
@@ -69,7 +69,7 @@ function getComment(
node: ts.Node,
): string {
let lc = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
- let lastComments: ts.CommentRange[];
+ let lastComments: ts.CommentRange[] | undefined = undefined;
for (let l = preLastTokLine; l < lastTokLine; l++) {
let pos = ts.getPositionOfLineAndCharacter(sourceFile, l, 0);
let comments = ts.getTrailingCommentRanges(sourceFile.text, pos);
@@ -78,7 +78,7 @@ function getComment(
}
}
if (!lastComments) {
- return;
+ return "";
}
let candidate = lastComments[lastComments.length - 1];
let candidateEndLine = ts.getLineAndCharacterOfPosition(
@@ -86,7 +86,7 @@ function getComment(
candidate.end,
).line;
if (candidateEndLine != lc.line - 1) {
- return;
+ return "";
}
let text = sourceFile.text.slice(candidate.pos, candidate.end);
switch (candidate.kind) {
@@ -137,6 +137,7 @@ function getPath(node: ts.Node): { path: string[]; ctx: string } {
ctx: str.text,
};
}
+ break;
}
default: {
// console.log("ASDASD", ts.SyntaxKind[node.kind], node);
@@ -199,8 +200,11 @@ const SCREEN_INFO: ScreenInfo = {
function formatScreenId(
sourceFile: ts.SourceFile,
outChunks: string[],
- screenId: string,
-) {
+ screenId: string | undefined,
+): void {
+ if (!screenId) {
+ return;
+ }
const screen = Number.parseInt(screenId, 10);
if (!screen || Number.isNaN(screen)) {
SCREEN_INFO.missing.add(sourceFile.fileName);
@@ -255,23 +259,24 @@ function formatMsgLine(outChunks: string[], head: string, msg: string) {
}
}
-function getJsxElementPath(node: ts.Node) {
- let path;
- let process = (childNode) => {
+function getJsxElementPath(node: ts.Node): string[] {
+ let path: string[] | undefined = undefined;
+ let process = (childNode: ts.Node) => {
switch (childNode.kind) {
case ts.SyntaxKind.JsxOpeningElement: {
let e = childNode as ts.JsxOpeningElement;
- return (path = getPath(e.tagName).path);
+ path = getPath(e.tagName).path;
+ return path;
}
default:
- break;
+ return undefined;
}
};
ts.forEachChild(node, process);
- return path;
+ return path ?? [];
}
-function translateJsxExpression(node: ts.Expression, h) {
+function translateJsxExpression(node: ts.Expression, h: number[]) {
switch (node.kind) {
case ts.SyntaxKind.StringLiteral: {
let e = node as ts.StringLiteral;
@@ -287,7 +292,7 @@ function trim(s: string) {
}
function getJsxAttribute(sour: ts.SourceFile, node: ts.Node) {
- const result = {};
+ const result: Record<string, any> = {};
ts.forEachChild(node, (childNode: ts.Node) => {
switch (childNode.kind) {
case ts.SyntaxKind.JsxOpeningElement: {
@@ -309,9 +314,9 @@ function getJsxAttribute(sour: ts.SourceFile, node: ts.Node) {
}
function getJsxContent(node: ts.Node) {
- let fragments = [];
+ let fragments: string[] = [];
let holeNum = [1];
- let process = (childNode) => {
+ let process = (childNode: ts.Node) => {
switch (childNode.kind) {
case ts.SyntaxKind.JsxText: {
let e = childNode as ts.JsxText;
@@ -324,6 +329,7 @@ function getJsxContent(node: ts.Node) {
t = t + " ";
}
fragments.push(t);
+ break;
}
case ts.SyntaxKind.JsxOpeningElement:
break;
@@ -333,7 +339,9 @@ function getJsxContent(node: ts.Node) {
break;
case ts.SyntaxKind.JsxExpression: {
let e = childNode as ts.JsxExpression;
- fragments.push(translateJsxExpression(e.expression, holeNum));
+ if (!!e.expression) {
+ fragments.push(translateJsxExpression(e.expression, holeNum));
+ }
break;
}
case ts.SyntaxKind.JsxClosingElement:
@@ -358,15 +366,16 @@ function getJsxContent(node: ts.Node) {
return fragments.join("").trim().replace(/ +/g, " ");
}
-function getJsxSingular(node: ts.Node) {
+function getJsxSingular(node: ts.Node): string | undefined {
let res;
- let process = (childNode) => {
+ let process = (childNode: ts.Node) => {
switch (childNode.kind) {
case ts.SyntaxKind.JsxElement: {
let path = getJsxElementPath(childNode);
if (arrayEq(path, ["i18n", "TranslateSingular"])) {
res = getJsxContent(childNode);
}
+ break;
}
default:
break;
@@ -376,15 +385,16 @@ function getJsxSingular(node: ts.Node) {
return res;
}
-function getJsxPlural(node: ts.Node) {
+function getJsxPlural(node: ts.Node): string | undefined {
let res;
- let process = (childNode) => {
+ let process = (childNode: ts.Node) => {
switch (childNode.kind) {
case ts.SyntaxKind.JsxElement: {
let path = getJsxElementPath(childNode);
if (arrayEq(path, ["i18n", "TranslatePlural"])) {
res = getJsxContent(childNode);
}
+ break;
}
default:
break;
@@ -395,10 +405,12 @@ function getJsxPlural(node: ts.Node) {
}
function searchScreenId(parents: ts.Node[], sourceFile: ts.SourceFile) {
- var result = undefined;
+ var result: string | undefined = undefined;
parents.forEach((parent) => {
// console.log("parent => ", ts.SyntaxKind[parent.kind]);
- if (result) return;
+ if (result) {
+ return;
+ }
parent.forEachChild((node) => {
// console.log(" children => ", ts.SyntaxKind[node.kind]);
@@ -409,7 +421,7 @@ function searchScreenId(parents: ts.Node[], sourceFile: ts.SourceFile) {
(d) => d.name.getText(sourceFile) === "TALER_SCREEN_ID",
);
if (found) {
- if (found.initializer.kind === ts.SyntaxKind.NumericLiteral) {
+ if (found?.initializer?.kind === ts.SyntaxKind.NumericLiteral) {
const id = found.initializer.getText(sourceFile);
result = id;
} else {
@@ -693,7 +705,7 @@ function searchIntoParents(directory: string, fileFlag: string) {
return searchIntoParents(parent, fileFlag);
}
-export function potextract(searchPath:string = "./") {
+export function potextract(searchPath: string = "./") {
const configPath = ts.findConfigFile(
searchPath,
ts.sys.fileExists,
@@ -716,6 +728,10 @@ export function potextract(searchPath:string = "./") {
},
);
+ if (!cmdline) {
+ throw Error("cound not parse command line");
+ }
+
const prog = ts.createProgram({
options: cmdline.options,
rootNames: cmdline.fileNames,
diff --git a/packages/pogen/tsconfig.json b/packages/pogen/tsconfig.json
@@ -1,12 +1,8 @@
{
+ "extends": "../../tsconfig.defaults.json",
"compilerOptions": {
- "module": "commonjs",
- "target": "ES2020",
- "noImplicitAny": false,
"outDir": "lib",
- "incremental": true,
- "moduleResolution": "node",
- "sourceMap": true,
+ "rootDir": "./src",
"lib": ["ES2020"],
"types": ["node"]
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
@@ -661,6 +661,9 @@ importers:
glob:
specifier: ^13.0.6
version: 13.0.6
+ tslib:
+ specifier: ^2.8.1
+ version: 2.8.1
devDependencies:
'@types/gettext-parser':
specifier: ^4.0.3
@@ -3785,6 +3788,9 @@ packages:
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -7092,6 +7098,8 @@ snapshots:
tslib@2.6.2: {}
+ tslib@2.8.1: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1