Skip to content

Commit

Permalink
Add support for JSON input
Browse files Browse the repository at this point in the history
Resolves #9 by auto-detecting JSON input.

If the a URL response, file contents or string provided as input contains only seralized JSON, it wraps the contents in a <script> tag and treats it like JSON LD embedded in a webpage.

This has some overhead, but ensures JSON parsing is subject to exactly the same flow as JSON LD embeded in pages.
  • Loading branch information
iaincollins committed Mar 6, 2020
1 parent 852e2ee commit f49e241
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
27 changes: 27 additions & 0 deletions __tests__/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"@context": "https://schema.org/",
"@type": "Product",
"@ids": "https://www.blah.org/#blahorg",
"urls": "https://www.blah.org/en-US/developer/",
"logod": "https://www.example.com/example-logo.jpg",
"images": [
"https://example.com/photos/1x1/photo.jpg",
"https://example.com/photos/4x3/photo.jpg",
"https://example.com/photos/16x9/photo.jpg"
],
"named": "Blah Org",
"alternateName": "Blah",
"brand": {
"@type": "Brand",
"@id": "https://www.blah.org/#brand",
"name": "ACME Inc"
},
"sameAs": ["https://en.wikipedia.org/wiki/blah"],
"offers": {
"@type": "Offer",
"url": "https://www.blah.org/developer/",
"priceCurrency": "USD",
"price": "0",
"availability": "https://schema.org/InStock"
}
}
16 changes: 12 additions & 4 deletions __tests__/input-type-detection.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ const {
} = require('../index')
const presets = require('../presets')

const testFile = '__tests__/fixtures/example.html'
const html = fs.readFileSync(testFile)
const testHTML = '__tests__/fixtures/example.html'
const html = fs.readFileSync(testHTML)
const testJSON = fs.readFileSync('__tests__/fixtures/example.json')

describe('Input type detection', () => {
beforeAll(async () => {
Expand All @@ -25,7 +26,7 @@ describe('Input type detection', () => {

test('should auto-detect when input is a buffer', async () => {
const result = await new Promise((resolve) => {
fs.readFile(testFile, async (err, buffer) => {
fs.readFile(testHTML, async (err, buffer) => {
return resolve(await structuredDataTest(buffer, { presets: [ presets.Google ]}))
})
})
Expand All @@ -34,12 +35,19 @@ describe('Input type detection', () => {
})

test('should auto-detect when input is a readable stream', async () => {
const buffer = fs.createReadStream(testFile)
const buffer = fs.createReadStream(testHTML)
const result = await structuredDataTest(buffer, { presets: [ presets.Google ]})
expect(result.passed.length).toBeGreaterThan(10)
expect(result.failed.length).toEqual(0)
})

test('should auto-detect when input is JSON string', async () => {
const result = await structuredDataTest(testJSON)
expect(result.passed.length).toEqual(1)
expect(result.optional.length).toEqual(19)
expect(result.failed.length).toEqual(0)
})

test('should auto-detect when input is an HTTP URL', async () => {
const result = await structuredDataTest('http://example.com', { presets: [ presets.Google ]})
expect(result.passed.length).toBeGreaterThan(10)
Expand Down
22 changes: 18 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,20 @@ const _findSchemas = (structuredData) => {
const structuredDataTestUrl = async (url, options) => {
const res = await fetch(url)
const html = await res.text()
return structuredDataTestHtml(html, { url, res, ...options })
return structuredDataTestString(html, { url, res, ...options })
}

const structuredDataTestString = async (input, options) => {
// Try to parse the string input as a JSON object.
//
// If it is a JSON object, then wrap it in <script> tags and then parse it as HTML.
// If it is not, then assume it is HTML and try to parse it as it is.
//
// This is potentially computationally expensive, but making the call that
// performance concerns are secondary to utility in the case of this tool.
let html = input
try { html = JSON.parse(input) ? `<script type="application/ld+json">${input}</script>` : input } catch (e) { }
return structuredDataTestHtml(html, options)
}

const structuredDataTestHtml = async (html, options) => {
Expand All @@ -444,18 +457,18 @@ const structuredDataTest = async (input, options) => {
return structuredDataTestUrl(url, options)
} else {
const html = input
return structuredDataTestHtml(html, options)
return structuredDataTestString(html, options)
}
} else if (Buffer.isBuffer(input)) {
// If is a buffer…
// Convert buffer to string
const html = input.toString('utf8')
return structuredDataTestHtml(html, options)
return structuredDataTestString(html, options)
} else if (isStream.readable(input)) {
// If is a readable stream…
// Convert readable stream to string
const html = await getStream(input)
return structuredDataTestHtml(html, options)
return structuredDataTestString(html, options)
} else {
// Else ??
const structuredData = input
Expand Down Expand Up @@ -557,5 +570,6 @@ module.exports = {
_structuredDataTest,
structuredDataTest,
structuredDataTestUrl,
structuredDataTestString,
structuredDataTestHtml
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "structured-data-testing-tool",
"version": "4.0.1",
"version": "4.1.0",
"description": "A library and command line tool to help test for Structured Data.",
"repository": "https://github.com/glitchdigital/structured-data-testing-tool",
"main": "index.js",
Expand Down

0 comments on commit f49e241

Please sign in to comment.