Skip to content

Commit 5613013

Browse files
Copilotjodeleeuw
andcommitted
Address code review feedback: improve module entrypoint, pluralization, and escaping
Co-authored-by: jodeleeuw <595524+jodeleeuw@users.noreply.github.com>
1 parent 5aaec69 commit 5613013

1 file changed

Lines changed: 57 additions & 18 deletions

File tree

packages/config/generatePluginDocs.js

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ function parseParametersSection(content, sectionName) {
126126

127127
// Extract default value
128128
let defaultValue = "*undefined*";
129-
// Match default: followed by value, handling functions, strings, numbers, etc.
129+
// Regex explanation:
130+
// \bdefault\s*:\s* - Match "default:" with optional whitespace
131+
// ([\s\S]*?) - Capture the value (non-greedy, including newlines)
132+
// (?:,\s*(?:\w+\s*:|$)|$) - Stop at: comma followed by another property, or end of string
130133
const defaultMatch = propertyDef.match(/\bdefault\s*:\s*([\s\S]*?)(?:,\s*(?:\w+\s*:|$)|$)/);
131134

132135
if (defaultMatch) {
@@ -160,7 +163,21 @@ function parseParametersSection(content, sectionName) {
160163
}
161164
}
162165

163-
const displayType = isArray ? `array of ${type}s` : type;
166+
// Format array types properly (e.g., "array of strings" not "array of strings")
167+
let displayType = type;
168+
if (isArray) {
169+
// Handle proper pluralization for different types
170+
const pluralForms = {
171+
string: "strings",
172+
boolean: "booleans",
173+
numeric: "numbers",
174+
function: "functions",
175+
object: "objects",
176+
"HTML string": "HTML strings",
177+
};
178+
const pluralType = pluralForms[type] || `${type}s`;
179+
displayType = `array of ${pluralType}`;
180+
}
164181

165182
params.push({
166183
name: propertyName,
@@ -294,10 +311,14 @@ function findExamples(pluginName, rootDir) {
294311
}
295312

296313
/**
297-
* Extracts JavaScript code from an example HTML file
314+
* Extracts JavaScript code from an example HTML file.
315+
* Note: This function parses trusted example files from the jsPsych repository,
316+
* not arbitrary user-provided HTML. The regex patterns are sufficient for
317+
* parsing well-formed HTML from our own examples.
298318
*/
299319
function extractExampleCode(htmlContent) {
300320
// Find script tags that contain jsPsych code (not src imports)
321+
// Note: This regex is for parsing trusted internal example files, not for security-critical HTML sanitization
301322
const scriptMatch = htmlContent.match(/<script[^>]*>(?![\s\S]*src=)([\s\S]*?)<\/script>/gi);
302323

303324
if (scriptMatch) {
@@ -331,8 +352,12 @@ function generateParametersTable(params) {
331352
table += "----------|------|---------------|------------\n";
332353

333354
for (const param of params) {
334-
// Escape pipe characters in description
335-
const description = param.description.replace(/\|/g, "\\|").replace(/\n/g, " ");
355+
// Escape special markdown characters in description for table cell
356+
// First escape backslashes, then pipes, and convert newlines to spaces
357+
const description = param.description
358+
.replace(/\\/g, "\\\\")
359+
.replace(/\|/g, "\\|")
360+
.replace(/\n/g, " ");
336361
table += `${param.name} | ${param.type} | ${param.default} | ${description}\n`;
337362
}
338363

@@ -354,8 +379,12 @@ function generateDataTable(data) {
354379
table += "-----|------|------\n";
355380

356381
for (const item of data) {
357-
// Escape pipe characters in description
358-
const description = item.description.replace(/\|/g, "\\|").replace(/\n/g, " ");
382+
// Escape special markdown characters in description for table cell
383+
// First escape backslashes, then pipes, and convert newlines to spaces
384+
const description = item.description
385+
.replace(/\\/g, "\\\\")
386+
.replace(/\|/g, "\\|")
387+
.replace(/\n/g, " ");
359388
table += `${item.name} | ${item.type} | ${description}\n`;
360389
}
361390

@@ -465,6 +494,21 @@ function getAllPluginNames() {
465494
.map((p) => p.replace("plugin-", ""));
466495
}
467496

497+
/**
498+
* Get argument value for a flag (supports both long and short forms)
499+
*/
500+
function getArgValue(args, longFlag, shortFlag) {
501+
const longIndex = args.indexOf(longFlag);
502+
if (longIndex !== -1 && args[longIndex + 1] && !args[longIndex + 1].startsWith("-")) {
503+
return args[longIndex + 1];
504+
}
505+
const shortIndex = args.indexOf(shortFlag);
506+
if (shortIndex !== -1 && args[shortIndex + 1] && !args[shortIndex + 1].startsWith("-")) {
507+
return args[shortIndex + 1];
508+
}
509+
return null;
510+
}
511+
468512
/**
469513
* Main entry point
470514
*/
@@ -497,22 +541,14 @@ Examples:
497541
}
498542

499543
let pluginNames = [];
500-
let outputDir = null;
501544

502545
if (args.includes("--all")) {
503546
pluginNames = getAllPluginNames();
504547
} else {
505548
pluginNames = args.filter((arg) => !arg.startsWith("-"));
506549
}
507550

508-
const outputIndex = args.indexOf("--output");
509-
if (outputIndex !== -1 && args[outputIndex + 1]) {
510-
outputDir = args[outputIndex + 1];
511-
}
512-
const outputIndexShort = args.indexOf("-o");
513-
if (outputIndexShort !== -1 && args[outputIndexShort + 1]) {
514-
outputDir = args[outputIndexShort + 1];
515-
}
551+
const outputDir = getArgValue(args, "--output", "-o");
516552

517553
if (pluginNames.length === 0) {
518554
console.error("No plugins specified. Use --help for usage information.");
@@ -556,5 +592,8 @@ export {
556592
parameterTypeMap,
557593
};
558594

559-
// Run main if this is the entry point
560-
main();
595+
// Run main if this is the entry point (i.e., script executed directly)
596+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
597+
if (isMainModule) {
598+
main();
599+
}

0 commit comments

Comments
 (0)