Skip to content

Commit 0123a7b

Browse files
authored
Merge pull request #81 from wp-blocks/generateHeader-fallback
Generate header fallback
2 parents 3279172 + 5fc4770 commit 0123a7b

5 files changed

Lines changed: 115 additions & 51 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"type-check": "npx tsc --noEmit",
5454
"update-pkg": "npm upgrade -S",
5555
"rm": "rmdir /s /q lib",
56-
"test:build": "npx esbuild ./src/**/* --format=cjs --sourcemap --outdir=lib --platform=node",
56+
"test:build": "npx esbuild ./src/**/* ./src/*.ts --format=cjs --sourcemap --outdir=lib --platform=node",
5757
"test": "npm run test:build && node --test",
5858
"build:build-ci": "npx esbuild ./src/index.ts --format=cjs --outdir=lib --bundle --external:tree-sitter --external:tree-sitter-typescript --external:tree-sitter-php --external:tree-sitter-javascript --external:@babel/preset-typescript --platform=node",
5959
"test:ci": "npm run build:build-ci && npm run test",
@@ -84,4 +84,4 @@
8484
"esbuild": "0.25.9",
8585
"typescript": "^5.9.3"
8686
}
87-
}
87+
}

src/extractors/auditStrings.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ export function audit(args: Args, translationsUnion: SetOfBlocks) {
1212
console.log("\nAudit Complete!");
1313
if (auditor.getResults().length === 0) {
1414
console.log("No issues found! 🎉");
15-
//if there are no errors, we can remove the audit.log file
15+
// if there are no errors, we can remove the audit.log file
1616
try {
1717
unlinkSync(path.join(args.paths.cwd, "audit.log"));
1818
} catch (_error) {
1919
//ignore
2020
}
2121
} else {
2222
console.log(`Found ${auditor.getResults().length} issues!`);
23-
const results = auditor.getResults().join("\n");
24-
console.log(results);
23+
// Print the results if not in silent mode
24+
if (args.options?.silent !== true) {
25+
const results = auditor.getResults().join("\n");
26+
console.log(results);
27+
}
2528
/** Write the audit results to a file */
26-
writeFileSync(path.join(args.paths.cwd, "audit.log"), results);
29+
writeFileSync(path.join(args.paths.cwd, "audit.log"), auditor.getResults().join("\n"));
2730
}
2831
}
2932

src/extractors/headers.ts

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import path from 'node:path'
2+
import process from 'node:process'
3+
import * as readline from 'node:readline'
24
import { SetOfBlocks } from 'gettext-merger'
35
import { modulePath } from '../const.js'
46
import { getEncodingCharset } from '../fs/fs.js'
@@ -12,11 +14,13 @@ import { extractPhpPluginData } from './php.js'
1214
* Checks if required fields are missing and logs a clear error message
1315
* @param {object} headerData - The header data to validate
1416
* @param {boolean} debug - Debug mode flag
17+
* @param {boolean} silent - Silent mode flag
1518
* @returns {boolean} - true if all required fields are present, false otherwise
1619
*/
1720
function validateRequiredFields(
1821
headerData: I18nHeaders,
1922
debug: boolean,
23+
silent = false,
2024
): boolean {
2125
// Define the required fields with strict key types
2226
const requiredFields: {
@@ -40,39 +44,41 @@ function validateRequiredFields(
4044
);
4145

4246
if (missingFields.length > 0) {
43-
console.error("\n! Missing required information for POT file header:\n");
47+
if (!silent) {
48+
console.error("\n! Missing required information for POT file header:\n");
4449

45-
for (const field of missingFields) {
46-
console.error(
47-
` - ${field.name} is missing or has a default value (eg. version: 0.0.1")`,
48-
);
49-
}
50-
51-
console.error(
52-
"\nPlease provide this information adding the missing fields inside the headers object of the plugin/theme declaration or to the package.json file.",
53-
"\nFor more information check the documentation at https://github.com/wp-blocks/makePot",
54-
);
50+
for (const field of missingFields) {
51+
console.error(
52+
` - ${field.name} is missing or has a default value (eg. version: 0.0.1")`,
53+
);
54+
}
5555

56-
if (missingFields.some((field) => field.key === "email")) {
5756
console.error(
58-
"\n\nWordpress didn't require an email field in the headers object but it's required in order to generate a valid pot file.",
59-
'\nPlease add the email field to the package.json file (author field eg. author: "AUTHOR <EMAIL>")',
60-
'\nor inject those information using the --headers flag to the "makePot" command (eg. --headers=email:erik@ck.it).',
57+
"\nPlease provide this information adding the missing fields inside the headers object of the plugin/theme declaration or to the package.json file.",
6158
"\nFor more information check the documentation at https://github.com/wp-blocks/makePot",
6259
);
63-
}
6460

65-
if (missingFields && debug) {
66-
console.error(
67-
"\nDebug information:",
68-
"\nMissing fields:",
69-
missingFields,
70-
"\nHeader data:",
71-
headerData,
72-
);
73-
}
61+
if (missingFields.some((field) => field.key === "email")) {
62+
console.error(
63+
"\n\nWordpress didn't require an email field in the headers object but it's required in order to generate a valid pot file.",
64+
'\nPlease add the email field to the package.json file (author field eg. author: "AUTHOR <EMAIL>")',
65+
'\nor inject those information using the --headers flag to the "makePot" command (eg. --headers=email:erik@ck.it).',
66+
"\nFor more information check the documentation at https://github.com/wp-blocks/makePot",
67+
);
68+
}
7469

75-
console.error("\n");
70+
if (missingFields && debug) {
71+
console.error(
72+
"\nDebug information:",
73+
"\nMissing fields:",
74+
missingFields,
75+
"\nHeader data:",
76+
headerData,
77+
);
78+
}
79+
80+
console.error("\n");
81+
}
7682

7783
return false;
7884
}
@@ -153,10 +159,7 @@ export function getAuthorFromPackage(
153159
} else if (Array.isArray(value)) {
154160
for (const author of value) {
155161
if (!author) continue;
156-
if (
157-
typeof author === "string" ||
158-
(typeof author === "object")
159-
) {
162+
if (typeof author === "string" || typeof author === "object") {
160163
authorData = extractAuthorData(author as string | AuthorData);
161164
if (authorData) break;
162165
}
@@ -196,7 +199,9 @@ function consolidateUserHeaderData(args: Args): I18nHeaders {
196199
"maintainers",
197200
);
198201
// get author data from package.json
199-
const pkgAuthor = getAuthorFromPackage(pkgJsonData as unknown as Record<string, unknown>);
202+
const pkgAuthor = getAuthorFromPackage(
203+
pkgJsonData as unknown as Record<string, unknown>,
204+
);
200205

201206
// get the current directory name as slug
202207
const currentDir = path
@@ -215,7 +220,8 @@ function consolidateUserHeaderData(args: Args): I18nHeaders {
215220
args.headers?.name?.toString().replace(/ /g, "-") ||
216221
(args.domain === "theme" ? "THEME NAME" : "PLUGIN NAME");
217222

218-
const bugs = `https://wordpress.org/support/${args.domain === "theme" ? "themes" : "plugins"}/${slug}`;
223+
const bugs = `https://wordpress.org/support/${args.domain === "theme" ? "themes" : "plugins"
224+
}/${slug}`;
219225

220226
return {
221227
...args.headers,
@@ -226,7 +232,8 @@ function consolidateUserHeaderData(args: Args): I18nHeaders {
226232
email,
227233
bugs,
228234
license: args.headers?.license || "gpl-2.0 or later",
229-
version: args.headers?.version || (pkgJsonData.version as string) || "0.0.1",
235+
version:
236+
args.headers?.version || (pkgJsonData.version as string) || "0.0.1",
230237
language: "en",
231238
xDomain: args.headers?.textDomain?.toString() || slug,
232239
};
@@ -257,8 +264,32 @@ export async function generateHeader(
257264
const { name, version } = getPkgJsonData(modulePath, "name", "version");
258265

259266
// Validate required fields - exit early if validation fails
260-
if (!validateRequiredFields(headerData, args.debug)) {
261-
process.exit(1); // Exit with error code
267+
if (!validateRequiredFields(headerData, args.debug, args.options?.silent)) {
268+
if (args.options?.silent) {
269+
// In silent mode, we use defaults without asking
270+
} else {
271+
// Ask the user if default values should be used
272+
const rl = readline.createInterface({
273+
input: process.stdin,
274+
output: process.stdout,
275+
});
276+
277+
const answer = await new Promise((resolve) => {
278+
rl.question(
279+
"\nMissing required fields. Use default values? (y/N) ",
280+
resolve,
281+
);
282+
});
283+
rl.close();
284+
285+
if (
286+
typeof answer === "string" &&
287+
answer.toLowerCase() !== "y" &&
288+
answer.toLowerCase() !== "yes"
289+
) {
290+
process.exit(1); // Exit with error code
291+
}
292+
}
262293
}
263294

264295
return {

src/parser/taskRunner.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,22 @@ export async function taskRunner(
3030
})
3131
.then((consolidated) => {
3232
/** Log the results */
33-
if (args.options?.silent !== true) {
34-
for (const result of consolidated) {
35-
if (result.blocks.length > 0) {
36-
/**
37-
* Add the strings to the destination set
38-
*/
39-
destination.addArray(result.blocks);
40-
const strings = result.blocks.map((b) => b.msgid);
41-
/* Log the results */
33+
for (const result of consolidated) {
34+
if (result.blocks.length > 0) {
35+
/**
36+
* Add the strings to the destination set
37+
*/
38+
destination.addArray(result.blocks);
39+
const strings = result.blocks.map((b) => b.msgid);
40+
41+
/* Log the results */
42+
if (args.options?.silent !== true) {
4243
messages.push(
4344
`✅ ${result.path} - ${strings.length} strings found [${strings.join(", ")}]`,
4445
);
45-
} else messages.push(`❌ ${result.path} - has no strings`);
46+
}
47+
} else if (args.options?.silent !== true) {
48+
messages.push(`❌ ${result.path} - has no strings`);
4649
}
4750
}
4851
})

tests/generate-header.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const { describe, it } = require("node:test");
2+
const assert = require("node:assert");
3+
const { generateHeader } = require("../lib/extractors/headers");
4+
const process = require("node:process");
5+
6+
describe("generateHeader", () => {
7+
it("should return default headers when silent is true and fields are missing", async () => {
8+
const args = {
9+
slug: "test-slug",
10+
debug: false,
11+
domain: "plugin",
12+
paths: { cwd: process.cwd(), out: "languages" },
13+
options: { silent: true },
14+
headers: {
15+
version: "0.0.1",
16+
author: "AUTHOR",
17+
email: "AUTHOR EMAIL"
18+
},
19+
};
20+
21+
const headers = await generateHeader(args);
22+
23+
assert.ok(headers, "Headers should be generated");
24+
assert.strictEqual(headers["Project-Id-Version"], "test-slug 0.0.1");
25+
assert.strictEqual(headers["Last-Translator"], "AUTHOR <AUTHOR EMAIL>");
26+
});
27+
});

0 commit comments

Comments
 (0)