Add icon license to JSON linting (and change JSON linting dependency) (#4945)

* Add "license" object to the data file JSON schema

* Add license to GNU and GNU social

As an example, based on the discussion in:
https://github.com/simple-icons/simple-icons/issues/1167

* Use `"additionalProperties": false` in JSON schema

... to detect properties in the data file that shouldn't be there.

For more info, see:
https://json-schema.org/understanding-json-schema/reference/object.html

* Update JSON scheme descriptions

* Switch from jsonlint2 to jsonschema

This gives is better support for advanced features of JSON schema.

A couple of clarifications:
- There does exist a jsonschema-cli package, but it is rather limited
  and crucially doens't exit with a non-zero exit code if there is an
  error. (it is also pretty old and not maintained), hence the custom
  script.
- I renamed .jsonlintschema 1) for clarity (lint is no longer accurate)
  and 2) the .json extension allows easy imorting in the script and 3)
  it adds syntax highlighting.
- The script outputs the number of errors in the end because the output
  gets pretty big pretty quickly, this way you can see it easily from
  your CLI.
- We could customize how the errors are logged, but I feel that is
  beyond this PR.

* Two minor changes

* Use `oneOf` to require URL for custom licenses

The updated configuration allows the `"license"` field to be either
1) a SPDX license, optional with a URL
2) a "custom" license with a required URL

Read more about the "oneOf" feature of jsonschema at:
https://json-schema.org/understanding-json-schema/reference/combining.html#oneof

* Include license field in Contributing Guidelines
This commit is contained in:
Eric Cornelissen 2021-02-19 15:19:22 +01:00 committed by GitHub
parent 9c029bc706
commit 39269e7d39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 118 deletions

View file

@ -1,46 +0,0 @@
{
"title": "Simple Icons",
"type": "object",
"properties": {
"icons": {
"description": "The list of icons",
"type": "array",
"items": {
"description": "A single icon",
"type": "object",
"properties": {
"title": {
"description": "The icons name",
"type": "string",
"required": true
},
"slug": {
"description": "The brand name slug (used as filename in icons/)",
"type": "string",
"pattern": "^[a-z0-9\\-]+_[a-z0-9\\-]+$",
"required": false
},
"hex": {
"description": "The icons color, as HEX (without #)",
"type": "string",
"pattern": "^[0-9A-F]{6}$",
"required": true
},
"source": {
"description": "The website from which the icon originated",
"type": "string",
"pattern": "^https?://[^\\s]+$",
"required": true
},
"guidelines": {
"description": "The brand guidelines for the icon and/or color",
"type": "string",
"pattern": "^https?://[^\\s]+$",
"required": false
}
},
"required": true
}
}
}
}

162
.jsonschema.json Normal file
View file

@ -0,0 +1,162 @@
{
"title": "Simple Icons",
"definitions": {
"brand": {
"description": "A single brand",
"type": "object",
"required": ["title", "hex", "source"],
"properties": {
"title": {
"description": "The name of the brand",
"type": "string"
},
"slug": {
"description": "The brand name slug (used as filename in icons/)",
"type": "string",
"pattern": "^[a-z0-9\\-]+_[a-z0-9\\-]+$",
"required": false
},
"hex": {
"description": "The brand color as a 6-character value (without #)",
"type": "string",
"pattern": "^[0-9A-F]{6}$"
},
"source": {
"description": "The website from which the icon was sourced",
"$ref": "#/definitions/url"
},
"guidelines": {
"description": "The brand guidelines",
"$ref": "#/definitions/url"
},
"license": {
"description": "The license for the icon",
"oneOf": [
{
"type": "object",
"required": ["type", "url"],
"properties": {
"type": {
"description": "The license name or 'custom'",
"type": "string",
"enum": ["custom"]
},
"url": {
"description": "The URL to the license text by the brand",
"$ref": "#/definitions/url"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["type"],
"properties": {
"type": {
"description": "An SPDX License Identifier",
"type": "string",
"enum": [
"0BSD",
"AAL",
"AFL-1.1",
"AFL-1.2",
"AFL-2.0",
"AFL-3.0",
"Afmparse",
"AGPL-1.0-only",
"AGPL-1.0-or-later",
"AGPL-3.0-only",
"AGPL-3.0-or-later",
"Aladdin",
"AML",
"AMPAS",
"Apache-1.0",
"Apache-1.1",
"Apache-2.0",
"APL-1.0",
"Artistic-1.0",
"Artistic-1.0-cl8",
"Artistic-1.0-Perl",
"Artistic-2.0",
"CC-BY-1.0",
"CC-BY-2.0",
"CC-BY-2.5",
"CC-BY-3.0",
"CC-BY-4.0",
"CC-BY-NC-ND-1.0",
"CC-BY-NC-ND-2.0",
"CC-BY-NC-ND-2.5",
"CC-BY-NC-ND-3.0",
"CC-BY-NC-ND-4.0",
"CC-BY-NC-SA-1.0",
"CC-BY-NC-SA-2.0",
"CC-BY-NC-SA-2.5",
"CC-BY-NC-SA-3.0",
"CC-BY-NC-SA-4.0",
"CC-BY-ND-1.0",
"CC-BY-ND-2.0",
"CC-BY-ND-2.5",
"CC-BY-ND-3.0",
"CC-BY-ND-4.0",
"CC-BY-SA-1.0",
"CC-BY-SA-2.0",
"CC-BY-SA-2.5",
"CC-BY-SA-3.0",
"CC-BY-SA-4.0",
"CC-PDDC",
"CC0-1.0",
"CDDL-1.0",
"CDDL-1.1",
"ClArtistic",
"copyleft-next-0.3.0",
"copyleft-next-0.3.1",
"CPAL-1.0",
"CPL-1.0",
"CPOL-1.02",
"EUPL-1.0",
"EUPL-1.1",
"EUPL-1.2",
"GPL-1.0-only",
"GPL-1.0-or-later",
"GPL-2.0-only",
"GPL-2.0-or-later",
"GPL-3.0-only",
"GPL-3.0-or-later",
"LAL-1.2",
"LAL-1.3",
"NLPL",
"OPL-1.0",
"Unlicense",
"UPL-1.0",
"WTFPL"
]
},
"url": {
"description": "The URL to the license text by the brand",
"$ref": "#/definitions/url"
}
},
"additionalProperties": false
}
]
}
},
"additionalProperties": false
},
"url": {
"$id": "#url",
"type": "string",
"pattern": "^https?://[^\\s]+$"
}
},
"type": "object",
"properties": {
"icons": {
"description": "A list of brands",
"type": "array",
"items": { "$ref": "#/definitions/brand" }
}
}
}

View file

@ -189,16 +189,23 @@ Icon metadata should be added to the `_data/simple-icons.json` file. Each icon i
* A `hex` color value that matches the brand's primary color. All uppercase and without the `#` pound symbol.)
* The `source` URL of the logo being used. There are [more details below](#source-guidelines).
There is also an optional field that may be used to specify the brand guidelines/presskit/etc. This is useful if the SVG file was sourced from a different place.
Additionally, there are also optional fields that may provided for an icon:
Here is the object for The Movie Database as an example:
- The `guidelines` may be used to specify the URL of the brand's guidelines/presskit/etc. This is useful if the SVG file was sourced from a different place.
- The `license` may be used to record the license under which the icon is available. This is an object with a `type` and `url`. The `type` should be an [SPDX License ID](https://spdx.org/licenses/) or `"custom"`, the `url` is optional unless the `type` is `"custom"`.
Here is the object of a fictional brand as an example:
```json
{
"title": "The Movie Database",
"hex": "01D277",
"source": "https://www.themoviedb.org/about/logos-attribution",
"guidelines": "https://www.themoviedb.org/about/logos-attribution"
"title": "A Fictional Brand",
"hex": "123456",
"source": "https://www.a-fictional-brand.org/logo",
"guidelines": "https://www.a-fictional-brand.org/brand-guidelines",
"license": {
"type": "CC0-1.0",
"url": "https://www.a-fictional-brand.org/logo/license"
}
}
```

View file

@ -2990,7 +2990,10 @@
{
"title": "GNU",
"hex": "A42E2B",
"source": "https://gnu.org"
"source": "https://gnu.org",
"license": {
"type": "CC-BY-SA-2.0"
}
},
{
"title": "GNU Bash",
@ -3015,7 +3018,10 @@
{
"title": "GNU social",
"hex": "A22430",
"source": "https://www.gnu.org/graphics/social.html"
"source": "https://www.gnu.org/graphics/social.html",
"license": {
"type": "CC0-1.0"
}
},
{
"title": "Go",

67
package-lock.json generated
View file

@ -761,12 +761,6 @@
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
"dev": true
},
"JSV": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
"integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=",
"dev": true
},
"abab": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
@ -2273,12 +2267,6 @@
"function-bind": "^1.1.1"
}
},
"has-color": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
"integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -3382,15 +3370,11 @@
"minimist": "^1.2.5"
}
},
"jsonlint2": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/jsonlint2/-/jsonlint2-1.7.1.tgz",
"integrity": "sha512-LNhh7oMVw5ooebi1ArmKPeOUWNfUd2NBGM065KVSdfSJs/OmdTTvEvAXkW8gf1XG6gJ/qn1SRIYXwufxHnbgQw==",
"dev": true,
"requires": {
"JSV": ">= 4.0.x",
"nomnom": "1.8.1"
}
"jsonschema": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz",
"integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==",
"dev": true
},
"jsprim": {
"version": "1.4.1",
@ -3926,41 +3910,6 @@
}
}
},
"nomnom": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz",
"integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=",
"dev": true,
"requires": {
"chalk": "~0.4.0",
"underscore": "~1.6.0"
},
"dependencies": {
"ansi-styles": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz",
"integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=",
"dev": true
},
"chalk": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
"integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=",
"dev": true,
"requires": {
"ansi-styles": "~1.0.0",
"has-color": "~0.1.0",
"strip-ansi": "~0.1.0"
}
},
"strip-ansi": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz",
"integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=",
"dev": true
}
}
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -5791,12 +5740,6 @@
"integrity": "sha512-SIZhkoh+U/wjW+BHGhVwE9nt8tWJspncloBcFapkpGRwNPqcH8pzX36BXe3TPBjzHWPMUZotpCigak/udWNr1Q==",
"dev": true
},
"underscore": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
"dev": true
},
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",

View file

@ -21,7 +21,7 @@
"editorconfig-checker": "3.3.0",
"jest": "26.6.3",
"jest-diff": "26.6.2",
"jsonlint2": "1.7.1",
"jsonschema": "1.4.0",
"npm-run-all": "4.1.5",
"svg-path-bbox": "0.2.0",
"svglint": "1.0.7",
@ -34,7 +34,7 @@
"clean": "rm -f icons/*.js index.js",
"lint": "run-s our-lint jsonlint svglint wslint",
"our-lint": "node scripts/lint.js",
"jsonlint": "jsonlint _data/simple-icons.json -q -V .jsonlintschema",
"jsonlint": "node scripts/jsonlint.js",
"svglint": "svglint icons/*.svg --ci",
"wslint": "editorconfig-checker -exclude \\.svg$",
"prepublishOnly": "npm run build",

19
scripts/jsonlint.js Normal file
View file

@ -0,0 +1,19 @@
const path = require("path");
const Validator = require("jsonschema").Validator;
const schemaFile = path.resolve(__dirname, "..", ".jsonschema.json");
const dataFile = path.resolve(__dirname, "..", "_data", "simple-icons.json");
const schema = require(schemaFile);
const data = require(dataFile);
const validator = new Validator();
const result = validator.validate(data, schema);
if (result.errors.length > 0) {
result.errors.forEach((error) => {
console.error(error);
});
console.error(`Found ${result.errors.length} error(s) in simple-icons.json`);
process.exit(1);
}