From 043dbc4f27c3e4196b2181067660e09e3b777a06 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Tue, 5 Mar 2024 23:14:56 +0000 Subject: [PATCH] Adds API endpoints for determing line numbers --- web/src/pages/api/awesome-privacy.json.ts | 21 +++++ web/src/pages/api/line-numbers.json.ts | 94 +++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 web/src/pages/api/awesome-privacy.json.ts create mode 100644 web/src/pages/api/line-numbers.json.ts diff --git a/web/src/pages/api/awesome-privacy.json.ts b/web/src/pages/api/awesome-privacy.json.ts new file mode 100644 index 0000000..f5258e0 --- /dev/null +++ b/web/src/pages/api/awesome-privacy.json.ts @@ -0,0 +1,21 @@ +import type { APIRoute } from 'astro'; +import yaml from 'js-yaml'; + +import type { AwesomePrivacy } from '../../types/Service'; + +const awesomePrivacyYamlPath = 'https://raw.githubusercontent.com/Lissy93/awesome-privacy/main/awesome-privacy.yml'; + +export const GET: APIRoute = async () => { + + const yamlContent = await fetch(awesomePrivacyYamlPath) + .then(response => response.text()) + .catch(error => { + return JSON.stringify({ error: "Failed to fetch YAML file", details: error }); + }); + + const yamlObject = yaml.load(yamlContent) as AwesomePrivacy; + + return new Response( + JSON.stringify(yamlObject), { headers: { 'content-type': 'application/json' } } + ) +} diff --git a/web/src/pages/api/line-numbers.json.ts b/web/src/pages/api/line-numbers.json.ts new file mode 100644 index 0000000..e3917a5 --- /dev/null +++ b/web/src/pages/api/line-numbers.json.ts @@ -0,0 +1,94 @@ +import type { APIRoute } from 'astro'; +import yaml from 'js-yaml'; + +import type { AwesomePrivacy, Service } from '../../types/Service'; + +interface LineNumberRange { + start: number; + end: number; +} + +interface LineNumberData { + [category: string]: { + [section: string]: { + [service: string]: { + lineNumbers: LineNumberRange | null; + yaml: string; + } + }; + }; +} + +const awesomePrivacyYamlPath = 'https://raw.githubusercontent.com/Lissy93/awesome-privacy/main/awesome-privacy.yml'; + +/** + * Given a service object and an array of string lines from the raw YAML + * Find the starting and ending line number for that service + */ +const calculateServiceRange = (service: Service, yamlLines: string[]): LineNumberRange | null => { + const lookFor = `- name: ${service.name}`; + const start = yamlLines.findIndex(line => line.includes(lookFor)) + 1; + if (start === -1) return null; + const detectEnd = (line: string) => { + return line.trim().length === 0 + || line.startsWith(' - ') + || line.includes('notableMentions:') + || line.includes('furtherInfo:') + || line.includes('wordOfWarning:') + } + const remainingLines = yamlLines.slice(start); + const end = start + remainingLines.findIndex(detectEnd); + + return { start, end }; +} + +/** + * Given a service object, convert it into a correctly formatted YAML string + */ +const convertJsonIntoYaml = (service: Service): string => { + return yaml.dump(service); +}; + +/** + * Given the object representation of the YAML and the array of lines from the raw YAML + * Organize the data into a format that can be returned as JSON + */ +const makeResults = (yamlObject: AwesomePrivacy, yamlLines: string[]): LineNumberData => { + const organizedData: LineNumberData = {}; + yamlObject.categories.forEach((category) => { + organizedData[category.name] = {}; + category.sections.forEach((section) => { + organizedData[category.name][section.name] = {}; + section.services.forEach((service) => { + organizedData[category.name][section.name][service.name] = { + lineNumbers: calculateServiceRange(service, yamlLines), + yaml: convertJsonIntoYaml(service), + }; + }); + }); + }); + return organizedData; +} + +export const GET: APIRoute = async () => { + + // Fetch the raw YAML from the awesome-privacy repository + const yamlContent = await fetch(awesomePrivacyYamlPath) + .then(response => response.text()) + .catch(error => { + return JSON.stringify({ error: "Failed to fetch YAML file", details: error }); + }); + + // Array of lines from the raw YAML + const yamlLines: string[] = yamlContent.split('\n'); + + // Object representation of the YAML + const yamlObject = yaml.load(yamlContent) as AwesomePrivacy; + + // Make results + const results = makeResults(yamlObject, yamlLines); + + return new Response( + JSON.stringify(results), { headers: { 'content-type': 'application/json' } } + ) +}