diff --git a/packages/core/parcel-bundler/src/Parser.js b/packages/core/parcel-bundler/src/Parser.js index 18521e97689..68ff9f811e3 100644 --- a/packages/core/parcel-bundler/src/Parser.js +++ b/packages/core/parcel-bundler/src/Parser.js @@ -20,6 +20,7 @@ class Parser { this.registerExtension('vue', './assets/VueAsset'); this.registerExtension('json', './assets/JSONAsset'); this.registerExtension('json5', './assets/JSONAsset'); + this.registerExtension('jsonld', './assets/JSONLDAsset'); this.registerExtension('yaml', './assets/YAMLAsset'); this.registerExtension('yml', './assets/YAMLAsset'); this.registerExtension('toml', './assets/TOMLAsset'); diff --git a/packages/core/parcel-bundler/src/Pipeline.js b/packages/core/parcel-bundler/src/Pipeline.js index b311e43f0ef..03a7579492f 100644 --- a/packages/core/parcel-bundler/src/Pipeline.js +++ b/packages/core/parcel-bundler/src/Pipeline.js @@ -67,6 +67,7 @@ class Pipeline { if (rendition.meta) { for (let res of processed) { res.meta = rendition.meta; + res.isMain = res.type === subAsset.type; } } diff --git a/packages/core/parcel-bundler/src/assets/HTMLAsset.js b/packages/core/parcel-bundler/src/assets/HTMLAsset.js index 173c2d7f4bc..244391bd312 100644 --- a/packages/core/parcel-bundler/src/assets/HTMLAsset.js +++ b/packages/core/parcel-bundler/src/assets/HTMLAsset.js @@ -49,7 +49,8 @@ const META = { 'msapplication-square310x310logo', 'msapplication-square70x70logo', 'msapplication-wide310x150logo', - 'msapplication-TileImage' + 'msapplication-TileImage', + 'msapplication-config' ], itemprop: [ 'image', @@ -65,6 +66,7 @@ const SCRIPT_TYPES = { 'application/javascript': 'js', 'text/javascript': 'js', 'application/json': false, + 'application/ld+json': 'jsonld', 'text/html': false }; @@ -251,15 +253,17 @@ class HTMLAsset extends Asset { if (type === 'attr' && rendition.type === 'css') { node.attrs.style = rendition.value; } else if (type === 'tag') { - if ( - (rendition.type === 'js' && node.tag === 'script') || - (rendition.type === 'css' && node.tag === 'style') - ) { + if (rendition.isMain) { node.content = rendition.value; } // Delete "type" attribute, since CSS and JS are the defaults. - if (node.attrs) { + // Unless it's application/ld+json + if ( + node.attrs && + (node.tag === 'style' || + (node.attrs.type && SCRIPT_TYPES[node.attrs.type] === 'js')) + ) { delete node.attrs.type; } } diff --git a/packages/core/parcel-bundler/src/assets/JSONLDAsset.js b/packages/core/parcel-bundler/src/assets/JSONLDAsset.js new file mode 100644 index 00000000000..55903b5e6c3 --- /dev/null +++ b/packages/core/parcel-bundler/src/assets/JSONLDAsset.js @@ -0,0 +1,76 @@ +const urlJoin = require('../utils/urlJoin'); +const isURL = require('../utils/is-url'); +const Asset = require('../Asset'); +const logger = require('../Logger'); + +// A list of all attributes in a schema that may produce a dependency +// Based on https://schema.org/ImageObject +// Section "Instances of ImageObject may appear as values for the following properties" +const SCHEMA_ATTRS = [ + 'logo', + 'photo', + 'image', + 'thumbnail', + 'screenshot', + 'primaryImageOfPage', + 'embedUrl', + 'thumbnailUrl', + 'video', + 'contentUrl' +]; + +class JSONLDAsset extends Asset { + constructor(name, options) { + super(name, options); + this.type = 'jsonld'; + } + + parse(content) { + return JSON.parse(content.trim()); + } + + collectDependencies() { + if (!this.options.publicURL.startsWith('http')) { + logger.warn( + "Please specify a publicURL using --public-url, otherwise schema assets won't be collected" + ); + return; + } + + for (let schemaKey in this.ast) { + if (SCHEMA_ATTRS.includes(schemaKey)) { + this.collectFromKey(this.ast, schemaKey); + this.isAstDirty = true; + } + } + } + + // Auxiliary method for collectDependencies() to use for recursion + collectFromKey(schema, schemaKey) { + if (!schema.hasOwnProperty(schemaKey)) { + return; + } + // values can be strings or objects + // if it's not a string, it should have a url + if (typeof schema[schemaKey] === 'string') { + let assetPath = this.addURLDependency(schema[schemaKey]); + if (!isURL(assetPath)) { + // paths aren't allowed, values must be urls + assetPath = urlJoin(this.options.publicURL, assetPath); + } + schema[schemaKey] = assetPath; + } else { + this.collectFromKey(schema[schemaKey], 'url'); + } + } + + generate() { + if (this.options.production) { + return JSON.stringify(this.ast); + } else { + return JSON.stringify(this.ast, null, 2); + } + } +} + +module.exports = JSONLDAsset; diff --git a/packages/core/parcel-bundler/test/integration/schema-jsonld/images/image.jpeg b/packages/core/parcel-bundler/test/integration/schema-jsonld/images/image.jpeg new file mode 100644 index 00000000000..508efd90649 Binary files /dev/null and b/packages/core/parcel-bundler/test/integration/schema-jsonld/images/image.jpeg differ diff --git a/packages/core/parcel-bundler/test/integration/schema-jsonld/images/logo.png b/packages/core/parcel-bundler/test/integration/schema-jsonld/images/logo.png new file mode 100644 index 00000000000..c62dfa4d68a Binary files /dev/null and b/packages/core/parcel-bundler/test/integration/schema-jsonld/images/logo.png differ diff --git a/packages/core/parcel-bundler/test/integration/schema-jsonld/index.html b/packages/core/parcel-bundler/test/integration/schema-jsonld/index.html new file mode 100644 index 00000000000..1cc5f850cbc --- /dev/null +++ b/packages/core/parcel-bundler/test/integration/schema-jsonld/index.html @@ -0,0 +1,29 @@ + + + hi + + + + +

text 123

+ + + + + diff --git a/packages/core/parcel-bundler/test/integration/schema-jsonld/other.css b/packages/core/parcel-bundler/test/integration/schema-jsonld/other.css new file mode 100644 index 00000000000..c96d1ffa977 --- /dev/null +++ b/packages/core/parcel-bundler/test/integration/schema-jsonld/other.css @@ -0,0 +1,3 @@ +.other { + color: green; +} diff --git a/packages/core/parcel-bundler/test/schema-jsonld.js b/packages/core/parcel-bundler/test/schema-jsonld.js new file mode 100644 index 00000000000..5e7d24c1aec --- /dev/null +++ b/packages/core/parcel-bundler/test/schema-jsonld.js @@ -0,0 +1,26 @@ +const {bundle, assertBundleTree} = require('./utils'); + +describe('schema ld+json', function() { + it('Should parse a LD+JSON schema and collect dependencies', async function() { + let b = await bundle(__dirname + '/integration/schema-jsonld/index.html', { + production: true, + publicURL: 'https://place.holder/' + }); + + await assertBundleTree(b, { + name: 'index.html', + assets: ['index.html'], + childBundles: [ + { + type: 'jpeg' + }, + { + type: 'png' + }, + { + type: 'css' + } + ] + }); + }); +});