master da9422c30667
37 files
31.6 KB
8.7k tokens
Repository: bentaylor2/react-structured-data
Branch: master
Commit: da9422c30667
Files: 37
Total size: 31.6 KB

Directory structure:
gitextract_7ekl7nb7/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── _config.yml
├── package.json
├── postcss.config.js
├── public/
│   ├── index.html
│   └── manifest.json
├── src/
│   ├── core/
│   │   ├── JSONLD.js
│   │   ├── JSONLDAbstractNode.js
│   │   ├── index.js
│   │   └── schemas/
│   │       ├── AggregateRating.js
│   │       ├── Answer.js
│   │       ├── Author.js
│   │       ├── Generic.js
│   │       ├── GenericCollection.js
│   │       ├── Graph.js
│   │       ├── ItemReviewed.js
│   │       ├── Location.js
│   │       ├── Product.js
│   │       ├── Question.js
│   │       ├── Rating.js
│   │       ├── Review.js
│   │       ├── Reviews.js
│   │       └── index.js
│   ├── example/
│   │   ├── Main.css
│   │   ├── Main.js
│   │   └── containers/
│   │       ├── Example.js
│   │       ├── Example.scss
│   │       └── TextExamples.js
│   ├── index.css
│   ├── index.js
│   └── registerServiceWorker.js
└── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock
*.tgz


================================================
FILE: .npmignore
================================================
src/*
build/*
_config.yml
yarn-error.log
.npmignore
registerServiceWorker.js
postcss.config.js
yarn.lock
config/*
public/*
scripts/*
*.tgz


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 Ben Taylor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# React Structured Data

React Structured Data provides an easy way to add structured data to your React apps. Structured data is a standardized format for providing information about a page and classifying the page content. This library follows guidelines specified at http://schema.org/.

## Installation

### Yarn

`yarn add react-structured-data`

### NPM

`npm install react-structured-data --save`

## Code Example

The following JSX:

```jsx
  <JSONLD>
    <Product name="Product Name">
      <AggregateRating ratingValue={4.3} reviewCount={197}/>
      <GenericCollection type="review">
        <Review name="It's awesome" reviewBody="This is Great! My family loves it" datePublished="11/22/1963">
          <Author name="Jerry"/>
          <Location name="Chicago, IL"/>
          <Rating ratingValue={5} />
        </Review>
        <Review name="Very cool" reviewBody="I like this a lot. Very cool product" datePublished="11/22/1963">
          <Author name="Cool Carl"/>
          <Location name="Chicago, IL"/>
          <Rating ratingValue={4} />
        </Review>
      </GenericCollection>
    </Product>
  </JSONLD>
```

will add the following to your markup (will be minified):

```html
<script type="application/ld+json">
  {
    "@context":"https://schema.org/",
    "@type":"Product",
    "name":"Product Name",
    "aggregateRating": {
      "@type":"AggregateRating",
      "ratingValue":4.3,
      "reviewCount":197
    },
    "review":[
      {
        "@type":"Review",
        "datePublished":"11/22/1963",
        "reviewBody":"This is Great! My family loves it",
        "name":"It's awesome",
        "author": {
          "@type":"Person",
          "name":"Jerry"
        },
        "locationCreated": {
          "@type":"AdministrativeArea",
          "name":"Chicago, IL"
        },
        "reviewRating": {
          "@type": "Rating",
          "ratingValue": 5
        }
      },
      {
        "@type":"Review",
        "datePublished":"11/22/1963",
        "reviewBody":"I like this a lot. Very cool product",
        "name":"Very cool",
        "author":{
          "@type":"Person",
          "name":"Cool Carl"
        },
        "locationCreated": {
          "@type":"AdministrativeArea",
          "name":"Chicago, IL"
        },
        "reviewRating": {
          "@type": "Rating",
          "ratingValue": 4
        }
      }
    ]
  }
</script>
```

## Reference

### PropTypes

#### Generic Component PropTypes


| PropType      | Value         | Description  |
| ------------- | ------------- | ------       |
| type          | String        | The @type description in the json-ld body: `"@type": "Product"` |
| jsonldtype    | String        | The value of the @type description in the json-ld body: `"@type": "Product"`  |
| schema        | Object (json) | This should be the schema that you want for your structured data node: `{name: "It is awesome", reviewBody: "This is great!"}`  |


#### JSONLD node propTypes


| PropType              | Value       | Description  |
| -------------         | ----------- | ------       |
| dangerouslyExposeHtml | Boolean     | Set this to render the json within script tag using `dangerouslySetInnerHTML` |


#### Schema node PropTypes


| PropType      | Value         | Description  |
| ------------- | ------------- | ------       |
| parentID      | String        | Sets the id of the schema that becomes a reference that the children point to `"@id": "product-x"` |
| id            | String        | similar to parentID but uses the ID on itself |


### Preset Components
There are several preset schema components that can be used

- AggregateRating
- Answer
- Author
- ItemReviewed
- Location
- Product
- Question
- Rating
- Review

If you would like to use a component that is not listed, simply use the Generic component and add the prop jsonldtype.
Generic and GenericCollection allow you to add your own structured data type.

For example, If Review preset didn't exist, you could write:

```jsx
<JSONLD>
  <Generic type="review" jsonldtype="Review" schema={{name: "It is awesome", reviewBody: "This is great!"}}>
    <Generic type="itemReviewed" jsonldtype="Product" schema={{"@id":"product-x"}} />
    <Generic type="author" jsonldtype="Person" schema={{name: "Cool Carl"}}/>
    <Generic type="locationCreated" jsonldtype="AdministrativeArea" schema={{name: "Chicago, IL"}}/>
  </Generic>
</JSONLD>
```

This will output (minified):

```html
<script type="application/ld+json">
  {
    "@context": "http://schema.org/",
    "@type": "Review",
    "name": "It is awesome",
    "reviewBody": "This is great!",
    "itemReviewed": {
      "@type": "Product",
      "@id": "product-x"
    },
    "author": {
      "@type": "Person",
      "name": "Cool Carl"
    },
    "locationCreated": {
      "@type": "AdministrativeArea",
      "name": "Chicago, IL"
    }
  }
</script>
```

This may seem not as ideal as using the presets, but this allows completely customizable structured data.
There will also be more preset components to come in future releases to make implementation easier so stay tuned!

### Structured Data and Schema.org

For more information on Structured data, visit https://developers.google.com/search/docs/guides/intro-structured-data, and also http://schema.org/.
You can also validate the structured data here: https://search.google.com/structured-data/testing-tool.

## Contributors

TBA

## License

MIT License


================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman

================================================
FILE: package.json
================================================
{
  "name": "react-structured-data",
  "version": "0.0.14",
  "description": "Declarative JSON-LD Structured Data for ReactJS Apps",
  "author": "Ben Taylor <benlt105@gmail.com>",
  "private": false,
  "homepage": "https://bentaylor2.github.io/react-structured-data/",
  "license": "MIT",
  "keywords": [
    "react",
    "React",
    "react-jsonld",
    "json-ld",
    "JSON-LD",
    "jsonld",
    "JSONLD",
    "schema.org",
    "schema",
    "structured data",
    "seo",
    "react-component"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/bentaylor2/react-structured-data.git"
  },
  "dependencies": {
    "prop-types": "^15.6.0"
  },
  "devDependencies": {
    "autoprefixer": "7.1.6",
    "babel-cli": "^6.14.0",
    "babel-core": "6.26.0",
    "babel-eslint": "7.2.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-class-properties": "6.11.5",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
    "babel-plugin-transform-object-assign": "^6.8.0",
    "babel-preset-minify": "^0.4.3",
    "babel-preset-react": "6.24.1",
    "babel-preset-react-app": "^3.1.0",
    "babel-preset-stage-2": "^6.13.0",
    "babel-runtime": "6.26.0",
    "css-loader": "0.28.7",
    "eslint": "^4.18.2",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.4.0",
    "node-sass": "^4.7.2",
    "postcss-flexbugs-fixes": "3.2.0",
    "postcss-loader": "2.0.8",
    "prop-types": "^15.6.0",
    "react": "^16.2.0",
    "react-dev-utils": "^4.2.1",
    "react-dom": "^16.2.0",
    "react-structured-data": "^0.0.8",
    "sass-loader": "^6.0.6",
    "style-loader": "0.19.0",
    "uglifyjs-webpack-plugin": "^1.2.5",
    "webpack": "^4.6.0",
    "webpack-cli": "^3.0.2",
    "webpack-dev-server": "^3.1.4"
  },
  "peerDependencies": {
    "react": "^16.2.0"
  },
  "scripts": {
    "start": "BABEL_ENV=development webpack-dev-server --mode development --open --hot",
    "build": "BABEL_ENV=production babel src/core --plugins transform-object-assign,transform-class-properties,transform-es2015-modules-commonjs --presets babel-preset-stage-2,babel-preset-react-app --out-dir dist"
  },
  "babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      "babel-plugin-syntax-trailing-function-commas",
      "babel-plugin-transform-class-properties",
      "babel-plugin-transform-object-rest-spread",
      "babel-plugin-transform-react-constant-elements"
    ]
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "main": "./dist"
}


================================================
FILE: postcss.config.js
================================================
module.exports = {}


================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
    <link rel="manifest" href="./public/manifest.json">
    <link rel="shortcut icon" href="./public/rsd-icon.ico">
    <!--i
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React Structured Data</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>


================================================
FILE: public/manifest.json
================================================
{
  "short_name": "React Structured Data",
  "name": "Example of adding declaritive structured data with React",
  "icons": [
    {
      "src": "rsd-icon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}


================================================
FILE: src/core/JSONLD.js
================================================
import React from 'react';
import PropTypes from 'prop-types';

export const JSONLD = props => {
  let json = null;
  if (props.children) {
    const ChildClass = props.children.type;
    const { children, type, ...schema } = props.children.props;
    const firstChild = new ChildClass(props.children.props).getJSON(true, schema);
    json = ChildClass.name === 'JSONLDNodeCollection'
      ? Object.assign({'@context': 'https://schema.org/'}, {[type]: firstChild})
      : Object.assign({'@context': 'https://schema.org/'}, firstChild)
  }

  return (props.dangerouslyExposeHtml
    ? <script type="application/ld+json" dangerouslySetInnerHTML={{__html: JSON.stringify(json)}} />
    : <script type="application/ld+json">{ JSON.stringify(json) }</script>
  );
}

JSONLD.propTypes = {
  additionalType: PropTypes.object,
  dangerouslyExposeHtml: PropTypes.bool
};

JSONLD.defaultProps = {
  dangerouslyExposeHtml: false
};

export default JSONLD;


================================================
FILE: src/core/JSONLDAbstractNode.js
================================================
import React from 'react';
import PropTypes from 'prop-types';

class JSONLDAbstractNode extends React.Component {

  static propTypes = {
    schema: PropTypes.object,
    type: PropTypes.string,
    id: PropTypes.string,
    jsonldtype: PropTypes.string
  };

  getChildJSON(child, isCollection) {
    if(!child) return '';
    
    const ChildClass = child.type;
    let { children, type, id, parentID, ...schema } = child.props;
    if (!!parentID) schema = {'@id': parentID };
    if (!!id) schema = {
      ...schema,
      "@id": id
    }
    const newChildren = new ChildClass(child.props).getJSON((!!type || isCollection), schema);
    return !!type ? Object.assign({[type]: newChildren}) : newChildren;
  }
  parseChildren(isCollection = false) {
    if (!this.props.children) return {};
    /*
     * If a component has a single child, this.props.children is a Child object.
     * If a component has multiple children, this.props.children is an array of Child objects.
     */
    if (this.props.children.length > 0) {
      return this.props.children.map(child => this.getChildJSON(child, isCollection));
    }
    return [this.getChildJSON(this.props.children, isCollection)];
  }
  render() {
    return null;
  }
}

export default JSONLDAbstractNode;


================================================
FILE: src/core/index.js
================================================
export * from './schemas';
export { default as JSONLD } from './JSONLD';


================================================
FILE: src/core/schemas/AggregateRating.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class AggregateRating extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'AggregateRating',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({aggregateRating: details}, ...parseChildren);
  }
}

export default AggregateRating;


================================================
FILE: src/core/schemas/Answer.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Answer extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Answer',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({suggestedAnswer: details}, ...parseChildren);
  }
}

export default Answer;


================================================
FILE: src/core/schemas/Author.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Author extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Person',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({author: details}, ...parseChildren);
  }
}

export default Author;


================================================
FILE: src/core/schemas/Generic.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class ChildNode extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false) {
    const parseChildren = super.parseChildren();
    const schema = this.props.schema;
    const details = {
      '@type': this.props.jsonldtype
    }

    return Object.assign({...details, ...schema}, ...parseChildren);
  }
}

export default ChildNode;


================================================
FILE: src/core/schemas/GenericCollection.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class JSONLDNodeCollection extends JSONLDAbstractNode {
  getJSON() {
    if (!!this.props.children) {
      return super.parseChildren(true);
    }
  }
}

export default JSONLDNodeCollection;


================================================
FILE: src/core/schemas/Graph.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Graph extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren(true);
    return Object.assign({'@graph': parseChildren});
  }
}

export default Graph;


================================================
FILE: src/core/schemas/ItemReviewed.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class ItemReviewed extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren(true);

    if (parseChildren.length > 1) {
      throw new Error('The <ItemReviewed /> component can only contain a single child.');
    }
    const details = {
      ...parseChildren[0],
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details)
      : Object.assign({itemReviewed: details});
  }
}

export default ItemReviewed;


================================================
FILE: src/core/schemas/Location.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Location extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'AdministrativeArea',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({locationCreated: details}, ...parseChildren);
  }
}

export default Location;


================================================
FILE: src/core/schemas/Product.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Product extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Product',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({product: details}, ...parseChildren);
  }
}

export default Product;


================================================
FILE: src/core/schemas/Question.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Question extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Question',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({question: details}, ...parseChildren);
  }
}

export default Question;


================================================
FILE: src/core/schemas/Rating.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Rating extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Rating',
      ...schema
    }
    return isFirstChildNode
      ? Object.assign(details, ...parseChildren)
      : Object.assign({reviewRating: details}, ...parseChildren);
  }
}

export default Rating;


================================================
FILE: src/core/schemas/Review.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Review extends JSONLDAbstractNode {
  getJSON(isFirstChildNode = false, schema) {
    const parseChildren = super.parseChildren();
    const details = {
      '@type': 'Review',
      ...schema
    }
    return Object.assign(details, ...parseChildren);
  }
}

export default Review;


================================================
FILE: src/core/schemas/Reviews.js
================================================
import JSONLDAbstractNode from '../JSONLDAbstractNode';

class Reviews extends JSONLDAbstractNode {
  getJSON() {
    return super.parseChildren();
  }
}

export default Reviews;


================================================
FILE: src/core/schemas/index.js
================================================
export { default as AggregateRating } from './AggregateRating';
export { default as Author } from './Author';
export { default as Generic } from './Generic';
export { default as GenericCollection } from './GenericCollection';
export { default as Location } from './Location';
export { default as Product } from './Product';
export { default as Rating } from './Rating';
export { default as Review } from './Review';
export { default as Reviews } from './Reviews';
export { default as ItemReviewed } from './ItemReviewed';
export { default as Question } from './Question';
export { default as Answer } from './Answer';
export { default as Graph } from './Graph';


================================================
FILE: src/example/Main.css
================================================
.Main {
  text-align: center;
}

.Main-logo {
  animation: Main-logo-spin infinite 20s linear;
  height: 80px;
}

.Main-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.Main-title {
  font-size: 1.5em;
}

.Main-intro {
  font-size: large;
}

.Main-jsonld {
  height: 500px;
  width: 500px;
  display: block;
}

@keyframes Main-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}


================================================
FILE: src/example/Main.js
================================================
import React from 'react';
import './Main.css';
import Example from './containers/Example';

const Main = () => (
  <main>
    <Example />
  </main>
);
export default Main;


================================================
FILE: src/example/containers/Example.js
================================================
import React, { PureComponent } from 'react';
import styles from './Example.scss';
import {
  JSONLD,
  Graph,
  Product,
  ItemReviewed,
  Review,
  Author,
  Location,
  Rating,
  Generic
} from 'react-structured-data';


class Example extends PureComponent {
  render() {
    return (
      <section className={styles.example}>
        <header className={styles.header}>
          <h2>React Structured Data</h2>
        </header>
        <p>
          Each JSONLD component added creates a script tag with structured data on the page
        </p>
        <p className={styles.exampleIntro}>
        Below is generated JSON-LD
        </p>
        <section className={styles.exampleCode}>
          <JSONLD>
            <Graph>
              <Review
                name="It's awesome"
                reviewBody="This is Great! My family loves it"
                datePublished="11/22/1963">
                <Author name="Jerry"/>
                <Location name="Chicago, IL"/>
                <Rating ratingValue={5} />
                <ItemReviewed>
                  <Product
                    name="Product Name"
                    parentID="product-x" />
                </ItemReviewed>
              </Review>
              <Review
                name="Very cool"
                reviewBody="I like this a lot. Very cool product"
                datePublished="11/22/1963">
                <Author name="Cool Carl"/>
                <Location name="Chicago, IL"/>
                <Rating ratingValue={4} />
                <ItemReviewed>
                  <Product
                    name="Product Name"
                    parentID="product-x" />
                </ItemReviewed>
              </Review>
            </Graph>
          </JSONLD>
          <JSONLD>
            <Generic type="review" jsonldtype="Review" schema={{name: "It is awesome", reviewBody: "This is great!"}}>
              <Generic type="itemReviewed" jsonldtype="Product" schema={{"@id":"product-x"}} />
              <Generic type="author" jsonldtype="Person" schema={{name: "Cool Carl"}}/>
              <Generic type="locationCreated" jsonldtype="AdministrativeArea" schema={{name: "Chicago, IL"}}/>
            </Generic>
          </JSONLD>
        </section>
      </section>
    );
  }
}



export default Example;


================================================
FILE: src/example/containers/Example.scss
================================================
.Example {
  padding: 20px;
  &__heading {
    background: #333333;
  }
  &__intro {
    text-align: center;
  }
  &__json-text {
    text-align: center;
  }
  &__code {
    // display: flex;
  }
  &__code-block {
    display: flex;
    pre {
      padding: 20px;
    }
  }
}


================================================
FILE: src/example/containers/TextExamples.js
================================================
export const product = `
  <JSONLD>
    <Product
      name="Product Name"
      id="product-x" />
  </JSONLD>
`;

export const productOutput = `
  <script type="application/ld+json">
    {
      "@context":"https://schema.org/",
      "@type":"Product",
      "name":"Product Name",
      "id":"product-x"
    }
  </script>
`;

export const aggregateRating = `
  <JSONLD>
    <AggregateRating
      ratingValue={4.3}
      reviewCount={197}>
      <ItemReviewed>
        <Product
          name="Product Name"
          parentID="product-x" />
      </ItemReviewed>
    </AggregateRating>
  </JSONLD>
`;

export const aggregateRatingOutput = `
  <script type="application/ld+json">
    {
      "@context":"https://schema.org/",
      "@type":"AggregateRating",
      "ratingValue":4.3,
      "reviewCount":197,
      "itemReviewed": {
        "@type":"Product",
        "@id":"product-x"
      }
    }
  </script>
`;

export const reviews = `
  <JSONLD>
    <Graph>
      <Review
        name="It's awesome"
        reviewBody="This is Great! My family loves it"
        datePublished="11/22/1963">
        <Author name="Jerry"/>
        <Location name="Chicago, IL"/>
        <Rating ratingValue={5} />
        <ItemReviewed>
          <Product
            name="Product Name"
            parentID="product-x" />
        </ItemReviewed>
      </Review>
      <Review
        name="Very cool"
        reviewBody="I like this a lot. Very cool product"
        datePublished="11/22/1963">
        <Author name="Cool Carl"/>
        <Location name="Chicago, IL"/>
        <Rating ratingValue={4} />
        <ItemReviewed>
          <Product
            name="Product Name"
            parentID="product-x" />
        </ItemReviewed>
      </Review>
    </Graph>
  </JSONLD>
`;

export const reviewsOutput = `
  <script type="application/ld+json">
    {
      "@context": "https://schema.org/",
      "@graph": [{
        "@type": "Review",
        "name": "It's awesome",
        "reviewBody": "This is Great! My family loves it",
        "datePublished": "11/22/1963",
        "author": {
          "@type": "Person",
          "name": "Jerry"
        },
        "locationCreated": {
          "@type": "AdministrativeArea",
          "name": "Chicago, IL"
        },
        "reviewRating": {
          "@type": "Rating",
          "ratingValue": 5
        },
        "itemReviewed": {
          "@type": "Product",
          "@id": "product-x"
        }
      }, {
        "@type": "Review",
        "name": "Very cool",
        "reviewBody": "I like this a lot. Very cool product",
        "datePublished": "11/22/1963",
        "author": {
          "@type": "Person",
          "name": "Cool Carl"
        },
        "locationCreated": {
          "@type": "AdministrativeArea",
          "name": "Chicago, IL"
        },
        "reviewRating": {
          "@type": "Rating",
          "ratingValue": 4
        },
        "itemReviewed": {
          "@type": "Product",
          "@id": "product-x"
        }
      }]
    }
  </script>
`;


================================================
FILE: src/index.css
================================================
body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}


================================================
FILE: src/index.js
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Main from './example/Main';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<Main />, document.getElementById('root'));
registerServiceWorker();


================================================
FILE: src/registerServiceWorker.js
================================================
// In production, we register a service worker to serve assets from local cache.

// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.

// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.

const isLocalhost = Boolean(
  window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

export default function register() {
  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return;
    }

    window.addEventListener('load', () => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

      if (isLocalhost) {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl);
      } else {
        // Is not local host. Just register service worker
        registerValidSW(swUrl);
      }
    });
  }
}

function registerValidSW(swUrl) {
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              // At this point, the old content will have been purged and
              // the fresh content will have been added to the cache.
              // It's the perfect time to display a "New content is
              // available; please refresh." message in your web app.
              console.log('New content is available; please refresh.');
            } else {
              // At this point, everything has been precached.
              // It's the perfect time to display a
              // "Content is cached for offline use." message.
              console.log('Content is cached for offline use.');
            }
          }
        };
      };
    })
    .catch(error => {
      console.error('Error during service worker registration:', error);
    });
}

function checkValidServiceWorker(swUrl) {
  // Check if the service worker can be found. If it can't reload the page.
  fetch(swUrl)
    .then(response => {
      // Ensure service worker exists, and that we really are getting a JS file.
      if (
        response.status === 404 ||
        response.headers.get('content-type').indexOf('javascript') === -1
      ) {
        // No service worker found. Probably a different app. Reload the page.
        navigator.serviceWorker.ready.then(registration => {
          registration.unregister().then(() => {
            window.location.reload();
          });
        });
      } else {
        // Service worker found. Proceed as normal.
        registerValidSW(swUrl);
      }
    })
    .catch(() => {
      console.log(
        'No internet connection found. App is running in offline mode.'
      );
    });
}

export function unregister() {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.ready.then(registration => {
      registration.unregister();
    });
  }
}


================================================
FILE: webpack.config.js
================================================
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.join(__dirname, "/dist"),
    filename: 'static/js/bundle.js',
    chunkFilename: 'static/js/[name].chunk.js',
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      },
      {
        test: /\.(scss|sass|css)$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader?modules&importLoaders=1&camelCase&localIdentName=[local]&-autoprefixer!postcss-loader!sass-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "public/index.html"
    }),
    new MiniCssExtractPlugin({
      filename: "styles.css"
    })
  ]
};
gitextract_7ekl7nb7/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── _config.yml
├── package.json
├── postcss.config.js
├── public/
│   ├── index.html
│   └── manifest.json
├── src/
│   ├── core/
│   │   ├── JSONLD.js
│   │   ├── JSONLDAbstractNode.js
│   │   ├── index.js
│   │   └── schemas/
│   │       ├── AggregateRating.js
│   │       ├── Answer.js
│   │       ├── Author.js
│   │       ├── Generic.js
│   │       ├── GenericCollection.js
│   │       ├── Graph.js
│   │       ├── ItemReviewed.js
│   │       ├── Location.js
│   │       ├── Product.js
│   │       ├── Question.js
│   │       ├── Rating.js
│   │       ├── Review.js
│   │       ├── Reviews.js
│   │       └── index.js
│   ├── example/
│   │   ├── Main.css
│   │   ├── Main.js
│   │   └── containers/
│   │       ├── Example.js
│   │       ├── Example.scss
│   │       └── TextExamples.js
│   ├── index.css
│   ├── index.js
│   └── registerServiceWorker.js
└── webpack.config.js
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (36K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 799,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise descriptio..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 560,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem?..."
  },
  {
    "path": ".gitignore",
    "chars": 307,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# testing\n/cov..."
  },
  {
    "path": ".npmignore",
    "chars": 139,
    "preview": "src/*\nbuild/*\n_config.yml\nyarn-error.log\n.npmignore\nregisterServiceWorker.js\npostcss.config.js\nyarn.lock\nconfig/*\npublic..."
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2017 Ben Taylor\n\nPermission is hereby granted, free of charge, to any person obtaining a copy..."
  },
  {
    "path": "README.md",
    "chars": 5444,
    "preview": "# React Structured Data\n\nReact Structured Data provides an easy way to add structured data to your React apps. Structure..."
  },
  {
    "path": "_config.yml",
    "chars": 26,
    "preview": "theme: jekyll-theme-cayman"
  },
  {
    "path": "package.json",
    "chars": 2508,
    "preview": "{\n  \"name\": \"react-structured-data\",\n  \"version\": \"0.0.14\",\n  \"description\": \"Declarative JSON-LD Structured Data for Re..."
  },
  {
    "path": "postcss.config.js",
    "chars": 20,
    "preview": "module.exports = {}\n"
  },
  {
    "path": "public/index.html",
    "chars": 1596,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-wid..."
  },
  {
    "path": "public/manifest.json",
    "chars": 363,
    "preview": "{\n  \"short_name\": \"React Structured Data\",\n  \"name\": \"Example of adding declaritive structured data with React\",\n  \"icon..."
  },
  {
    "path": "src/core/JSONLD.js",
    "chars": 947,
    "preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport const JSONLD = props => {\n  let json = null;\n  if..."
  },
  {
    "path": "src/core/JSONLDAbstractNode.js",
    "chars": 1267,
    "preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nclass JSONLDAbstractNode extends React.Component {\n\n  st..."
  },
  {
    "path": "src/core/index.js",
    "chars": 73,
    "preview": "export * from './schemas';\nexport { default as JSONLD } from './JSONLD';\n"
  },
  {
    "path": "src/core/schemas/AggregateRating.js",
    "chars": 466,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass AggregateRating extends JSONLDAbstractNode {\n  getJSON(is..."
  },
  {
    "path": "src/core/schemas/Answer.js",
    "chars": 439,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Answer extends JSONLDAbstractNode {\n  getJSON(isFirstChil..."
  },
  {
    "path": "src/core/schemas/Author.js",
    "chars": 430,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Author extends JSONLDAbstractNode {\n  getJSON(isFirstChil..."
  },
  {
    "path": "src/core/schemas/Generic.js",
    "chars": 395,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass ChildNode extends JSONLDAbstractNode {\n  getJSON(isFirstC..."
  },
  {
    "path": "src/core/schemas/GenericCollection.js",
    "chars": 250,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass JSONLDNodeCollection extends JSONLDAbstractNode {\n  getJS..."
  },
  {
    "path": "src/core/schemas/Graph.js",
    "chars": 279,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Graph extends JSONLDAbstractNode {\n  getJSON(isFirstChild..."
  },
  {
    "path": "src/core/schemas/ItemReviewed.js",
    "chars": 551,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass ItemReviewed extends JSONLDAbstractNode {\n  getJSON(isFir..."
  },
  {
    "path": "src/core/schemas/Location.js",
    "chars": 455,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Location extends JSONLDAbstractNode {\n  getJSON(isFirstCh..."
  },
  {
    "path": "src/core/schemas/Product.js",
    "chars": 434,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Product extends JSONLDAbstractNode {\n  getJSON(isFirstChi..."
  },
  {
    "path": "src/core/schemas/Question.js",
    "chars": 438,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Question extends JSONLDAbstractNode {\n  getJSON(isFirstCh..."
  },
  {
    "path": "src/core/schemas/Rating.js",
    "chars": 436,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Rating extends JSONLDAbstractNode {\n  getJSON(isFirstChil..."
  },
  {
    "path": "src/core/schemas/Review.js",
    "chars": 346,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Review extends JSONLDAbstractNode {\n  getJSON(isFirstChil..."
  },
  {
    "path": "src/core/schemas/Reviews.js",
    "chars": 179,
    "preview": "import JSONLDAbstractNode from '../JSONLDAbstractNode';\n\nclass Reviews extends JSONLDAbstractNode {\n  getJSON() {\n    re..."
  },
  {
    "path": "src/core/schemas/index.js",
    "chars": 662,
    "preview": "export { default as AggregateRating } from './AggregateRating';\nexport { default as Author } from './Author';\nexport { d..."
  },
  {
    "path": "src/example/Main.css",
    "chars": 453,
    "preview": ".Main {\n  text-align: center;\n}\n\n.Main-logo {\n  animation: Main-logo-spin infinite 20s linear;\n  height: 80px;\n}\n\n.Main-..."
  },
  {
    "path": "src/example/Main.js",
    "chars": 173,
    "preview": "import React from 'react';\nimport './Main.css';\nimport Example from './containers/Example';\n\nconst Main = () => (\n  <mai..."
  },
  {
    "path": "src/example/containers/Example.js",
    "chars": 2311,
    "preview": "import React, { PureComponent } from 'react';\nimport styles from './Example.scss';\nimport {\n  JSONLD,\n  Graph,\n  Product..."
  },
  {
    "path": "src/example/containers/Example.scss",
    "chars": 276,
    "preview": ".Example {\n  padding: 20px;\n  &__heading {\n    background: #333333;\n  }\n  &__intro {\n    text-align: center;\n  }\n  &__js..."
  },
  {
    "path": "src/example/containers/TextExamples.js",
    "chars": 3044,
    "preview": "export const product = `\n  <JSONLD>\n    <Product\n      name=\"Product Name\"\n      id=\"product-x\" />\n  </JSONLD>\n`;\n\nexpor..."
  },
  {
    "path": "src/index.css",
    "chars": 63,
    "preview": "body {\n  margin: 0;\n  padding: 0;\n  font-family: sans-serif;\n}\n"
  },
  {
    "path": "src/index.js",
    "chars": 265,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport Main from './example/Main';\nim..."
  },
  {
    "path": "src/registerServiceWorker.js",
    "chars": 4021,
    "preview": "// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on su..."
  },
  {
    "path": "webpack.config.js",
    "chars": 899,
    "preview": "const path = require(\"path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\nconst MiniCssExtractPlugin = req..."
  }
]

About this extraction

This page contains the full source code of the bentaylor2/react-structured-data GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (31.6 KB), approximately 8.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!