| 141 | } |
| 142 | |
| 143 | function findMainPy(dir, folder) { |
| 144 | const top = fs.readdirSync(dir, { withFileTypes: true }); |
| 145 | const pys = top |
| 146 | .filter((d) => d.isFile() && d.name.toLowerCase().endsWith(".py")) |
| 147 | .map((d) => d.name); |
| 148 | const pick = (names) => { |
| 149 | const byMain = names.find((n) => n.toLowerCase() === "main.py"); |
| 150 | if (byMain) return byMain; |
| 151 | const slug = slugify(folder); |
| 152 | const byName = names.find( |
| 153 | (n) => slugify(n.replace(/\.py$/i, "")) === slug, |
| 154 | ); |
| 155 | return byName || names[0]; |
| 156 | }; |
| 157 | if (pys.length) return path.join(dir, pick(pys)); |
| 158 | // look one level deep for projects that nest their code in a subfolder |
| 159 | for (const d of top) { |
| 160 | if (!d.isDirectory()) continue; |
| 161 | const sub = path.join(dir, d.name); |
| 162 | const subpys = fs |
| 163 | .readdirSync(sub) |
| 164 | .filter((n) => n.toLowerCase().endsWith(".py")); |
| 165 | if (subpys.length) { |
| 166 | const byMain = subpys.find((n) => n.toLowerCase() === "main.py"); |
| 167 | return path.join(sub, byMain || subpys[0]); |
| 168 | } |
| 169 | } |
| 170 | return null; |
| 171 | } |
| 172 | |
| 173 | function parseReadme(file) { |
| 174 | const lines = fs.readFileSync(file, "utf8").split(/\r?\n/); |