()
| 235 | }, |
| 236 | |
| 237 | async docsHelpers() { |
| 238 | // generate documentation for helpers |
| 239 | const files = fs.readdirSync('lib/helper').filter(f => path.extname(f) === '.js') |
| 240 | |
| 241 | const ignoreList = ['Polly', 'MockRequest'] // WebDriverIO won't be documented and should be removed |
| 242 | |
| 243 | const partials = fs.readdirSync('docs/webapi').filter(f => path.extname(f) === '.mustache') |
| 244 | const placeholders = partials.map(file => `{{> ${path.basename(file, '.mustache')} }}`) |
| 245 | const templates = partials |
| 246 | .map(file => fs.readFileSync(`docs/webapi/${file}`).toString()) |
| 247 | .map(template => |
| 248 | template |
| 249 | .replace(/^/gm, ' * ') |
| 250 | .replace(/^/, '\n') |
| 251 | .replace(/\s*\* /, ''), |
| 252 | ) |
| 253 | |
| 254 | const sharedPartials = fs.readdirSync('docs/shared').filter(f => path.extname(f) === '.mustache') |
| 255 | const sharedPlaceholders = sharedPartials.map(file => `{{ ${path.basename(file, '.mustache')} }}`) |
| 256 | const sharedTemplates = sharedPartials.map(file => fs.readFileSync(`docs/shared/${file}`).toString()).map(template => `\n\n\n${template}`) |
| 257 | |
| 258 | for (const file of files) { |
| 259 | const name = path.basename(file, '.js') |
| 260 | if (ignoreList.indexOf(name) >= 0) continue |
| 261 | console.log(`Writing documentation for ${name}`) |
| 262 | copy(`lib/helper/${file}`, `docs/build/${file}`) |
| 263 | replaceInFile(`docs/build/${file}`, cfg => { |
| 264 | for (const i in placeholders) { |
| 265 | cfg.replace(placeholders[i], templates[i]) |
| 266 | } |
| 267 | cfg.replace(/CodeceptJS.LocatorOrString\?/g, '(string | object)?') |
| 268 | cfg.replace(/LocatorOrString\?/g, '(string | object)?') |
| 269 | cfg.replace(/CodeceptJS.LocatorOrString/g, 'string | object') |
| 270 | cfg.replace(/LocatorOrString/g, 'string | object') |
| 271 | cfg.replace(/CodeceptJS.StringOrSecret/g, 'string | object') |
| 272 | |
| 273 | // Convert ESM imports to require() for JSDoc compatibility |
| 274 | cfg.replace(/^import\s+([^'"`\s{]+)\s+from\s+['"`]([^'"`]+)['"`]/gm, "const $1 = require('$2')") |
| 275 | cfg.replace(/^import\s*\{\s*([^}]+)\s*\}\s*from\s+['"`]([^'"`]+)['"`]/gm, (match, imports, path) => { |
| 276 | // Handle destructuring imports with aliases - convert to simple require and assign |
| 277 | if (imports.includes(' as ')) { |
| 278 | const parts = imports.split(',').map(i => i.trim()) |
| 279 | const assignments = parts.map(part => { |
| 280 | if (part.includes(' as ')) { |
| 281 | const [original, alias] = part.split(' as ').map(s => s.trim()) |
| 282 | return `const ${alias} = require('${path}').${original}` |
| 283 | } else { |
| 284 | return `const ${part} = require('${path}').${part}` |
| 285 | } |
| 286 | }) |
| 287 | return assignments.join(';\n') |
| 288 | } |
| 289 | return `const { ${imports} } = require('${path}')` |
| 290 | }) |
| 291 | cfg.replace(/^import\s+\*\s+as\s+([^'"`]+)\s+from\s+['"`]([^'"`]+)['"`]/gm, "const $1 = require('$2')") |
| 292 | |
| 293 | // Convert ESM exports to module.exports for JSDoc compatibility |
| 294 | cfg.replace(/^export\s*\{\s*([^}]+)\s+as\s+default\s*\}/gm, 'module.exports = $1') |
nothing calls this directly
no test coverage detected