All files / server/services/examples built-in-provider.ts

97.29% Statements 36/37
75% Branches 6/8
100% Functions 8/8
97.05% Lines 33/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82            2x     5x     1x 1x       1x         1x 1x 1x 1x 1x 1x           1x 1x 1x 132x 52x   1x 52x 52x 2704x   52x 52x         52x 52x 52x                         6x 6x         6x 57x 57x 5x 52x 52x          
import { readdir, readFile, stat } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolvePathWithinRoot } from "../../security/safe-paths";
import type { ExampleRecord } from "./examples-schema";
 
const __dirname = path.dirname(fileURLToPath(import.meta.url));
 
export class BuiltInProvider {
  private snapshotPromise: Promise<ExampleRecord[]> | null = null;
 
  getExamples(): Promise<ExampleRecord[]> {
    this.snapshotPromise ??= this.loadExamples();
    return this.snapshotPromise;
  }
 
  private async loadExamples(): Promise<ExampleRecord[]> {
    const publicCandidates = [
      path.resolve(__dirname, "../../../public"),
      path.resolve(__dirname, "public"),
      path.resolve(__dirname, "../../public"),
    ];
    let publicDir = publicCandidates[0];
    for (const candidate of publicCandidates) {
      try {
        await stat(candidate);
        publicDir = candidate;
        break;
      } catch {
        // Try the next runtime layout.
      }
    }
 
    const examplesRoot = path.resolve(publicDir, "examples");
    const files: string[] = [];
    await this.collectFiles(examplesRoot, examplesRoot, files);
    files.sort((a, b) => a.localeCompare(b));
    const sketches = files.filter((file) => file.toLowerCase().endsWith(".ino"));
 
    return Promise.all(sketches.map(async (relativePath) => {
      const relativeDirectory = path.dirname(relativePath);
      const relatedHeaders = files.filter(
        (file) => path.dirname(file) === relativeDirectory && file.toLowerCase().endsWith(".h"),
      );
      const exampleFiles = [relativePath, ...relatedHeaders];
      const loadedFiles = await Promise.all(exampleFiles.map(async (file) => ({
        name: path.basename(file),
        path: file.replaceAll(path.sep, "/"),
        content: await readFile(resolvePathWithinRoot(examplesRoot, file), "utf8"),
      })));
      const name = path.basename(relativePath);
      const category = relativePath.split(path.sep)[0] ?? "Built-in";
      return {
        id: `builtin-${relativePath.replaceAll(path.sep, "-").replaceAll(/[^A-Za-z0-9_-]/g, "-").replaceAll(/-+/g, "-").replaceAll(/(?:^-|-$)/g, "")}`,
        title: name.replaceAll(/\.(?:ino|h)$/gi, "").replaceAll(/[-_]+/g, " "),
        category,
        files: loadedFiles,
        main: name,
        source: "builtin" as const,
      };
    }));
  }
 
  private async collectFiles(root: string, current: string, output: string[]): Promise<void> {
    let entries;
    try {
      entries = await readdir(current, { withFileTypes: true });
    } catch {
      return;
    }
 
    for (const entry of entries) {
      const relative = path.relative(root, path.join(current, entry.name));
      if (entry.isDirectory()) {
        await this.collectFiles(root, path.join(current, entry.name), output);
      E} else if (/\.(?:ino|h)$/i.test(entry.name)) {
        output.push(relative);
      }
    }
  }
}