digitalbazaar / jsonld.js

A JSON-LD Processor and API implementation in JavaScript
https://json-ld.org/
Other
1.64k stars 195 forks source link

Bug: Missing properties in compact and expand #529

Closed jeremiahlee closed 10 months ago

jeremiahlee commented 10 months ago

Properties seem to be removed from the output of compact and expand unexpectedly. The behavior of the playground and the library differs.

Using the example from the README:

const context = {
  "name": "http://schema.org/name",
  "homepage": {"@id": "http://schema.org/url", "@type": "@id"},
  "image": {"@id": "http://schema.org/image", "@type": "@id"}
};

const doc = {
  "http://schema.org/name": "Manu Sporny",
  "http://schema.org/url": {"@id": "http://manu.sporny.org/"},
  "http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"}
};

If I rename the document property "http://schema.org/name" to "name" so that the full input is:

{
  "@context": {
    "name": "http://schema.org/name",
    "homepage": {"@id": "http://schema.org/url", "@type": "@id"},
    "image": {"@id": "http://schema.org/image", "@type": "@id"}
  },
  "name": "Manu Sporny",
  "http://schema.org/url": {"@id": "http://manu.sporny.org/"},
  "http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"}
}

The expanded and compacted output on the Playground are the same if the document property is named "name" or "http://schema.org/name". This is the behavior I would expect and consider correct.

However, using node v18.17.1 and jsonld v8.2.0 of the library produces different output. The name property will be missing on output.

const jsonld = require("jsonld");

const context = {
    "name": "http://schema.org/name",
    "homepage": { "@id": "http://schema.org/url", "@type": "@id" },
    "image": { "@id": "http://schema.org/image", "@type": "@id" }
};
const doc = {
    "name": "Manu Sporny",
    "http://schema.org/url": { "@id": "http://manu.sporny.org/" },
    "http://schema.org/image": { "@id": "http://manu.sporny.org/images/manu.png" }
};

async function test() {
    const compacted = await jsonld.compact(doc, context);

    const expanded = await jsonld.expand(compacted);

    console.dir(compacted, { depth: null });
    console.dir(expanded, { depth: null });
}

test();

The console logs a compacted and expanded form with no name property.

{
  '@context': {
    name: 'http://schema.org/name',
    homepage: { '@id': 'http://schema.org/url', '@type': '@id' },
    image: { '@id': 'http://schema.org/image', '@type': '@id' }
  },
  image: 'http://manu.sporny.org/images/manu.png',
  homepage: 'http://manu.sporny.org/'
}
[
  {
    'http://schema.org/url': [ { '@id': 'http://manu.sporny.org/' } ],
    'http://schema.org/image': [ { '@id': 'http://manu.sporny.org/images/manu.png' } ]
  }
]

Is there a configuration difference between the Playground and the library? Am I incorrect in expecting the document properties to matched against the property names in the context?

dlongley commented 10 months ago

@jeremiahlee,

In your node + jsonld test case your input is different from the playground: it does not include @context in doc. This is why you see a difference and why name is dropped. There's no @context on the input doc, so name has no global mapping. The default behavior is to drop name when that happens. If you'd prefer to get an error instead, you can enable "safe mode" that will throw if anything gets dropped by passing {safe: true} as an option to functions like compact().

jeremiahlee commented 10 months ago

@dlongley Thanks, I can confirm that adding the @context back to the document and sending an empty object {} as the second parameter to jsonld.compact() works as expected.

I thought it was quite strange to have to separate out the @context object from the doc to send to the compact, but the README example implied that to be the case because there is no @context on the document.

jeremiahlee commented 10 months ago

Working as designed