Skip to content

Add script to validate a single article + docs #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion libraries/from-bodyxml/readme

This file was deleted.

31 changes: 31 additions & 0 deletions libraries/from-bodyxml/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
a library (and cli) for creating a (transit) content-tree from a bodyXML

## Testing

### Generate a bodyTree from a content api URL

```
curl "$CONTENT_API_HOST/internalcontent/9e9192ba-02f1-4034-aaf0-200270d0f6d7?apiKey=$CONTENT_API_READ_KEY" | jq '.bodyXML' -r | node libraries/from-bodyxml/cli.js
```

### Validate from-bodyxml's output against the schema

Ensure you have the environment variables:

- CONTENT_API_HOST
- CONTENT_API_READ_KEY

```
node libraries/from-bodyxml/validate.js 9e9192ba-02f1-4034-aaf0-200270d0f6d7
```

### Validate articles published in the last 5 minutes

Ensure you have the environment variables:

- CONTENT_API_HOST
- CONTENT_API_READ_KEY

```
node --test libraries/from-bodyxml/smoke-test.js
```
90 changes: 90 additions & 0 deletions libraries/from-bodyxml/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import assert from "node:assert";
import fromBodyXML from "./index.js";
import Ajv from "ajv";
import fs from "node:fs";
import path from "node:path";
import test from "node:test";
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const apiHost = process.env.CONTENT_API_HOST || "https://api-t.ft.com";
const apiKey = process.env.CONTENT_API_READ_KEY;
const uuid = process.argv[2];

const transitTreeSchemaFile = fs.readFileSync(
path.resolve(__dirname, "../../schemas/transit-tree.schema.json")
);

const transitTreeSchema = JSON.parse(transitTreeSchemaFile);

const ajv = new Ajv();

const validate = ajv.compile(transitTreeSchema);

/**
* Gets the value from an object based on an AJV instancePath.
*
* @param {Object} obj - The JSON object to navigate.
* @param {string} instancePath - The AJV instancePath (e.g., "/body/children/14/type").
* @returns {*} - The value at the given instancePath, or undefined if the path does not exist.
*/
function getValueAtInstancePath(obj, instancePath) {
// Split the path into parts, ignoring the leading "/"
const parts = instancePath.split("/").filter(Boolean);

// Navigate through the object
return parts.reduce((acc, key) => {
// Convert array indices from string to number
const index = Number(key);
return acc && !isNaN(index) ? acc[index] : acc?.[key];
}, obj);
}

async function fetchArticleFromCAPI(uuid) {
try {
const response = await fetch(`${apiHost}/internalcontent/${uuid}`, {
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey ?? "",
},
});

if (!response.ok) {
throw new Error(`Error fetching ${apiUrl}: ${response.status}`);
}

const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching ${apiUrl}:", error);
}
}

test("Validating " + uuid, async (t) => {
const article = await fetchArticleFromCAPI(uuid);
if (!article.bodyXML) {
console.log("No bodyXML");
t.skip("Skipping - no bodyXML");
return;
}

const bodyTree = fromBodyXML(article.bodyXML);
const isValid = validate(bodyTree);
// Add the erroneous value to the error message, for debugging
if (!isValid) {
validate.errors.forEach(
(error) =>
(error.instanceValue = getValueAtInstancePath(
bodyTree,
error.instancePath
))
);
}
assert.ok(
isValid,
`Transit tree is invalid: ${JSON.stringify(validate.errors, null, 2)}`
);
});
Loading