├── commitlint.config.js
├── packages
├── jsonld-lint-vscode
│ ├── .gitignore
│ ├── assets
│ │ └── vscode.gif
│ ├── .vscodeignore
│ ├── README.md
│ ├── src
│ │ ├── test
│ │ │ ├── suite
│ │ │ │ ├── extension.test.ts
│ │ │ │ └── index.ts
│ │ │ └── runTest.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ ├── CHANGELOG.md
│ └── package.json
├── jsonld-lint
│ ├── __tests__
│ │ ├── __fixtures__
│ │ │ ├── 0002-in.json
│ │ │ ├── 0003-in.json
│ │ │ ├── 0010-in.json
│ │ │ ├── 0005-in.json
│ │ │ ├── 0006-in.json
│ │ │ ├── 0004-in.json
│ │ │ ├── 0007-in.json
│ │ │ ├── 0011-in.json
│ │ │ ├── 0008-in.json
│ │ │ ├── 0009-in.json
│ │ │ ├── 0001-in.json
│ │ │ ├── 0011-out.json
│ │ │ ├── 0010-out.json
│ │ │ ├── 0002-out.json
│ │ │ ├── 0003-out.json
│ │ │ ├── 0006-out.json
│ │ │ ├── 0004-out.json
│ │ │ ├── 0005-out.json
│ │ │ ├── 0007-out.json
│ │ │ ├── 0009-out.json
│ │ │ ├── 0008-out.json
│ │ │ ├── 0001-out.json
│ │ │ └── index.ts
│ │ ├── lintCompactDocument.spec.ts
│ │ └── utilities.ts
│ ├── tsconfig.json
│ ├── src
│ │ ├── types
│ │ │ ├── ContextResolver.ts
│ │ │ ├── jsonld.d.ts
│ │ │ ├── JsonLdDocumentLintRule.ts
│ │ │ ├── DocumentPosition.ts
│ │ │ ├── JsonLdDocumentTermInfo.ts
│ │ │ ├── JsonLdLintOptions.ts
│ │ │ ├── JsonLdLintError.ts
│ │ │ ├── JsonLdDocumentProcessingResult.ts
│ │ │ ├── JsonLdDocumentContext.ts
│ │ │ ├── JsonLdDocumentTermContext.ts
│ │ │ ├── JsonLdDocumentLintResult.ts
│ │ │ ├── JsonLdDocumentTerm.ts
│ │ │ ├── KnownJsonLdTerm.ts
│ │ │ ├── JsonLdDocumentProcessingContext.ts
│ │ │ ├── JsonLdObjectType.ts
│ │ │ ├── index.ts
│ │ │ └── JsonLdDocumentSyntaxError.ts
│ │ ├── utilities.ts
│ │ ├── jsonldDocumentProcessor.ts
│ │ └── index.ts
│ ├── package.json
│ ├── jest.config.js
│ ├── CHANGELOG.md
│ └── README.md
└── jsonld-lint-cli
│ ├── assets
│ └── cli.gif
│ ├── tsconfig.json
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ ├── index.js
│ ├── cli.ts
│ └── utilities.ts
│ ├── README.md
│ └── jest.config.js
├── .husky
├── commit-msg
└── pre-commit
├── tsconfig.json
├── config
└── tsconfig.base.json
├── lerna.json
├── .github
├── workflows
│ ├── any.pr.yml
│ ├── github_backup.yaml
│ ├── push-master.yml
│ └── push-release.yml
└── pull_request_template.md
├── .eslintrc.json
├── .gitignore
├── docs
├── assets
│ ├── mattr-logo-square.svg
│ └── mattr-logo-tm.svg
├── RELEASE.md
└── CONTRIBUTING.md
├── package.json
├── README.md
└── LICENSE
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ["@commitlint/config-conventional"] };
2 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | .vscode-test/
4 | *.vsix
5 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0002-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": false
3 | }
4 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0003-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": 100
3 | }
4 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0010-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {},
3 | "": false
4 | }
5 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0005-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "@version": false
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0006-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "@version": 100
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | [[ -n $HUSKY_BYPASS ]] || yarn commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | [[ -n $HUSKY_BYPASS ]] || yarn pretty-quick --staged
5 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0004-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "@version": "a string"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0007-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "@notAValidProperty": 100
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0011-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "termDefinition": "@context"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/assets/cli.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattrglobal/jsonld-lint/HEAD/packages/jsonld-lint-cli/assets/cli.gif
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0008-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {},
3 | "id": "some-id",
4 | "@id": "some-duplicate-id"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0009-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {},
3 | "id": "some-id",
4 | "id": "some-duplicate-id"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/assets/vscode.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattrglobal/jsonld-lint/HEAD/packages/jsonld-lint-vscode/assets/vscode.gif
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./config/tsconfig.base.json",
3 | "include": ["packages/**/src"],
4 | "exclude": ["**/node_modules/**"]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0001-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": {
3 | "definedTerm": "https://example.com/definedTerm"
4 | },
5 | "definedTerm": "good",
6 | "undefinedTerm": "bad"
7 | }
8 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/test/**
4 | src/**
5 | .gitignore
6 | vsc-extension-quickstart.md
7 | **/tsconfig.json
8 | **/.eslintrc.json
9 | **/*.map
10 | **/*.ts
11 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0011-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "iri": "https://www.w3.org/TR/json-ld11/#the-context",
6 | "isJsonLdKeyword": true,
7 | "documentPosition": {
8 | "startPositionOffset": 4,
9 | "endPositionOffset": 14
10 | }
11 | }
12 | ]
13 |
--------------------------------------------------------------------------------
/config/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "lib": ["es6"],
6 | "sourceMap": true,
7 | "allowJs": false,
8 | "moduleResolution": "node",
9 | "strict": true,
10 | "declaration": true,
11 | "downlevelIteration": true,
12 | "types": ["node", "jest"],
13 | "typeRoots": ["../node_modules/@types"],
14 | "baseUrl": ".",
15 | "resolveJsonModule": true
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "sourceMap": true,
6 | "allowJs": false,
7 | "moduleResolution": "node",
8 | "strict": true,
9 | "declaration": true,
10 | "downlevelIteration": true,
11 | "baseUrl": ".",
12 | "esModuleInterop": true,
13 | "resolveJsonModule": true,
14 | "outDir": "./bin",
15 | "types": ["jest", "node"]
16 | },
17 | "include": ["./src"]
18 | }
19 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "sourceMap": true,
6 | "allowJs": false,
7 | "moduleResolution": "node",
8 | "strict": true,
9 | "declaration": true,
10 | "downlevelIteration": true,
11 | "baseUrl": ".",
12 | "esModuleInterop": true,
13 | "resolveJsonModule": true,
14 | "outDir": "./lib",
15 | "types": ["jest", "node"]
16 | },
17 | "include": ["./src"]
18 | }
19 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # JSON-LD Lint VS-Code Extension
4 |
5 | 
6 | 
7 |
8 | _Coming soon_
9 |
10 | The jsonld-lint engine bundled as a [vscode](https://code.visualstudio.com/) extension.
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "independent",
3 | "npmClient": "yarn",
4 | "npmClientArgs": ["--no-optional", "--frozen-lockfile"],
5 | "useWorkspaces": true,
6 | "packages": ["packages/*"],
7 | "command": {
8 | "publish": {
9 | "allowBranch": ["master"],
10 | "conventionalCommits": true,
11 | "verifyAccess": false
12 | },
13 | "version": {
14 | "allowBranch": ["release"],
15 | "conventionalCommits": true,
16 | "message": "chore(release): publish [skip ci]"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/src/test/suite/extension.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from "assert";
2 |
3 | // You can import and use all API from the 'vscode' module
4 | // as well as import your extension to test it
5 | import * as vscode from "vscode";
6 | // import * as myExtension from '../../extension';
7 |
8 | suite("Extension Test Suite", () => {
9 | vscode.window.showInformationMessage("Start all tests.");
10 |
11 | test("Sample test", () => {
12 | assert.equal(-1, [1, 2, 3].indexOf(5));
13 | assert.equal(-1, [1, 2, 3].indexOf(0));
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/.github/workflows/any.pr.yml:
--------------------------------------------------------------------------------
1 | name: any-pr
2 |
3 | on: [pull_request]
4 |
5 | jobs:
6 | build_test:
7 | name: Build test
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | node-version: [18.x, 20.x, 22.x]
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Use Node.js ${{ matrix.node-version }}
15 | uses: actions/setup-node@v4
16 | with:
17 | node-version: ${{ matrix.node-version }}
18 | - run: yarn install --frozen-lockfile
19 | - run: yarn lint
20 | - run: yarn build
21 | - run: yarn test
22 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "parserOptions": {
5 | "ecmaVersion": 6,
6 | "sourceType": "module"
7 | },
8 | "plugins": ["@typescript-eslint", "node"],
9 | "extends": [
10 | "eslint:recommended",
11 | "plugin:@typescript-eslint/eslint-recommended",
12 | "plugin:@typescript-eslint/recommended",
13 | "plugin:prettier/recommended"
14 | ],
15 | "rules": {
16 | "@typescript-eslint/explicit-function-return-type": "error",
17 | "@typescript-eslint/no-explicit-any": "error",
18 | "node/no-extraneous-import": "error"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0010-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "iri": "https://www.w3.org/TR/json-ld11/#the-context",
6 | "isJsonLdKeyword": true,
7 | "documentPosition": {
8 | "startPositionOffset": 4,
9 | "endPositionOffset": 14
10 | }
11 | },
12 | {
13 | "type": "jsonld-lint-result/syntax-error",
14 | "rule": "jsonld-lint/empty-json-property-key",
15 | "message": "Empty JSON property encountered",
16 | "documentPosition": {
17 | "startPositionOffset": 22,
18 | "endPositionOffset": 24
19 | }
20 | }
21 | ]
22 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0002-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/syntax-error",
13 | "rule": "jsonld-lint/unexpected-json-value-type",
14 | "message": "Value type for the JSON-LD keyword \"@context\" of \"boolean\" is invalid, expected one of type: string,array,object",
15 | "documentPosition": {
16 | "startPositionOffset": 16,
17 | "endPositionOffset": 21
18 | },
19 | "value": "@context"
20 | }
21 | ]
22 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0003-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/syntax-error",
13 | "rule": "jsonld-lint/unexpected-json-value-type",
14 | "message": "Value type for the JSON-LD keyword \"@context\" of \"number\" is invalid, expected one of type: string,array,object",
15 | "documentPosition": {
16 | "startPositionOffset": 16,
17 | "endPositionOffset": 19
18 | },
19 | "value": "@context"
20 | }
21 | ]
22 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/src/test/runTest.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 |
3 | import { runTests } from "vscode-test";
4 |
5 | async function main() {
6 | try {
7 | // The folder containing the Extension Manifest package.json
8 | // Passed to `--extensionDevelopmentPath`
9 | const extensionDevelopmentPath = path.resolve(__dirname, "../../");
10 |
11 | // The path to test runner
12 | // Passed to --extensionTestsPath
13 | const extensionTestsPath = path.resolve(__dirname, "./suite/index");
14 |
15 | // Download VS Code, unzip it and run the integration test
16 | await runTests({ extensionDevelopmentPath, extensionTestsPath });
17 | } catch (err) {
18 | console.error("Failed to run tests");
19 | process.exit(1);
20 | }
21 | }
22 |
23 | main();
24 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "out",
6 | "lib": ["es6"],
7 | "noImplicitAny": false,
8 | "noImplicitReturns": true,
9 | "sourceMap": true,
10 | "rootDir": "src",
11 | "esModuleInterop": true,
12 | "strict": true /* enable all strict type-checking options */,
13 | "types": ["node"]
14 | /* Additional Checks */
15 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
16 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
17 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
18 | },
19 | "exclude": ["node_modules", ".vscode-test"]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [0.4.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-cli@0.3.0...jsonld-lint-cli@0.4.0) (2022-06-22)
7 |
8 | **Note:** Version bump only for package jsonld-lint-cli
9 |
10 | # [0.3.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-cli@0.2.0...jsonld-lint-cli@0.3.0) (2020-10-29)
11 |
12 | **Note:** Version bump only for package jsonld-lint-cli
13 |
14 | # [0.2.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-cli@0.1.0...jsonld-lint-cli@0.2.0) (2020-10-09)
15 |
16 | **Note:** Version bump only for package jsonld-lint-cli
17 |
18 | # 0.1.0 (2020-10-08)
19 |
20 | Initial release
21 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/ContextResolver.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * A JSON-LD Context resolver
16 | */
17 | export declare class ContextResolver {
18 | constructor(options: any);
19 |
20 | resolve(options: any): Promise;
21 | }
22 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/jsonld.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * Declare placeholder module for missing types for jsonld.js
16 | */
17 | declare module "jsonld";
18 | declare module "jsonld/lib/context";
19 | declare module "jsonld/lib/ContextResolver";
20 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [0.4.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-vscode@0.3.0...jsonld-lint-vscode@0.4.0) (2022-06-22)
7 |
8 | **Note:** Version bump only for package jsonld-lint-vscode
9 |
10 | # [0.3.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-vscode@0.2.0...jsonld-lint-vscode@0.3.0) (2020-10-29)
11 |
12 | **Note:** Version bump only for package jsonld-lint-vscode
13 |
14 | # [0.2.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint-vscode@0.1.0...jsonld-lint-vscode@0.2.0) (2020-10-09)
15 |
16 | **Note:** Version bump only for package jsonld-lint-vscode
17 |
18 | # 0.1.0 (2020-10-08)
19 |
20 | Initial release
21 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0006-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/term-definition",
13 | "name": "@version",
14 | "isJsonLdKeyword": true,
15 | "documentPosition": {
16 | "startPositionOffset": 22,
17 | "endPositionOffset": 32
18 | }
19 | },
20 | {
21 | "type": "jsonld-lint-result/syntax-error",
22 | "rule": "jsonld-lint/unexpected-json-value",
23 | "message": "Value for the JSON-LD keyword \"@version\" of \"100\" is invalid, expected one of: 1,1,1.1",
24 | "value": "@version",
25 | "documentPosition": {
26 | "startPositionOffset": 34,
27 | "endPositionOffset": 37
28 | }
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentLintRule.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * Result from processing a JSON-LD Document
16 | */
17 | export enum JsonLdDocumentLintRule {
18 | UnrecognizedJsonLdKeyword = "jsonld-lint/unrecognized-jsonld-keyword",
19 | UnmappedTerm = "jsonld-lint/unmapped-term",
20 | }
21 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0004-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/term-definition",
13 | "name": "@version",
14 | "isJsonLdKeyword": true,
15 | "documentPosition": {
16 | "startPositionOffset": 22,
17 | "endPositionOffset": 32
18 | }
19 | },
20 | {
21 | "type": "jsonld-lint-result/syntax-error",
22 | "rule": "jsonld-lint/unexpected-json-value-type",
23 | "message": "Value type for the JSON-LD keyword \"@version\" of \"string\" is invalid, expected type: number",
24 | "documentPosition": {
25 | "startPositionOffset": 34,
26 | "endPositionOffset": 44
27 | },
28 | "value": "@version"
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0005-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/term-definition",
13 | "name": "@version",
14 | "isJsonLdKeyword": true,
15 | "documentPosition": {
16 | "startPositionOffset": 22,
17 | "endPositionOffset": 32
18 | }
19 | },
20 | {
21 | "type": "jsonld-lint-result/syntax-error",
22 | "rule": "jsonld-lint/unexpected-json-value-type",
23 | "message": "Value type for the JSON-LD keyword \"@version\" of \"boolean\" is invalid, expected type: number",
24 | "documentPosition": {
25 | "startPositionOffset": 34,
26 | "endPositionOffset": 39
27 | },
28 | "value": "@version"
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsonld-lint-cli",
3 | "description": "JSON-LD Linter CLI",
4 | "license": "Apache-2.0",
5 | "homepage": "https://github.com/mattrglobal/jsonld-lint",
6 | "version": "0.4.0",
7 | "main": "lib/index.js",
8 | "bin": {
9 | "jsonld-lint": "./bin/index.js"
10 | },
11 | "directories": {
12 | "bin": "bin"
13 | },
14 | "files": [
15 | "bin"
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/mattrglobal/jsonld-lint.git"
20 | },
21 | "scripts": {
22 | "build": "rm -rf bin/ && tsc --pretty && cp src/index.js bin/index.js"
23 | },
24 | "devDependencies": {
25 | "@types/jest": "29.5.13",
26 | "@types/node": "17.0.42",
27 | "jest": "29.7.0",
28 | "ts-jest": "29.2.5",
29 | "typescript": "4.3.5"
30 | },
31 | "dependencies": {
32 | "commander": "6.0.0",
33 | "jsonld-lint": "0.4.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ######################
2 | # Project Specific
3 | ######################
4 | lib/
5 | jest_results/
6 | node_modules/
7 | .npmrc
8 | out/
9 | .vscode-test/
10 |
11 | ######################
12 | # Visual Studio Code
13 | ######################
14 | .vscode/
15 |
16 | ######################
17 | # Webstorm
18 | ######################
19 | .idea
20 |
21 | ######################
22 | # Windows
23 | ######################
24 | # Windows image file caches
25 | Thumbs.db
26 |
27 | # Folder config file
28 | Desktop.ini
29 |
30 | ######################
31 | # Mac OSX
32 | ######################
33 | .DS_Store
34 |
35 | # Thumbnails
36 | ._*
37 |
38 | # Files that might appear on external disk
39 | .Spotlight-V100
40 | .Trashes
41 |
42 | ######################
43 | # Logs
44 | ######################
45 | *.log*
46 |
47 | ######################
48 | # Others
49 | ######################
50 | *.*~
51 | *~
52 | .merge_file*
53 | *.swp
54 | *.swo
55 | **/bin
56 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0007-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/linting-result",
13 | "rule": "jsonld-lint/unrecognized-jsonld-keyword",
14 | "message": "The term \"@notAValidProperty\" matches the convention of a JSON-LD syntax token but is un-recognized",
15 | "value": "@notAValidProperty",
16 | "documentPosition": {
17 | "startPositionOffset": 22,
18 | "endPositionOffset": 42
19 | }
20 | },
21 | {
22 | "type": "jsonld-lint-result/term-definition",
23 | "name": "@notAValidProperty",
24 | "isJsonLdKeyword": false,
25 | "documentPosition": {
26 | "startPositionOffset": 22,
27 | "endPositionOffset": 42
28 | }
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsonld-lint",
3 | "description": "JSON-LD Linter",
4 | "license": "Apache-2.0",
5 | "homepage": "https://github.com/mattrglobal/jsonld-lint",
6 | "version": "0.4.0",
7 | "main": "lib/index.js",
8 | "directories": {
9 | "lib": "lib"
10 | },
11 | "files": [
12 | "lib"
13 | ],
14 | "typings": "lib/index.d.ts",
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/mattrglobal/jsonld-lint.git"
18 | },
19 | "scripts": {
20 | "build": "tsc --pretty",
21 | "test": "jest"
22 | },
23 | "devDependencies": {
24 | "@types/jest": "29.5.13",
25 | "@types/lru-cache": "5.1.0",
26 | "@types/node": "17.0.42",
27 | "jest": "29.7.0",
28 | "ts-jest": "29.2.5",
29 | "typescript": "4.3.5"
30 | },
31 | "dependencies": {
32 | "jsonld": "3.3.2",
33 | "lru-cache": "6.0.0",
34 | "vscode-json-languageservice": "3.8.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0009-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "isJsonLdKeyword": true,
6 | "documentPosition": {
7 | "startPositionOffset": 4,
8 | "endPositionOffset": 14
9 | }
10 | },
11 | {
12 | "type": "jsonld-lint-result/syntax-error",
13 | "rule": "jsonld-lint/duplicate-property-in-json-object",
14 | "message": "Duplicate property of \"id\" encountered",
15 | "value": "id",
16 | "documentPosition": {
17 | "startPositionOffset": 22,
18 | "endPositionOffset": 26
19 | }
20 | },
21 | {
22 | "type": "jsonld-lint-result/syntax-error",
23 | "rule": "jsonld-lint/duplicate-property-in-json-object",
24 | "message": "Duplicate property of \"id\" encountered",
25 | "value": "id",
26 | "documentPosition": {
27 | "startPositionOffset": 41,
28 | "endPositionOffset": 45
29 | }
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/src/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /*
4 | * Copyright 2020 - MATTR Limited
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | /**
17 | * This file is required as `tsc` does not follow the
18 | * file permission rules of the input when generating an
19 | * output allocating `-rw-r--r--` instead of `-rwxr-xr-x`
20 | * which is required for the file to be executable
21 | */
22 |
23 | require("./cli");
24 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0008-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "documentPosition": {
4 | "endPositionOffset": 14,
5 | "startPositionOffset": 4
6 | },
7 | "isJsonLdKeyword": true,
8 | "name": "@context",
9 | "type": "jsonld-lint-result/term-definition"
10 | },
11 | {
12 | "documentPosition": {
13 | "endPositionOffset": 26,
14 | "startPositionOffset": 22
15 | },
16 | "message": "Duplicate aliased property of JSON-LD term of \"id\" encountered",
17 | "rule": "jsonld-lint/duplicate-property-in-json-object",
18 | "type": "jsonld-lint-result/syntax-error",
19 | "value": "id"
20 | },
21 | {
22 | "documentPosition": {
23 | "endPositionOffset": 46,
24 | "startPositionOffset": 41
25 | },
26 | "message": "Duplicate aliased property of JSON-LD term of \"@id\" encountered",
27 | "rule": "jsonld-lint/duplicate-property-in-json-object",
28 | "type": "jsonld-lint-result/syntax-error",
29 | "value": "@id"
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/0001-out.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "jsonld-lint-result/term-definition",
4 | "name": "@context",
5 | "iri": "https://www.w3.org/TR/json-ld11/#the-context",
6 | "isJsonLdKeyword": true,
7 | "documentPosition": {
8 | "startPositionOffset": 4,
9 | "endPositionOffset": 14
10 | }
11 | },
12 | {
13 | "type": "jsonld-lint-result/term-definition",
14 | "name": "definedTerm",
15 | "isJsonLdKeyword": false,
16 | "iri": "https://example.com/definedTerm",
17 | "documentPosition": {
18 | "startPositionOffset": 78,
19 | "endPositionOffset": 91
20 | }
21 | },
22 | {
23 | "type": "jsonld-lint-result/linting-result",
24 | "rule": "jsonld-lint/unmapped-term",
25 | "message": "The term \"undefinedTerm\" is not defined in the document context (unmapped)",
26 | "value": "undefinedTerm",
27 | "documentPosition": {
28 | "startPositionOffset": 103,
29 | "endPositionOffset": 118
30 | }
31 | }
32 | ]
33 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/src/test/suite/index.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import Mocha from "mocha";
3 | import glob from "glob";
4 |
5 | export function run(): Promise {
6 | // Create the mocha test
7 | const mocha = new Mocha({
8 | ui: "tdd",
9 | color: true,
10 | });
11 |
12 | const testsRoot = path.resolve(__dirname, "..");
13 |
14 | return new Promise((c, e) => {
15 | glob("**/**.test.js", { cwd: testsRoot }, (err, files) => {
16 | if (err) {
17 | return e(err);
18 | }
19 |
20 | // Add files to the test suite
21 | files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
22 |
23 | try {
24 | // Run the mocha test
25 | mocha.run((failures) => {
26 | if (failures > 0) {
27 | e(new Error(`${failures} tests failed.`));
28 | } else {
29 | c();
30 | }
31 | });
32 | } catch (err) {
33 | console.error(err);
34 | e(err);
35 | }
36 | });
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # JSON-LD Lint CLI
4 |
5 | 
6 | 
7 | 
8 | 
9 |
10 | The jsonld-lint engine bundled as a CLI tool
11 |
12 |
13 |
14 | ## Getting started
15 |
16 | With your favorite package manager install
17 |
18 | With [yarn](https://yarnpkg.com/) run
19 |
20 | ```
21 | yarn add jsonld-lint-cli
22 | ```
23 |
24 | Or [npm](https://www.npmjs.com/) run
25 |
26 | ```
27 | npm i -g jsonld-lint-cli
28 | ```
29 |
30 | Now lint your document
31 |
32 | ```
33 | jsonld-lint my-jsonld-document.jsonld
34 | ```
35 |
36 | Or a directory of documents
37 |
38 | ```
39 | jsonld-lint ./my-directory-of-jsonld-documents
40 | ```
41 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | ## Description
6 |
7 |
8 |
9 | - [ ] Tests for the changes have been added (for bug fixes / features)
10 | - [ ] The commit message(s) follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)
11 | - [ ] Documentation has been added / updated (for bug fixes / features)
12 | - [ ] Changes follow the **[contributing](../CONTRIBUTING.md)** document.
13 |
14 | ## Motivation and Context
15 |
16 |
17 |
18 | ## Does this PR introduce a breaking change?
19 |
20 | - [ ] Yes
21 | - [ ] No
22 |
23 |
24 |
25 | ## Which merge strategy will you use?
26 |
27 |
28 |
29 | - [ ] Squash
30 | - [ ] Rebase (REVIEW COMMITS)
31 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/DocumentPosition.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * Defines an elements position within a document
16 | */
17 | export interface DocumentPosition {
18 | /**
19 | * A zero based offset position for the start of the term within the JSON document
20 | */
21 | readonly startPositionOffset: number;
22 | /**
23 | * A zero based offset position for the end of the term within the JSON document
24 | */
25 | readonly endPositionOffset: number;
26 | }
27 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/jest.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | const pack = require("./package");
15 |
16 | module.exports = {
17 | preset: "ts-jest",
18 | roots: ["/src", "/__tests__"],
19 | testPathIgnorePatterns: ["/node_modules/", "/output/"],
20 | testRegex: [".spec.ts$"],
21 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
22 | coveragePathIgnorePatterns: ["/__tests__"],
23 | verbose: true,
24 | name: pack.name,
25 | displayName: pack.name
26 | };
27 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/jest.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | const pack = require("./package");
15 |
16 | module.exports = {
17 | preset: "ts-jest",
18 | roots: ["/src", "/__tests__"],
19 | testPathIgnorePatterns: ["/node_modules/", "/output/"],
20 | testRegex: [".spec.ts$"],
21 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
22 | coveragePathIgnorePatterns: ["/__tests__"],
23 | testTimeout: 30000,
24 | verbose: true,
25 | name: pack.name,
26 | displayName: pack.name
27 | };
28 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentTermInfo.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * A JSON-LD document term
16 | */
17 | export interface JsonLdDocumentTermInfo {
18 | /**
19 | * The compacted term
20 | */
21 | readonly name: string;
22 | /**
23 | * The fully qualified term IRI
24 | */
25 | readonly iri?: string;
26 | /**
27 | * The value type IRI
28 | */
29 | readonly valueTypeIri?: string;
30 | /**
31 | * Indicates whether the term is a JSON-LD type
32 | */
33 | readonly isJsonLdKeyword: boolean;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdLintOptions.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdDocumentLintRule } from "./JsonLdDocumentLintRule";
15 | import { ContextResolver } from "./ContextResolver";
16 |
17 | /**
18 | * Options for linting a JSON-LD document
19 | */
20 | export interface JsonLdLintOptions {
21 | /**
22 | * The rule set to use for the linting process
23 | */
24 | readonly lintingRules?: JsonLdDocumentLintRule[];
25 | /**
26 | * JSON-LD context resolver
27 | */
28 | readonly contextResolver?: ContextResolver;
29 | }
30 |
--------------------------------------------------------------------------------
/.github/workflows/github_backup.yaml:
--------------------------------------------------------------------------------
1 | name: Mirror repository to S3
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | BackupRepoToS3:
8 | runs-on: ubuntu-latest
9 | permissions:
10 | contents: read
11 | id-token: write
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 |
16 | - name: Configure aws credentials
17 | uses: aws-actions/configure-aws-credentials@v1
18 | with:
19 | aws-region: ap-southeast-2
20 | role-to-assume: arn:aws:iam::817632051851:role/oidc-github-actions-mattrglobal-global
21 | role-duration-seconds: 900
22 | role-session-name: GithubActions
23 |
24 | - name: Backing up this repo to AWS S3
25 | uses: peter-evans/s3-backup@v1
26 | env:
27 | AWS_REGION: ${{ env.AWS_REGION }}
28 | ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
29 | MIRROR_TARGET: mattrglobal-github-backup/jsonld-lint
30 | SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
31 | AWS_SESSION_TOKEN: ${{ env.AWS_SESSION_TOKEN }}
32 | with:
33 | args: --overwrite --remove
34 |
--------------------------------------------------------------------------------
/docs/assets/mattr-logo-square.svg:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdLintError.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | export const JsonLdLintErrorName = "jsonld-lint-error";
15 |
16 | export enum JsonLdLintErrorType {
17 | ParsingError,
18 | JsonLdDetectionError,
19 | ProcessingError,
20 | JsonLdSyntaxError,
21 | }
22 |
23 | export interface JsonLdLintError {
24 | /**
25 | * Name of the error
26 | */
27 | readonly name: string;
28 | /**
29 | * Type of the error
30 | */
31 | readonly type: JsonLdLintErrorType;
32 | /**
33 | * Error message
34 | */
35 | readonly message?: string;
36 | /**
37 | * Error details
38 | */
39 | readonly details?: any;
40 | }
41 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentProcessingResult.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * An enumeration of result types
16 | */
17 | export enum JsonLdDocumentProcessingResultType {
18 | JsonLdSyntaxError = "jsonld-lint-result/syntax-error",
19 | JsonLdLintingResult = "jsonld-lint-result/linting-result",
20 | JsonLdTerm = "jsonld-lint-result/term-definition",
21 | JsonLdTermValue = "jsonld-lint-result/term-value",
22 | }
23 |
24 | /**
25 | * Base Result type from processing a JSON-LD Document
26 | */
27 | export interface BaseJsonLdDocumentProcessingResult {
28 | /**
29 | * The type of processing result
30 | */
31 | readonly type: JsonLdDocumentProcessingResultType;
32 | }
33 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsonld-lint-vscode",
3 | "description": "JSON-LD Linter for vs code",
4 | "private": true,
5 | "license": "Apache-2.0",
6 | "version": "0.4.0",
7 | "engines": {
8 | "vscode": "^1.46.1"
9 | },
10 | "categories": [
11 | "Other"
12 | ],
13 | "activationEvents": [
14 | "*"
15 | ],
16 | "main": "./out/index.js",
17 | "contributes": {
18 | "colors": [
19 | {
20 | "id": "jsonldlint.JsonLdLintResultBackgroundColor",
21 | "description": "Background color style for an issue identified by JSON-LD lint",
22 | "defaults": {
23 | "dark": "#e63333e5",
24 | "light": "#e63333e5",
25 | "highContrast": "#e63333e5"
26 | }
27 | }
28 | ]
29 | },
30 | "scripts": {
31 | "build": "tsc -p ./",
32 | "watch": "tsc -watch -p ./",
33 | "test:integration": "node ./out/test/runTest.js"
34 | },
35 | "devDependencies": {
36 | "@types/glob": "7.2.0",
37 | "@types/mocha": "8.0.0",
38 | "@types/node": "17.0.42",
39 | "@types/vscode": "1.68.0",
40 | "eslint": "7.6.0",
41 | "glob": "7.1.6",
42 | "mocha": "8.4.0",
43 | "typescript": "4.3.5",
44 | "vscode-test": "1.4.0"
45 | },
46 | "dependencies": {
47 | "jsonld-lint": "0.4.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.github/workflows/push-master.yml:
--------------------------------------------------------------------------------
1 | name: push-master
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build_test_publish:
10 | name: Build, test, and publish unstable release
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | with:
16 | # checkout master explicitly as workflow triggered on a tag which results in checkout of detached HEAD
17 | ref: master
18 | # 0 indicates all history, needed for correct unstable version generation (commit count since last release)
19 | fetch-depth: 0
20 |
21 | - name: Setup nodejs
22 | uses: actions/setup-node@v4
23 | with:
24 | node-version: 22.x
25 | registry-url: "https://registry.npmjs.org"
26 |
27 | - name: Install, lint and build
28 | run: |
29 | yarn install --frozen-lockfile
30 | yarn lint
31 | yarn build
32 |
33 | - name: Test (unit)
34 | run: yarn test
35 |
36 | - name: Publish unstable release
37 | env:
38 | NODE_AUTH_TOKEN: ${{ secrets.NPMJS_PUBLIC_TOKEN }}
39 | run: |
40 | git config user.name "Mattr CI"
41 | git config user.email "npmjs_ci_mattr_public@mattr.global"
42 |
43 | yarn publish:unstable
44 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [0.4.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint@0.3.0...jsonld-lint@0.4.0) (2022-06-22)
7 |
8 | **Note:** Version bump only for package jsonld-lint
9 |
10 | # [0.3.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint@0.2.0...jsonld-lint@0.3.0) (2020-10-29)
11 |
12 | ### Bug Fixes
13 |
14 | - **jsonld-lint:** minor improvement to linting result formating ([#15](https://github.com/mattrglobal/jsonld-lint/issues/15)) ([b795bd7](https://github.com/mattrglobal/jsonld-lint/commit/b795bd72ddf9e83b36c76bac549cf68b581101f3))
15 | - **jsonld-lint:** remove problematic rule and cleanup msg output format ([#16](https://github.com/mattrglobal/jsonld-lint/issues/16)) ([e0bb005](https://github.com/mattrglobal/jsonld-lint/commit/e0bb005791534fb9a6ab72ecaea54cf279224c89))
16 |
17 | # [0.2.0](https://github.com/mattrglobal/jsonld-lint/compare/jsonld-lint@0.1.0...jsonld-lint@0.2.0) (2020-10-09)
18 |
19 | ### Features
20 |
21 | - **jsonld-lint:** empty json property key ([e7ef6cb](https://github.com/mattrglobal/jsonld-lint/commit/e7ef6cbae61d057f285d62d12c81a0e19124b86b))
22 |
23 | # 0.1.0 (2020-10-08)
24 |
25 | Initial release
26 |
--------------------------------------------------------------------------------
/.github/workflows/push-release.yml:
--------------------------------------------------------------------------------
1 | name: push-release
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build_test_publish:
10 | name: Build, test, and publish stable release
11 | if: "contains(github.event.head_commit.message, 'chore(release): publish')"
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v4
17 | with:
18 | # checkout master explicitly as workflow triggered on a tag which results in checkout of detached HEAD
19 | ref: master
20 | # 0 indicates all history, needed for correct unstable version generation (commit count since last release)
21 | fetch-depth: 0
22 |
23 | - name: Setup nodejs
24 | uses: actions/setup-node@v4
25 | with:
26 | node-version: 22.x
27 | registry-url: "https://registry.npmjs.org"
28 |
29 | - name: Install, lint and build
30 | run: |
31 | yarn install --frozen-lockfile
32 | yarn lint
33 | yarn build
34 |
35 | - name: Test (unit)
36 | run: yarn test
37 |
38 | - name: Publish stable release
39 | env:
40 | NODE_AUTH_TOKEN: ${{ secrets.NPMJS_PUBLIC_TOKEN }}
41 | run: |
42 | git config user.name "Mattr CI"
43 | git config user.email "npmjs_ci_mattr_public@mattr.global"
44 |
45 | yarn publish:release
46 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentContext.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdDocumentTermContext } from "./JsonLdDocumentTermContext";
15 |
16 | /**
17 | * A map of terms and whether they are protected
18 | */
19 | export interface ProtectedTerms {
20 | /**
21 | * The term and boolean status on whether
22 | * it is protected
23 | */
24 | readonly [key: string]: boolean;
25 | }
26 |
27 | /**
28 | * A JSON-LD document context
29 | */
30 | export interface JsonLdDocumentContext {
31 | /**
32 | * The JSON-LD processing mode
33 | */
34 | readonly processingMode: string;
35 | /**
36 | * A map of terms and whether they are protected
37 | */
38 | readonly protected?: ProtectedTerms;
39 | /**
40 | * A map of terms and their inverse term
41 | */
42 | readonly inverse?: any;
43 | /**
44 | * TODO should validate
45 | */
46 | readonly mappings?: Map;
47 | }
48 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentTermContext.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * A JSON-LD document term context
16 | */
17 | export interface JsonLdDocumentTermContext {
18 | /**
19 | * Indicates whether the reverse property applies to this term
20 | */
21 | readonly reverse: boolean;
22 | /**
23 | * A map of terms and whether they are protected
24 | */
25 | readonly _termHasColon: boolean;
26 | /**
27 | * Identifier for the term
28 | */
29 | readonly "@id": string;
30 | /**
31 | * Type for the term
32 | */
33 | readonly "@type"?: string;
34 | /**
35 | * If the term is a context the value of the context
36 | */
37 | readonly "@context"?: any;
38 | /**
39 | * Container associated to the term
40 | */
41 | readonly "@container"?: readonly string[];
42 | /**
43 | * Indicates whether the term is protected
44 | */
45 | readonly protected: boolean;
46 | /**
47 | * Indicates whether the term is prefixed
48 | */
49 | readonly _prefix: boolean;
50 | }
51 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentLintResult.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdDocumentLintRule } from "./JsonLdDocumentLintRule";
15 | import { DocumentPosition } from "./DocumentPosition";
16 | import { JsonLdDocumentProcessingResultType } from "./JsonLdDocumentProcessingResult";
17 |
18 | /**
19 | * Result from linting a JSON-LD Document
20 | */
21 | export interface JsonLdDocumentLintResult {
22 | /**
23 | * The processing result type for a JSON-LD syntax error
24 | */
25 | readonly type: JsonLdDocumentProcessingResultType.JsonLdLintingResult;
26 | /**
27 | * The JSON-LD lint rule breached
28 | */
29 | readonly rule: JsonLdDocumentLintRule;
30 | /**
31 | * The message describing the linting result
32 | */
33 | readonly message: string;
34 | /**
35 | * Positional information indicating the where the lint
36 | * result applies to
37 | */
38 | readonly documentPosition: DocumentPosition;
39 | /**
40 | * Value of the JSON key or value the linting rule breach pertains to
41 | */
42 | readonly value?: any;
43 | }
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "root",
3 | "private": true,
4 | "license": "Apache-2.0",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/mattrglobal/jsonld-lint"
8 | },
9 | "bugs": {
10 | "url": "https://github.com/mattrglobal/jsonld-lint/issues"
11 | },
12 | "homepage": "https://github.com/mattrglobal/jsonld-lint#readme",
13 | "useWorkspaces": true,
14 | "workspaces": [
15 | "packages/*"
16 | ],
17 | "scripts": {
18 | "test": "lerna run test",
19 | "build": "lerna run build",
20 | "format": "prettier --write \"**/*.ts\" \"**/*.md\" \"!**/lib/**\"",
21 | "pre-pr": "yarn format && yarn lint:fix && yarn build && yarn test",
22 | "lint": "prettier --check \"**/*.ts\" \"**/*.md\" \"!**/lib/**\" && tslint --project ./tsconfig.json",
23 | "lint:fix": "prettier --check \"**/*.ts\" \"**/*.md\" \"!**/lib/**\" && tslint --project ./tsconfig.json --fix",
24 | "publish:unstable": "lerna publish --canary --dist-tag=unstable --preid=unstable --yes --exact",
25 | "publish:release": "lerna publish from-git --yes",
26 | "version:release": "lerna version minor --yes --exact --no-push",
27 | "prepare": "husky install"
28 | },
29 | "devDependencies": {
30 | "@commitlint/cli": "17.0.2",
31 | "@commitlint/config-conventional": "17.0.2",
32 | "husky": "8.0.1",
33 | "jest": "29.7.0",
34 | "jest-html-reporters": "3.0.9",
35 | "lerna": "5.1.8",
36 | "prettier": "2.6.2",
37 | "pretty-quick": "3.1.3",
38 | "ts-jest": "29.2.5",
39 | "tslint": "5.20.1",
40 | "tslint-config-prettier": "1.18.0",
41 | "tslint-consistent-codestyle": "1.16.0",
42 | "tslint-immutable": "6.0.1",
43 | "typescript": "4.3.5"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentTerm.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { DocumentPosition } from "./DocumentPosition";
15 | import {
16 | JsonLdDocumentProcessingResultType,
17 | BaseJsonLdDocumentProcessingResult,
18 | } from "./JsonLdDocumentProcessingResult";
19 |
20 | /**
21 | * A JSON-LD document term
22 | */
23 | export interface JsonLdDocumentTerm extends BaseJsonLdDocumentProcessingResult {
24 | /**
25 | * The processing result type for a JSON-LD syntax error
26 | */
27 | readonly type: JsonLdDocumentProcessingResultType.JsonLdTerm;
28 | /**
29 | * The compacted term
30 | */
31 | readonly name: string;
32 | /**
33 | * Indicates whether the processed term is a JSON-LD syntax token
34 | */
35 | readonly isJsonLdKeyword: boolean;
36 | /**
37 | * The fully qualified term IRI
38 | */
39 | readonly iri?: string;
40 | /**
41 | * The value type IRI
42 | */
43 | readonly valueTypeIri?: string;
44 | /**
45 | * Positional information indicating where the
46 | * term is located within the document
47 | */
48 | readonly documentPosition: DocumentPosition;
49 | }
50 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/utilities.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import {
15 | JsonLdLintErrorType,
16 | JsonLdLintError,
17 | JsonLdLintErrorName,
18 | DocumentPosition,
19 | } from "./types";
20 |
21 | /**
22 | * Converts a document offset to a position
23 | * @param offset positional offset of the element
24 | * @param length length of the element
25 | */
26 | export const documentOffSetToPosition = (
27 | offset: Number,
28 | length: number
29 | ): DocumentPosition => {
30 | const startPositionOffset = offset as number;
31 | const endPositionOffset = ((offset as number) + length) as number;
32 |
33 | return {
34 | startPositionOffset,
35 | endPositionOffset,
36 | };
37 | };
38 |
39 | /**
40 | * Creates a JSON-LD lint error
41 | * @param type Type of error to create
42 | * @param message Error message
43 | * @param details Error details
44 | */
45 | export const createJsonLdLintError = (
46 | type: JsonLdLintErrorType,
47 | message?: string,
48 | details?: any
49 | ): JsonLdLintError => {
50 | return {
51 | name: JsonLdLintErrorName,
52 | type,
53 | message,
54 | details,
55 | };
56 | };
57 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/KnownJsonLdTerm.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdObjectType } from "./JsonLdObjectType";
15 |
16 | /**
17 | * Type declaration for a value validator for a known JSON-LD term
18 | */
19 | export type ValueValidator = (value: any) => boolean;
20 |
21 | /**
22 | * A known JSON-LD term
23 | */
24 | export interface KnownJsonLdTerm {
25 | /**
26 | * The term name
27 | */
28 | readonly name: string;
29 | /**
30 | * The name of an aliased term
31 | * e.g `@id` is an alias is of `id`
32 | */
33 | readonly aliasTerm?: string;
34 | /**
35 | * The fully qualified term IRI
36 | */
37 | readonly iri?: string;
38 | /**
39 | * The expected JSON value types
40 | */
41 | readonly expectedJsonValueTypes?: string[];
42 | /**
43 | * The expected JSON values
44 | */
45 | readonly expectedJsonValues?: any[];
46 | /**
47 | * An array indicating in which JSON-LD terms
48 | */
49 | readonly validInJsonLdObjectTypes: JsonLdObjectType[];
50 | /**
51 | * A map of value validators for a known JSON-LD term
52 | */
53 | readonly valueValidators?: Map;
54 | }
55 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentProcessingContext.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdDocumentTerm } from "./JsonLdDocumentTerm";
15 | import { JsonLdDocumentContext } from "./JsonLdDocumentContext";
16 | import { JsonLdObjectType } from "./JsonLdObjectType";
17 | import { ContextResolver } from "./ContextResolver";
18 |
19 | /**
20 | * Describes the processing context
21 | */
22 | export interface JsonLdDocumentProcessingContext {
23 | /**
24 | * The type of JSON-LD object currently being processed
25 | */
26 | readonly currentJsonLdObjectType?: JsonLdObjectType;
27 | /**
28 | * Document being processed
29 | */
30 | readonly document: any;
31 | /**
32 | * The JSON-LD Document context for current document being processed
33 | */
34 | readonly jsonLdDocumentContext?: JsonLdDocumentContext;
35 | /**
36 | * An array of unmapped terms found in the JSON-LD document during initial processing
37 | */
38 | readonly unmappedTerms?: string[];
39 | /**
40 | * The current JSON-LD term being processed
41 | */
42 | readonly currentTerm?: JsonLdDocumentTerm;
43 | /**
44 | * JSON-LD context resolver
45 | */
46 | readonly contextResolver: ContextResolver;
47 | }
48 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/lintCompactDocument.spec.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { process } from "../src";
15 | import { JsonLdLintErrorType, JsonLdLintErrorName } from "../src/types";
16 | import { readFile } from "./utilities";
17 | import { testCases } from "./__fixtures__";
18 |
19 | const TEST_FIXTURES_DIRECTORY = "__tests__/__fixtures__";
20 |
21 | describe("lintCompactDocument", () => {
22 | testCases.forEach(({ inputFileName, outputFileName, description }) => {
23 | it(`should successfully ${description}`, async () => {
24 | const inputFile = await readFile(TEST_FIXTURES_DIRECTORY, inputFileName);
25 | const outputFile = await readFile(
26 | TEST_FIXTURES_DIRECTORY,
27 | outputFileName
28 | );
29 | const result = await process(inputFile);
30 | expect(result).toMatchObject(JSON.parse(outputFile));
31 | });
32 | });
33 |
34 | it("should throw parsing error when invalid JSON supplied", async () => {
35 | await expect(process("this-is-not-json")).rejects.toMatchObject({
36 | name: JsonLdLintErrorName,
37 | type: JsonLdLintErrorType.ParsingError,
38 | message: "Unable to parse input document as JSON",
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdObjectType.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * An enumeration of possible object types as per JSON-LD grammar
16 | *
17 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
18 | */
19 | export enum JsonLdObjectType {
20 | /**
21 | * Node Object
22 | *
23 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
24 | */
25 | NodeObject = "NodeObject",
26 | /**
27 | * Frame Object
28 | *
29 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
30 | */
31 | FrameObject = "FrameObject",
32 | /**
33 | * Graph Object
34 | *
35 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
36 | */
37 | GraphObject = "GraphObject",
38 | /**
39 | * Graph Object
40 | *
41 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
42 | */
43 | ValueObject = "ValueObject",
44 | /**
45 | * Local Context
46 | *
47 | * @see https://www.w3.org/TR/json-ld11/#context-definitions
48 | */
49 | LocalContextDefinition = "LocalContextDefinition",
50 | /**
51 | * Expanded Term Definition
52 | *
53 | * @see https://www.w3.org/TR/json-ld11/#expanded-term-definition
54 | */
55 | ExpandedTermDefinition = "ExpandedTermDefinition",
56 | }
57 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { JsonLdDocumentTerm } from "./JsonLdDocumentTerm";
15 | import {
16 | JsonLdDocumentSyntaxError,
17 | JsonLdDocumentSyntaxErrorRule,
18 | } from "./JsonLdDocumentSyntaxError";
19 | import { JsonLdDocumentLintResult } from "./JsonLdDocumentLintResult";
20 |
21 | export {
22 | JsonLdDocumentSyntaxError,
23 | JsonLdDocumentSyntaxErrorRule,
24 | JsonLdDocumentTerm,
25 | JsonLdDocumentLintResult,
26 | };
27 |
28 | export type JsonLdDocumentProcessingResult =
29 | | JsonLdDocumentTerm
30 | | JsonLdDocumentSyntaxError
31 | | JsonLdDocumentLintResult;
32 |
33 | export { DocumentPosition } from "./DocumentPosition";
34 | export {
35 | JsonLdLintError,
36 | JsonLdLintErrorName,
37 | JsonLdLintErrorType,
38 | } from "./JsonLdLintError";
39 | export { JsonLdLintOptions } from "./JsonLdLintOptions";
40 | export { JsonLdDocumentLintRule } from "./JsonLdDocumentLintRule";
41 | export { JsonLdDocumentProcessingContext } from "./JsonLdDocumentProcessingContext";
42 | export { KnownJsonLdTerm, ValueValidator } from "./KnownJsonLdTerm";
43 | export { JsonLdDocumentProcessingResultType } from "./JsonLdDocumentProcessingResult";
44 | export { JsonLdObjectType } from "./JsonLdObjectType";
45 | export { ContextResolver } from "./ContextResolver";
46 | export { JsonLdDocumentTermInfo } from "./JsonLdDocumentTermInfo";
47 | export { JsonLdDocumentContext } from "./JsonLdDocumentContext";
48 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/src/cli.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { lint, processFile, isDirectory } from "./utilities";
15 |
16 | // tslint:disable: no-console no-var-requires
17 |
18 | const commander = require("commander");
19 | const packageJson = require("../package.json");
20 |
21 | const program = new commander.Command();
22 |
23 | const programBase = program
24 | .version(packageJson.version)
25 | .description("jsonld-lint");
26 |
27 | programBase
28 | .command("lint", { isDefault: true })
29 | .arguments("[fileOrDirectory]")
30 | .option("-r, --recursive", "recursive file search", false)
31 | .option(
32 | "-f, --fileExtensionFilter ",
33 | "file extension filter",
34 | ".jsonld"
35 | )
36 | .action(async (_: any, cmd?: any) => {
37 | if (!cmd?.args[0]) {
38 | programBase.help();
39 | process.exit(0);
40 | }
41 | if (await lint(cmd?.args[0], cmd.recursive, cmd.fileExtensionFilter)) {
42 | process.exit(1);
43 | }
44 | process.exit(0);
45 | });
46 |
47 | programBase
48 | .command("process")
49 | .arguments("[file]")
50 | .action(async (file?: string) => {
51 | if (!file) {
52 | programBase.help();
53 | process.exit(0);
54 | }
55 | if (isDirectory(file)) {
56 | console.log("Supplied parameter is a directory not a file");
57 | process.exit(0);
58 | }
59 | if (await processFile(file)) {
60 | process.exit(1);
61 | }
62 | process.exit(0);
63 | });
64 |
65 | programBase.parse(process.argv);
66 |
67 | if (!programBase.args.length) {
68 | programBase.help();
69 | }
70 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/utilities.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { promises } from "fs";
15 | import * as path from "path";
16 |
17 | export const getTestsFixtures = async (
18 | directory: string,
19 | filter: string
20 | ): Promise => {
21 | const directoryPath = path.join(process.env.PWD as string, directory);
22 | let stat = await promises.lstat(directoryPath);
23 | if (!stat.isDirectory()) {
24 | return [];
25 | }
26 | const files = await getFilesFromDirectory(directory, filter);
27 | return files
28 | .map((item) => item.substring(0, 4))
29 | .filter((value, index, self) => {
30 | return self.indexOf(value) === index;
31 | });
32 | };
33 |
34 | export const readFile = async (
35 | directory: string,
36 | file: string
37 | ): Promise => {
38 | const directoryPath = path.join(process.env.PWD as string, directory);
39 | const filePath = path.join(directoryPath, file);
40 | return (await promises.readFile(filePath)).toString();
41 | };
42 |
43 | export const getFilesFromDirectory = async (
44 | directory: string,
45 | filter: string
46 | ): Promise => {
47 | let matchedFiles: string[] = [];
48 | let files = await promises.readdir(directory);
49 | for (let i = 0; i < files.length; i++) {
50 | let filename = path.join(directory, files[i]);
51 | let stat = await promises.lstat(filename);
52 | if (stat.isDirectory()) {
53 | continue;
54 | } else if (
55 | filename.indexOf(filter) >= 0 &&
56 | !matchedFiles.includes(filename)
57 | ) {
58 | matchedFiles.push(files[i]);
59 | }
60 | }
61 | return matchedFiles;
62 | };
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/mattrglobal)
2 |
3 | # JSON-LD Lint
4 |
5 | 
6 | 
7 |
8 | This repository is home to a set of packages designed to [lint](<"https://en.wikipedia.org/wiki/Lint_(software)">) [JSON-LD](https://www.w3.org/TR/json-ld11/) documents.
9 |
10 | These include
11 |
12 | ### [JSON-LD Lint cli](./packages/jsonld-lint-cli/README.md)
13 |
14 | A CLI tool for linting/processing JSON-LD documents
15 |
16 |
17 |
18 | ### [JSON-LD Lint VS-Code extension](./packages/jsonld-lint-vscode/README.md)
19 |
20 | _Coming soon_
21 |
22 | An extension that brings the JSON-LD lint smarts to the popular IDE [VS-Code](https://code.visualstudio.com/)
23 |
24 |
25 |
26 | ### [JSON-LD Lint Core](./packages/jsonld-lint/README.md)
27 |
28 | The core linting and processing engine for JSON-LD documents
29 |
30 | ## Built with
31 |
32 | - [Typescript](https://www.typescriptlang.org/)
33 | - [Lerna](https://lerna.js.org/)
34 |
35 | ## Getting started as a Contributor
36 |
37 | ### Prerequisites
38 |
39 | - [Yarn](https://yarnpkg.com/)
40 |
41 | ### Installation
42 |
43 | With [Yarn](https://yarnpkg.com/) run:
44 |
45 | ```
46 | yarn install --frozen-lockfile
47 | yarn build
48 | ```
49 |
50 | ### Testing
51 |
52 | To run all tests across all packages run:
53 |
54 | ```
55 | yarn test
56 | ```
57 |
58 | ### Contributing
59 |
60 | Read our [contributing guide](./CONTRIBUTING.md) to learn about our development process.
61 |
62 | ## Release Process
63 |
64 | A description of the release process and how to create a release can be found [here](./docs/RELEASE.md).
65 |
66 | ---
67 |
68 |
Copyright © MATTR Limited. Some rights reserved. “MATTR” is a trademark of MATTR Limited, registered in New Zealand and other countries.
69 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/types/JsonLdDocumentSyntaxError.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { DocumentPosition } from "./DocumentPosition";
15 | import {
16 | BaseJsonLdDocumentProcessingResult,
17 | JsonLdDocumentProcessingResultType,
18 | } from "./JsonLdDocumentProcessingResult";
19 |
20 | /**
21 | * JSON-LD Document Syntax error type
22 | */
23 | export enum JsonLdDocumentSyntaxErrorRule {
24 | UnexpectedJsonLdKeywordValueType = "jsonld-lint/unexpected-json-value-type",
25 | UnexpectedJsonLdKeywordValue = "jsonld-lint/unexpected-json-value",
26 | UnexpectedUseOfJsonLdKeyword = "jsonld-lint/unexpected-use-of-jsonld-keyword",
27 | DuplicatePropertyInJsonObject = "jsonld-lint/duplicate-property-in-json-object",
28 | DuplicateAliasPropertyInJsonObject = "jsonld-lint/duplicate-property-in-json-object",
29 | InvalidJsonLdKeywordAsTermValue = "jsonld-lint/invalid-jsonld-keyword-as-term-value",
30 | EmptyJsonPropertyKey = "jsonld-lint/empty-json-property-key",
31 | }
32 |
33 | export interface JsonLdDocumentSyntaxError
34 | extends BaseJsonLdDocumentProcessingResult {
35 | /**
36 | * The processing result type for a JSON-LD syntax error
37 | */
38 | readonly type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError;
39 | /**
40 | * The JSON-LD syntax error type
41 | */
42 | readonly rule: JsonLdDocumentSyntaxErrorRule;
43 | /**
44 | * Positional information indicating the where the lint
45 | * result applies to
46 | */
47 | readonly documentPosition: DocumentPosition;
48 | /**
49 | * The message for the syntax error
50 | */
51 | readonly message: string;
52 | /**
53 | * Value of the JSON key or value the linting rule breach pertains to
54 | */
55 | readonly value?: any;
56 | }
57 |
--------------------------------------------------------------------------------
/docs/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Stable Releases
2 |
3 | To create a stable release follow the following steps
4 |
5 | 1. Checkout the head of master `git checkout master && git pull`
6 | 2. Create a new release branch from master called `release`
7 | 3. Install the dependencies `yarn install --frozen-lockfile`
8 | 4. Build the package `yarn build`
9 | 5. Test the package `yarn test`
10 | 6. Run `yarn version:release`, note by default this will do a minor package release as we are pre the `1.0.0` release
11 | 7. Observe the correctly incremented change to the `package.json` and the new entry in `CHANGELOG.md` along with the
12 | newly created commit
13 | 8. Push the release branch including the newly created tags `git push origin release --tags`
14 | 9. Open a pull request for the release, once approvals have been sought, merge the pull request using rebase,
15 | preserving the commit message as `chore(release): publish [skip ci]`
16 | 10. Observe the triggering of the `/.github/workflows/push-release.yaml`
17 |
18 | **Note** It is important that rebase is used as the strategy for merging a release pull request as this preserves the created release tag.
19 |
20 | The resulting release will publish the new package to NPM and the resulting binaries to github packages.
21 |
22 | # Unstable Releases
23 |
24 | An unstable release is triggered on every commit to master, where the `/.github/workflows/push-master.yaml` is run.
25 |
26 | The releases have the following version syntax
27 | `-unstable.`
28 |
29 | **Note** The `/.github/workflows/push-master.yaml` will skip if the commit message includes `[skip ci]`
30 |
31 | **Note** To skip the automatic release of a new unstable version append `[skip ci]` to the end of the commit message
32 | that is merged into master.
33 |
34 | # Unstable Releases
35 |
36 | An unstable release is triggered on every commit to master, where the `/.github/workflows/push-master.yaml` is run.
37 |
38 | The releases have the following version syntax
39 | `-unstable.`
40 |
41 | **Note** The `/.github/workflows/push-master.yaml` will skip if the commit message includes `[skip ci]`
42 |
43 | **Note** To skip the automatic release of a new unstable version append `[skip ci]` to the end of the commit message
44 | that is merged into master.
45 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/__tests__/__fixtures__/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | /**
15 | * An array of test cases
16 | */
17 | export const testCases = [
18 | {
19 | inputFileName: "0001-in.json",
20 | outputFileName: "0001-out.json",
21 | description: "detect un-mapped terms",
22 | },
23 | {
24 | inputFileName: "0002-in.json",
25 | outputFileName: "0002-out.json",
26 | description: "detect boolean value type for @context as syntax error",
27 | },
28 | {
29 | inputFileName: "0003-in.json",
30 | outputFileName: "0003-out.json",
31 | description: "detect numeric value type for @context as syntax error",
32 | },
33 | {
34 | inputFileName: "0004-in.json",
35 | outputFileName: "0004-out.json",
36 | description: "detect string value type for @version as syntax error",
37 | },
38 | {
39 | inputFileName: "0005-in.json",
40 | outputFileName: "0005-out.json",
41 | description: "detect boolean value type for @version as syntax error",
42 | },
43 | {
44 | inputFileName: "0006-in.json",
45 | outputFileName: "0006-out.json",
46 | description:
47 | "detect un-expected numeric value type for @version as syntax error",
48 | },
49 | {
50 | inputFileName: "0007-in.json",
51 | outputFileName: "0007-out.json",
52 | description:
53 | "detect property matching JSON-LD keyword syntax that is not a known keyword",
54 | },
55 | {
56 | inputFileName: "0008-in.json",
57 | outputFileName: "0008-out.json",
58 | description:
59 | "detect duplicate aliased properties in object as syntax error",
60 | },
61 | {
62 | inputFileName: "0009-in.json",
63 | outputFileName: "0009-out.json",
64 | description: "detect duplicate properties in object as syntax error",
65 | },
66 | {
67 | inputFileName: "0010-in.json",
68 | outputFileName: "0010-out.json",
69 | description: "detect term thats an empty string",
70 | },
71 | {
72 | inputFileName: "0011-in.json",
73 | outputFileName: "0011-out.json",
74 | description: "detect term with value of syntax token other than @type",
75 | },
76 | ];
77 |
--------------------------------------------------------------------------------
/docs/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We use several pieces of technology in this repository to streamline the release process whilst maintaining high code
4 | quality.
5 |
6 | ## Pre pull request checklist
7 |
8 | Below is a brief checklist prior to submitting or updating a pull request
9 |
10 | 1. Running `yarn pre-pr` passes.
11 | 2. Commit messages conform to the below conventions.
12 | 3. The pull request description fills in the relevant fields provided by the template.
13 |
14 | ## Commit messages
15 |
16 | A well formed commit message communicates context about a change. A diff will tell you what changed. A well cared for
17 | commit log is a beautiful and useful thing.
18 |
19 | What may be a hassle at first soon becomes habit, and eventually a source of pride and productivity for all
20 | involved. From reviews to maintenance it's a powerful tool. Understanding why something happened months or years ago
21 | becomes not only possible but efficient.
22 |
23 | We rely on consistent commit messages as we use
24 | [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) which automatically generates
25 | the changelog diff based on the commit messages
26 |
27 | We enforce well formed commit messages with pre-commit hooks using [husky](https://github.com/typicode/husky).
28 |
29 | The following guidelines are based on the angular
30 | team's [contribution guide](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
31 | Checkout [commitizen](https://www.npmjs.com/package/commitizen) and [commitlint.io](https://commitlint.io/) for
32 | assistance.
33 |
34 | ```
35 | ():
36 |
37 |
38 |
39 |
40 | ```
41 |
42 | ### Type
43 |
44 | Must be one of the following:
45 |
46 | - **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
47 | - **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
48 | - **docs**: Documentation only changes
49 | - **feat**: A new feature
50 | - **fix**: A bug fix
51 | - **perf**: A code change that improves performance
52 | - **refactor**: A code change that neither fixes a bug nor adds a feature
53 | - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
54 | - **test**: Adding missing tests or correcting existing tests
55 |
56 | ### Scope
57 |
58 | The scope should be the name of the module/package/area affected (as perceived by the person reading the commit
59 | message).
60 |
61 | ### Subject
62 |
63 | The subject contains a succinct description of the change.
64 |
65 | - use the imperative, present tense: "change" not "changed" nor "changes" (this convention matches up with commit
66 | messages generated by commands like git merge and git revert)
67 | - don't capitalise the first letter
68 | - no dot (.) at the end
69 |
70 | ### Body
71 |
72 | The body contains more detailed explanatory text, if necessary.
73 |
74 | - must have blank line between subject and body (unless you omit the body)
75 | - wrap at 72 chars
76 | - use the imperative, present tense: "change" not "changed" nor "changes" (this convention matches up with commit
77 | messages generated by commands like git merge and git revert)
78 | - should include the motivation for the change and contrast this with previous behaviour
79 | - paragraphs come after blank lines
80 | - use of markdown is encourage i.e. links, bullet points
81 |
82 | ### Footer
83 |
84 | The footer contains references to issues the commit closes or addresses.
85 |
--------------------------------------------------------------------------------
/docs/assets/mattr-logo-tm.svg:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # JSON-LD Lint
4 |
5 | 
6 | 
7 | 
8 | 
9 |
10 | This package contains the core JSON-LD lint engine written in [typescript](https://www.typescriptlang.org/) its primary dependencies are
11 |
12 | - [vscode-json-languageservice](https://github.com/Microsoft/vscode-json-languageservice) for JSON document parsing
13 | - [jsonld.js](https://github.com/digitalbazaar/jsonld.js/blob/master/lib/jsonld.js) for certain JSON-LD operations
14 |
15 | ## Syntax Errors
16 |
17 | The following defines the different types of syntax errors the processing engine detects, if a syntax error is encountered
18 | subsequent processing of the document terminates.
19 |
20 | ### Unexpected JSON-LD Keyword Value Type
21 |
22 | Rule - `jsonld-lint/unexpected-json-value-type`
23 |
24 | A result of this type will be returned when an unexpected value type for a JSON-LD keyword is encountered.
25 |
26 | Example - Invalid as the expected JSON value types for @context are string, array or object.
27 |
28 | ```json
29 | {
30 | "@context": false
31 | }
32 | ```
33 |
34 | ### Unexpected JSON-LD Keyword Value
35 |
36 | Rule - `jsonld-lint/unexpected-json-value`
37 |
38 | A result of this type will be returned when an unexpected value for a JSON-LD keyword is encountered.
39 |
40 | Example - Invalid as the expected values for @version are 1, 1.0 and 1.1.
41 |
42 | ```json
43 | {
44 | "@version": 25
45 | }
46 | ```
47 |
48 | ### Unexpected use of JSON-LD keyword
49 |
50 | Rule - `jsonld-lint/unexpected-use-of-jsonld-keyword`
51 |
52 | A result of this type will be returned when a JSON-LD keyword is used in an unexpected way.
53 |
54 | Example - Invalid as @base is not valid inside a node object only in a local context definition.
55 |
56 | ```json
57 | {
58 | "@base": "https://example.com"
59 | }
60 | ```
61 |
62 | ### Duplicate key in JSON object
63 |
64 | Rule - `jsonld-lint/duplicate-json-key`
65 |
66 | A result of this type will be return when an object/map within a JSON-LD document is encountered
67 | that features duplicate property keys, which is illegal in JSON-LD.
68 |
69 | Example - Invalid as the `test` property key is repeated.
70 |
71 | ```json
72 | {
73 | "test": true,
74 | "test": false
75 | }
76 | ```
77 |
78 | ### Duplicate aliased JSON-LD keyword
79 |
80 | Rule - `jsonld-lint/duplicate-alias-jsonld-keyword`
81 |
82 | A result of this type will be return when an object/map within a JSON-LD document
83 | has the aliased equivalent properties both featured in the same JSON object.
84 |
85 | Example - Invalid as `id` is an alias of the JSON-LD keyword `@id`.
86 |
87 | ```json
88 | {
89 | "id": "test-id",
90 | "@id": "test-id"
91 | }
92 | ```
93 |
94 | ### Invalid JSON-LD keyword as term value
95 |
96 | Rule - `jsonld-lint/invalid-jsonld-keyword-as-term-value`
97 |
98 | A result of this type will be returned when a JSON value type of string is encountered where
99 | the value matches a JSON-LD keyword being used in an invalid manner.
100 |
101 | Example - Invalid when a JSON property has a string value of `@context` because it is a JSON-LD keyword, `@type` is the only
102 | JSON-LD keyword allowed.
103 |
104 | ```json
105 | {
106 | "property": "@context"
107 | }
108 | ```
109 |
110 | ## Linting Rules
111 |
112 | The following defines the different types of linting results the processing engine detects.
113 |
114 | ### Unrecognized JSON-LD keyword
115 |
116 | Rule - `jsonld-lint/unrecognized-jsonld-keyword`
117 |
118 | JSON-LD keywords use the common pattern of featuring the `@` as a prefix, to ensure preservation of the namespace
119 | and allow future versions of JSON-LD to define new terms, developers are encourage to not feature JSON properties where
120 | the key is prefixed with an `@` symbol and it is not defined by JSON-LD.
121 |
122 | Example - The JSON key of `@this-is-a-test` matches the convention of being a JSON-LD term but is not a JSON-LD term.
123 |
124 | ```json
125 | {
126 | "@this-is-a-test": true
127 | }
128 | ```
129 |
130 | ### Un-mapped Term
131 |
132 | Rule - `jsonld-lint/unmapped-term`
133 |
134 | A result of this type will be returned when expansion of a term fails. This is usually due to the term
135 | not being documented in the documents context.
136 |
137 | Example - The term `undefinedTerm` is not defined in the documents context, hence will be reported as an
138 | un-mapped term.
139 |
140 | ```json
141 | {
142 | "@context": {
143 | "definedTerm": "https://example.com/definedTerm"
144 | },
145 | "definedTerm": "good",
146 | "undefinedTerm": "bad"
147 | }
148 | ```
149 |
150 | ### Empty JSON Property Key
151 |
152 | Rule - `jsonld-lint/empty-json-property-key`
153 |
154 | A result of this type will be returned when a JSON property key is encountered which is an empty string
155 |
156 | Example - The JSON object contains an empty string as the key for one of the JSON properties
157 |
158 | ```json
159 | {
160 | "@context": {},
161 | "": false
162 | }
163 | ```
164 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-cli/src/utilities.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import { promises, existsSync as fsExists, statSync } from "fs";
15 | import * as path from "path";
16 | import {
17 | JsonLdDocumentLintResult,
18 | JsonLdDocumentProcessingResultType,
19 | JsonLdDocumentProcessingResult,
20 | lint as jsonldLint,
21 | process as processDocument,
22 | JsonLdDocumentSyntaxError,
23 | } from "jsonld-lint";
24 |
25 | export const exists = (fileOrDirectoryPath: string): boolean => {
26 | return fsExists(fileOrDirectoryPath);
27 | };
28 |
29 | export const isDirectory = (fileOrDirectoryPath: string): boolean => {
30 | const result = statSync(fileOrDirectoryPath);
31 | return result.isDirectory();
32 | };
33 |
34 | export const processJsonLd = async (file: string): Promise => {
35 | try {
36 | if (!exists(file)) {
37 | throw new Error("File does not exist");
38 | }
39 |
40 | if (isDirectory(file)) {
41 | throw new Error("Supplied path is a directory, expected a file");
42 | }
43 |
44 | return await processFile(file);
45 | } catch (ex) {
46 | console.error("ERROR:", JSON.stringify(ex, null, 2), ex);
47 | process.exit(1);
48 | }
49 | };
50 |
51 | export const lint = async (
52 | fileOrDirectoryPath: string,
53 | recursiveFileSearch: boolean,
54 | fileExtensionFilter: string
55 | ): Promise => {
56 | try {
57 | console.log("JSON-LD Linter");
58 | if (!exists(fileOrDirectoryPath)) {
59 | throw new Error("File or directory does not exist");
60 | }
61 | if (fileExtensionFilter.charAt(0) !== ".") {
62 | throw new Error("File extension must begin with `.`");
63 | }
64 | if (isDirectory(fileOrDirectoryPath)) {
65 | return await lintDirectory(
66 | fileOrDirectoryPath,
67 | fileExtensionFilter,
68 | recursiveFileSearch
69 | );
70 | } else {
71 | if (recursiveFileSearch) {
72 | console.log(
73 | "WARN: ignoring recursive option, not valid when linting file"
74 | );
75 | }
76 | return await lintFile(fileOrDirectoryPath);
77 | }
78 | } catch (ex) {
79 | console.error("ERROR:", ex.message);
80 | process.exit(1);
81 | }
82 | };
83 |
84 | export const lintDirectory = async (
85 | directory: string,
86 | filter: string,
87 | recursive: boolean
88 | ): Promise => {
89 | const directoryPath = path.join(process.env.PWD as string, directory);
90 | console.log(
91 | `Linting directory: ${directoryPath} with file filter ${filter} ${
92 | recursive ? `recursively` : ``
93 | }`
94 | );
95 | const matchedFiles = await fileSearch(directory, filter, recursive);
96 | if (matchedFiles.length === 0) {
97 | console.log(`No files found for linting`);
98 | return true;
99 | }
100 |
101 | let result = false;
102 | for (let i = 0; i < matchedFiles.length; i++) {
103 | result = (await lintFile(matchedFiles[i])) || result;
104 | }
105 |
106 | return result;
107 | };
108 |
109 | export const processFile = async (file: string): Promise => {
110 | const filePath = path.join(process.env.PWD as string, file);
111 | const fileContents = (await promises.readFile(filePath)).toString();
112 | const results = await processDocument(fileContents);
113 | console.log(JSON.stringify(results, null, 2));
114 | return false;
115 | };
116 |
117 | export const lintFile = async (file: string): Promise => {
118 | const filePath = path.join(process.env.PWD as string, file);
119 | const fileContents = (await promises.readFile(filePath)).toString();
120 | const results = await jsonldLint(fileContents);
121 | if (results.length > 0) {
122 | formatResults(filePath, results);
123 | return true;
124 | } else {
125 | console.log(`SUCCESS: ${filePath}`);
126 | }
127 | return false;
128 | };
129 |
130 | const formatResults = (
131 | filePath: string,
132 | results: JsonLdDocumentProcessingResult[]
133 | ) => {
134 | results
135 | .filter(
136 | (item) =>
137 | item.type === JsonLdDocumentProcessingResultType.JsonLdSyntaxError
138 | )
139 | .forEach((result) => {
140 | formatJsonSyntaxError(filePath, result as JsonLdDocumentSyntaxError);
141 | });
142 |
143 | results
144 | .filter(
145 | (item) =>
146 | item.type === JsonLdDocumentProcessingResultType.JsonLdLintingResult
147 | )
148 | .forEach((result) => {
149 | formatLintResult(filePath, result as JsonLdDocumentLintResult);
150 | });
151 | };
152 |
153 | const formatLintResult = (
154 | filePath: string,
155 | result: JsonLdDocumentLintResult
156 | ) => {
157 | console.log(`ERROR: ${filePath} - ${result.message}`);
158 | };
159 |
160 | const formatJsonSyntaxError = (
161 | filePath: string,
162 | result: JsonLdDocumentSyntaxError
163 | ) => {
164 | console.log(`SYNTAX ERROR: ${filePath} - ${result.message}`);
165 | };
166 |
167 | const fileSearch = async (
168 | startPath: string,
169 | filter: string,
170 | recursive: boolean,
171 | matchedFiles: string[] = []
172 | ): Promise => {
173 | let files = await promises.readdir(startPath);
174 | for (let i = 0; i < files.length; i++) {
175 | let filename = path.join(startPath, files[i]);
176 | let stat = await promises.lstat(filename);
177 | if (stat.isDirectory() && recursive) {
178 | const results = await fileSearch(
179 | filename,
180 | filter,
181 | recursive,
182 | matchedFiles
183 | );
184 | results.forEach((item) => {
185 | if (!matchedFiles.includes(item)) {
186 | matchedFiles.push(item);
187 | }
188 | });
189 | } else if (
190 | filename.indexOf(filter) >= 0 &&
191 | !matchedFiles.includes(filename)
192 | ) {
193 | matchedFiles.push(filename);
194 | }
195 | }
196 | return matchedFiles;
197 | };
198 |
--------------------------------------------------------------------------------
/packages/jsonld-lint-vscode/src/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import * as vscode from "vscode";
15 |
16 | import {
17 | process,
18 | buildContextResolver,
19 | JsonLdLintErrorType,
20 | JsonLdDocumentTerm,
21 | JsonLdDocumentLintResult,
22 | JsonLdDocumentSyntaxError,
23 | JsonLdDocumentProcessingResultType,
24 | } from "jsonld-lint";
25 |
26 | /**
27 | * The max time processing a JSON-LD document can take
28 | */
29 | const PROCESSING_TIMEOUT_MS = 500;
30 | /**
31 | * When the extension is activated we build a context resolver that
32 | * has LRU cache that persists for the lifetime of the extension
33 | * which prevents reloading of JSON-LD document contexts
34 | */
35 | const contextResolver = buildContextResolver();
36 |
37 | /**
38 | * Method is called when vs code is activated
39 | */
40 | export function activate(context: vscode.ExtensionContext) {
41 | console.log("jsonld-lint extension is active");
42 |
43 | let timeout: NodeJS.Timer | undefined = undefined;
44 |
45 | // create a decorator type that we use to decorate small numbers
46 | const unmappedPropertyDecorationType =
47 | vscode.window.createTextEditorDecorationType({
48 | color: {
49 | id: "jsonldlint.JsonLdLintResultBackgroundColor",
50 | },
51 | });
52 |
53 | // create a decorator type that we use to decorate small numbers
54 | const termDecorationType = vscode.window.createTextEditorDecorationType({});
55 |
56 | let activeEditor = vscode.window.activeTextEditor;
57 |
58 | const updateDecorations = async (): Promise => {
59 | if (!activeEditor) {
60 | return;
61 | }
62 |
63 | try {
64 | const text = activeEditor.document.getText();
65 |
66 | let lintingDecorations: vscode.DecorationOptions[] = [];
67 | let termDecorations: vscode.DecorationOptions[] = [];
68 |
69 | const results = await process(text, { contextResolver });
70 | termDecorations = getTermDecorations(
71 | results.filter(
72 | (item) => item.type === JsonLdDocumentProcessingResultType.JsonLdTerm
73 | ) as JsonLdDocumentTerm[]
74 | );
75 | lintingDecorations.push(
76 | ...getLintingDecorations(
77 | results.filter(
78 | (item) =>
79 | item.type ===
80 | JsonLdDocumentProcessingResultType.JsonLdLintingResult
81 | ) as JsonLdDocumentLintResult[]
82 | )
83 | );
84 | lintingDecorations.push(
85 | ...getLintingDecorations(
86 | results.filter(
87 | (item) =>
88 | item.type === JsonLdDocumentProcessingResultType.JsonLdSyntaxError
89 | ) as JsonLdDocumentSyntaxError[]
90 | )
91 | );
92 |
93 | activeEditor.setDecorations(
94 | unmappedPropertyDecorationType,
95 | lintingDecorations
96 | );
97 | activeEditor.setDecorations(termDecorationType, termDecorations);
98 | } catch (ex) {
99 | // Unable to detect JSON-LD reset the decorations
100 | if (ex.type === JsonLdLintErrorType.JsonLdDetectionError) {
101 | activeEditor.setDecorations(unmappedPropertyDecorationType, []);
102 | activeEditor.setDecorations(termDecorationType, []);
103 | }
104 | return;
105 | }
106 | };
107 |
108 | const getTermDecorations = (
109 | terms: JsonLdDocumentTerm[]
110 | ): vscode.DecorationOptions[] => {
111 | let decorations: vscode.DecorationOptions[] = [];
112 | terms.forEach((item) => {
113 | const propertyStartPos = activeEditor?.document.positionAt(
114 | item.documentPosition.startPositionOffset
115 | );
116 | const propertyEndPos = activeEditor?.document.positionAt(
117 | item.documentPosition.endPositionOffset
118 | );
119 | let decoration: any = {
120 | range: new vscode.Range(
121 | propertyStartPos as vscode.Position,
122 | propertyEndPos as vscode.Position
123 | ),
124 | };
125 | if (item.isJsonLdKeyword) {
126 | decoration.hoverMessage = `JSON-LD Keyword see ${item.iri}`;
127 | } else {
128 | decoration.hoverMessage = `JSON-LD Term definition see ${item.iri}`;
129 | }
130 | decorations.push(decoration);
131 | });
132 | return decorations;
133 | };
134 |
135 | const getLintingDecorations = (
136 | lintingResults: JsonLdDocumentSyntaxError[] | JsonLdDocumentLintResult[]
137 | ): vscode.DecorationOptions[] => {
138 | let decorations: vscode.DecorationOptions[] = [];
139 | lintingResults.forEach((item) => {
140 | const propertyStartPos = activeEditor?.document.positionAt(
141 | item.documentPosition.startPositionOffset
142 | );
143 | const propertyEndPos = activeEditor?.document.positionAt(
144 | item.documentPosition.endPositionOffset
145 | );
146 | let decoration: any = {
147 | range: new vscode.Range(
148 | propertyStartPos as vscode.Position,
149 | propertyEndPos as vscode.Position
150 | ),
151 | };
152 |
153 | decoration.hoverMessage = item.message;
154 | decorations.push(decoration);
155 | });
156 | return decorations;
157 | };
158 |
159 | const triggerUpdateDecorations = async (): Promise => {
160 | if (timeout) {
161 | clearTimeout(timeout);
162 | timeout = undefined;
163 | }
164 | timeout = setTimeout(await updateDecorations, PROCESSING_TIMEOUT_MS);
165 | };
166 |
167 | if (activeEditor) {
168 | triggerUpdateDecorations();
169 | }
170 |
171 | vscode.window.onDidChangeActiveTextEditor(
172 | async (editor) => {
173 | activeEditor = editor;
174 | if (editor && editor.document.languageId === "json") {
175 | await triggerUpdateDecorations();
176 | }
177 | },
178 | null,
179 | context.subscriptions
180 | );
181 |
182 | vscode.workspace.onDidChangeTextDocument(
183 | async (event) => {
184 | if (
185 | activeEditor &&
186 | event.document === activeEditor.document &&
187 | activeEditor.document.languageId === "json"
188 | ) {
189 | await triggerUpdateDecorations();
190 | }
191 | },
192 | null,
193 | context.subscriptions
194 | );
195 | }
196 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2020 - MATTR Limited
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/jsonldDocumentProcessor.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | import * as jsonld from "jsonld";
15 | import * as context from "jsonld/lib/context";
16 | import JsonLDContextResolver from "jsonld/lib/ContextResolver";
17 | import LRUCache from "lru-cache";
18 |
19 | import {
20 | JsonLdDocumentTermInfo,
21 | KnownJsonLdTerm,
22 | JsonLdDocumentContext,
23 | JsonLdObjectType,
24 | ContextResolver,
25 | ValueValidator,
26 | } from "./types";
27 |
28 | /**
29 | * The keyword pattern for JSON-LD terms
30 | * taken from @here https://github.com/digitalbazaar/jsonld.js/blob/master/lib/context.js#L30
31 | */
32 | const KEYWORD_PATTERN = /^@[a-zA-Z]+$/;
33 |
34 | /**
35 | * Regular expression to test if a string is a valid absolute IRI or blank node IRI
36 | * taken from @see https://github.com/digitalbazaar/jsonld.js/blob/master/lib/url.js#L280
37 | */
38 | const ABSOLUTE_IRI_REGEX = /^([A-Za-z][A-Za-z0-9+-.]*|_):[^\s]*$/;
39 |
40 | /**
41 | * Checks whether an input string is a valid absolute IRI
42 | *
43 | * @param value String to test the absolute IRI regular expression against
44 | */
45 | export const isAbsoluteIri = (value: string) => ABSOLUTE_IRI_REGEX.test(value);
46 |
47 | /**
48 | * Indicates whether the given string matches the conventions required to be a valid as a JSON-LD keyword
49 | * e.g a string suffixed with a '@' symbol
50 | *
51 | * @param value value to check
52 | */
53 | export const isValidAsJsonLdKeyword = (value: string): boolean =>
54 | value.match(KEYWORD_PATTERN) !== null;
55 |
56 | /**
57 | * Checks whether the supplied value is a JSON-LD keyword
58 | *
59 | * @param value value to check
60 | */
61 | export const isJsonLdKeyword = (value: string) => jsonLdKeywords.has(value);
62 |
63 | /**
64 | * Checks whether the JSON-LD keyword is valid for the JSON-LD object
65 | *
66 | * @param value value to check
67 | * @param type type the JSON-LD keyword is valid in
68 | */
69 | export const isJsonLdKeywordAndValidInJsonLdObjectType = (
70 | value: string,
71 | type: JsonLdObjectType
72 | ) => jsonLdKeywords.get(value)?.validInJsonLdObjectTypes.includes(type);
73 |
74 | /**
75 | * A list of known JSON-LD keywords and what we know about them from a JSON-LD
76 | * syntax perspective
77 | *
78 | * @see https://www.w3.org/TR/json-ld11/#keywords
79 | */
80 | export const jsonLdKeywords = new Map([
81 | [
82 | "@base",
83 | {
84 | name: "@base",
85 | iri: "https://www.w3.org/TR/json-ld11/#base-iri",
86 | expectedJsonValueTypes: ["string"],
87 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
88 | },
89 | ],
90 | [
91 | "@container",
92 | {
93 | name: "@container",
94 | iri: "https://www.w3.org/TR/json-ld11/#keywords-and-keywords",
95 | expectedJsonValueTypes: ["string"],
96 | expectedJsonValues: ["@list", "@language", "@set", "@index", "@id"],
97 | validInJsonLdObjectTypes: [
98 | JsonLdObjectType.ExpandedTermDefinition,
99 | JsonLdObjectType.LocalContextDefinition,
100 | ],
101 | },
102 | ],
103 | [
104 | "@context",
105 | {
106 | name: "@context",
107 | iri: "https://www.w3.org/TR/json-ld11/#the-context",
108 | expectedJsonValueTypes: ["string", "array", "object"],
109 | validInJsonLdObjectTypes: [
110 | JsonLdObjectType.NodeObject,
111 | JsonLdObjectType.ExpandedTermDefinition,
112 | ],
113 | valueValidators: new Map([
114 | ["string", isAbsoluteIri],
115 | ]),
116 | },
117 | ],
118 | [
119 | "@direction",
120 | {
121 | name: "@direction",
122 | iri: "https://www.w3.org/TR/json-ld11/#base-direction",
123 | expectedJsonValueTypes: ["string"],
124 | expectedJsonValues: ["ltr", "rtl"],
125 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
126 | },
127 | ],
128 | [
129 | "@graph",
130 | {
131 | name: "@graph",
132 | iri: "https://www.w3.org/TR/json-ld11/#named-graphs",
133 | expectedJsonValueTypes: ["array", "object"],
134 | validInJsonLdObjectTypes: [
135 | JsonLdObjectType.NodeObject,
136 | JsonLdObjectType.LocalContextDefinition,
137 | ],
138 | },
139 | ],
140 | [
141 | "@id",
142 | {
143 | name: "@id",
144 | iri: "https://www.w3.org/TR/json-ld11/#node-identifiers",
145 | expectedJsonValueTypes: ["string"],
146 | aliasTerm: "id",
147 | validInJsonLdObjectTypes: [
148 | JsonLdObjectType.NodeObject,
149 | JsonLdObjectType.ExpandedTermDefinition,
150 | JsonLdObjectType.LocalContextDefinition,
151 | ],
152 | },
153 | ],
154 | [
155 | "id",
156 | {
157 | name: "@id",
158 | iri: "https://www.w3.org/TR/json-ld11/#node-identifiers",
159 | expectedJsonValueTypes: ["string"],
160 | aliasTerm: "@id",
161 | validInJsonLdObjectTypes: [
162 | JsonLdObjectType.NodeObject,
163 | JsonLdObjectType.ExpandedTermDefinition,
164 | JsonLdObjectType.LocalContextDefinition,
165 | ],
166 | },
167 | ],
168 | [
169 | "@import",
170 | {
171 | name: "@import",
172 | iri: "https://www.w3.org/TR/json-ld11/#imported-contexts",
173 | expectedJsonValueTypes: ["string"],
174 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
175 | },
176 | ],
177 | [
178 | "@included",
179 | {
180 | name: "@included",
181 | iri: "https://www.w3.org/TR/json-ld11/#included-blocks",
182 | expectedJsonValueTypes: ["object", "array"], // TODO check if string is actually valid
183 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
184 | },
185 | ],
186 | [
187 | "@index",
188 | {
189 | name: "@index",
190 | iri: "https://www.w3.org/TR/json-ld11/#property-based-data-indexing",
191 | expectedJsonValueTypes: ["string"],
192 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
193 | },
194 | ],
195 | [
196 | "@json",
197 | {
198 | name: "@json",
199 | iri: "https://www.w3.org/TR/json-ld11/#json-literals",
200 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
201 | },
202 | ],
203 | [
204 | "@language",
205 | {
206 | name: "@language",
207 | iri: "https://www.w3.org/TR/json-ld11/#string-internationalization",
208 | expectedJsonValueTypes: ["string"],
209 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
210 | },
211 | ],
212 | [
213 | "@list",
214 | {
215 | name: "@list",
216 | iri: "https://www.w3.org/TR/json-ld11/#lists",
217 | expectedJsonValueTypes: ["array"],
218 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
219 | },
220 | ],
221 | [
222 | "@nest",
223 | {
224 | name: "@nest",
225 | iri: "https://www.w3.org/TR/json-ld11/#nested-properties",
226 | expectedJsonValueTypes: ["string"],
227 | expectedJsonValues: ["labels"],
228 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
229 | },
230 | ],
231 | [
232 | "@none",
233 | {
234 | name: "@none",
235 | iri: "https://www.w3.org/TR/json-ld11/#keywords-and-keywords",
236 | expectedJsonValueTypes: ["array", "object", "string"],
237 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
238 | },
239 | ],
240 | [
241 | "@prefix",
242 | {
243 | name: "@prefix",
244 | iri: "https://www.w3.org/TR/json-ld11/#keywords-and-keywords",
245 | expectedJsonValueTypes: ["boolean"],
246 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
247 | },
248 | ],
249 | [
250 | "@propagate",
251 | {
252 | name: "@propagate",
253 | iri: "https://www.w3.org/TR/json-ld11/#keywords-and-keywords",
254 | expectedJsonValueTypes: ["boolean"],
255 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
256 | },
257 | ],
258 | [
259 | "@protected",
260 | {
261 | name: "@protected",
262 | iri: "https://www.w3.org/TR/json-ld11/#protected-term-definitions",
263 | expectedJsonValueTypes: ["boolean"],
264 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
265 | },
266 | ],
267 | [
268 | "@type",
269 | {
270 | name: "@type",
271 | iri: "https://www.w3.org/TR/json-ld11/#typed-values",
272 | expectedJsonValueTypes: ["string", "array"],
273 | aliasTerm: "type",
274 | validInJsonLdObjectTypes: [
275 | JsonLdObjectType.NodeObject,
276 | JsonLdObjectType.ExpandedTermDefinition,
277 | JsonLdObjectType.LocalContextDefinition,
278 | ],
279 | },
280 | ],
281 | [
282 | "type",
283 | {
284 | name: "@type",
285 | iri: "https://www.w3.org/TR/json-ld11/#typed-values",
286 | expectedJsonValueTypes: ["string", "array"],
287 | aliasTerm: "@type",
288 | validInJsonLdObjectTypes: [
289 | JsonLdObjectType.NodeObject,
290 | JsonLdObjectType.ExpandedTermDefinition,
291 | JsonLdObjectType.LocalContextDefinition,
292 | ],
293 | },
294 | ],
295 | [
296 | "@value",
297 | {
298 | name: "@value",
299 | iri: "https://www.w3.org/TR/json-ld11/#typed-values",
300 | expectedJsonValueTypes: ["string", "number", "boolean"],
301 | validInJsonLdObjectTypes: [JsonLdObjectType.ExpandedTermDefinition],
302 | },
303 | ],
304 | [
305 | "@version",
306 | {
307 | name: "@version",
308 | iri: "https://www.w3.org/TR/json-ld11/#json-ld-1-1-processing-mode",
309 | expectedJsonValueTypes: ["number"],
310 | expectedJsonValues: [1, 1.0, 1.1],
311 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
312 | },
313 | ],
314 | [
315 | "@vocab",
316 | {
317 | name: "@vocab",
318 | iri: "https://www.w3.org/TR/json-ld11/#default-vocabulary",
319 | expectedJsonValueTypes: ["string"],
320 | validInJsonLdObjectTypes: [JsonLdObjectType.LocalContextDefinition],
321 | },
322 | ],
323 | ]);
324 |
325 | /**
326 | * An enumeration of the valid JSON value types that a JSON-LD term
327 | * definition can be in a JSON-LD context
328 | */
329 | export const validJsonLdTermDefinitionJsonTypes = ["string", "object"];
330 |
331 | /**
332 | * Checks whether the supplied document is a compact JSON-LD document
333 | *
334 | * @param document document to check
335 | *
336 | * @returns {boolean} Indicating whether the document is a compact JSON-LD document
337 | */
338 | export const isCompactJsonLdDocument = (document: any): boolean =>
339 | document["@context"] !== undefined;
340 |
341 | /**
342 | * Expands a JSON-LD document and returns any un-mapped properties
343 | *
344 | * @param document JSON-LD document to expand
345 | *
346 | * @returns Expanded JSON-LD document
347 | */
348 | export const expand = async (document: any): Promise => {
349 | const unmappedTerms: string[] = [];
350 |
351 | // Whilst expanding the JSON-LD document catch any un-mapped properties
352 | const expansionMap = (info: any) => {
353 | if (
354 | info?.unmappedProperty &&
355 | !unmappedTerms.includes(info.unmappedProperty)
356 | ) {
357 | unmappedTerms.push(info.unmappedProperty);
358 | }
359 | };
360 |
361 | const expandedDocument = await jsonld.expand(document, { expansionMap });
362 |
363 | return {
364 | expandedDocument,
365 | unmappedTerms,
366 | };
367 | };
368 |
369 | // TODO type the response
370 | export const getDocumentContext = async (
371 | document: any,
372 | contextResolver: ContextResolver
373 | ): Promise => {
374 | if (!document["@context"]) {
375 | throw Error("Failed to find document context");
376 | }
377 |
378 | const initialContext = await jsonld.processContext(
379 | context.getInitialContext({}),
380 | document["@context"],
381 | { contextResolver }
382 | );
383 |
384 | let resultingContext = { ...initialContext };
385 | for (let key of initialContext.mappings.keys()) {
386 | const item = initialContext.mappings.get(key);
387 | if (item["@context"]) {
388 | resultingContext = await jsonld.processContext(
389 | resultingContext,
390 | item["@context"]
391 | );
392 | }
393 | }
394 | return resultingContext as JsonLdDocumentContext;
395 | };
396 |
397 | /**
398 | * Gets the information associated to a JSON-LD term
399 | *
400 | * @param documentContext documents context to extract the term definition from
401 | * @param term to fetch the context for
402 | *
403 | * @returns {JsonLdDocumentTermInfo} Result
404 | */
405 | export const getTermInfo = async (
406 | documentContext: any,
407 | term: string
408 | ): Promise => {
409 | let iri;
410 | let valueTypeIri;
411 | let _isJsonLdKeyword = false;
412 | if (isJsonLdKeyword(term)) {
413 | _isJsonLdKeyword = true;
414 | iri = jsonLdKeywords.get(term)?.iri;
415 | } else if (documentContext?.mappings && documentContext.mappings.has(term)) {
416 | const mappedTerm = documentContext.mappings.get(term);
417 | iri = mappedTerm["@id"];
418 | let valueType: string = mappedTerm["@type"];
419 | if (valueType && valueType !== "@id") {
420 | valueTypeIri = valueType;
421 | }
422 | } else if (documentContext?.mappings) {
423 | // todo convert this forEach loop
424 | await documentContext.mappings.forEach(async (item: any) => {
425 | if (item["@context"]) {
426 | const nestedContext = await jsonld.processContext(
427 | documentContext,
428 | item["@context"],
429 | {}
430 | );
431 | if (nestedContext.mappings && nestedContext.mappings.has(term)) {
432 | const mappedTerm = nestedContext.mappings.get(term);
433 | iri = mappedTerm["@id"];
434 | let valueType: string = mappedTerm["@type"];
435 | if (valueType && valueType !== "@id") {
436 | valueTypeIri = valueType;
437 | }
438 | }
439 | }
440 | });
441 | }
442 |
443 | return {
444 | name: term,
445 | iri,
446 | valueTypeIri,
447 | isJsonLdKeyword: _isJsonLdKeyword,
448 | };
449 | };
450 |
451 | /**
452 | * Builds a context resolver featuring a shared LRU based cache
453 | * @param sharedCache LRU based cache
454 | */
455 | export const buildContextResolver = (
456 | sharedCache?: LRUCache>
457 | ): ContextResolver => {
458 | if (!sharedCache) {
459 | sharedCache = new LRUCache();
460 | }
461 |
462 | return new JsonLDContextResolver({ sharedCache }) as ContextResolver;
463 | };
464 |
--------------------------------------------------------------------------------
/packages/jsonld-lint/src/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 - MATTR Limited
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | import {
14 | getLanguageService,
15 | TextDocument,
16 | ASTNode,
17 | PropertyASTNode,
18 | StringASTNode,
19 | ObjectASTNode,
20 | ArrayASTNode,
21 | JSONDocument,
22 | } from "vscode-json-languageservice";
23 | import {
24 | expand,
25 | getDocumentContext,
26 | getTermInfo,
27 | isCompactJsonLdDocument,
28 | validJsonLdTermDefinitionJsonTypes,
29 | isJsonLdKeyword,
30 | jsonLdKeywords,
31 | isJsonLdKeywordAndValidInJsonLdObjectType,
32 | isValidAsJsonLdKeyword,
33 | buildContextResolver,
34 | } from "./jsonldDocumentProcessor";
35 | import { createJsonLdLintError, documentOffSetToPosition } from "./utilities";
36 | import {
37 | ContextResolver,
38 | JsonLdDocumentProcessingResultType,
39 | JsonLdObjectType,
40 | JsonLdDocumentTerm,
41 | JsonLdDocumentProcessingResult,
42 | JsonLdLintErrorType,
43 | JsonLdDocumentLintRule,
44 | JsonLdLintOptions,
45 | JsonLdDocumentProcessingContext,
46 | JsonLdDocumentSyntaxErrorRule,
47 | ValueValidator,
48 | } from "./types";
49 |
50 | const service = getLanguageService({});
51 |
52 | export * from "./types";
53 |
54 | export { buildContextResolver };
55 |
56 | /**
57 | * VS Code language identifier for JSON
58 | */
59 | const JSON_LANGUAGE_ID = "json";
60 |
61 | /**
62 | * Sets the default linting options
63 | *
64 | * @param options Options to populate further default from
65 | */
66 | const setDefaultJsonLdLintOptions = (
67 | options?: JsonLdLintOptions
68 | ): Required => {
69 | let lintingRules = options?.lintingRules;
70 | if (!lintingRules) {
71 | lintingRules = [
72 | JsonLdDocumentLintRule.UnrecognizedJsonLdKeyword,
73 | JsonLdDocumentLintRule.UnmappedTerm,
74 | ];
75 | }
76 |
77 | let contextResolver = options?.contextResolver;
78 | if (!contextResolver) {
79 | contextResolver = buildContextResolver();
80 | }
81 |
82 | return {
83 | lintingRules,
84 | contextResolver,
85 | };
86 | };
87 |
88 | /**
89 | * Lints a JSON-LD document
90 | *
91 | * @param document A JSON-LD document to lint
92 | *
93 | * @returns Results of the linting
94 | */
95 | export const lint = async (
96 | document: string,
97 | options?: JsonLdLintOptions
98 | ): Promise =>
99 | (await process(document, options)).filter(
100 | (item) =>
101 | item.type === JsonLdDocumentProcessingResultType.JsonLdLintingResult ||
102 | item.type === JsonLdDocumentProcessingResultType.JsonLdSyntaxError
103 | );
104 |
105 | /**
106 | * Processes a JSON-LD document performing both linting
107 | * and extracting the understood terms and values
108 | *
109 | * @param document A JSON-LD document
110 | *
111 | * @returns Result of the processing
112 | */
113 | export const process = async (
114 | document: string,
115 | options?: JsonLdLintOptions
116 | ): Promise => {
117 | options = setDefaultJsonLdLintOptions(options);
118 |
119 | let parsedDocument;
120 | try {
121 | parsedDocument = JSON.parse(document);
122 | } catch (ex) {
123 | throw createJsonLdLintError(
124 | JsonLdLintErrorType.ParsingError,
125 | "Unable to parse input document as JSON",
126 | { input: document, rawError: ex }
127 | );
128 | }
129 |
130 | let rootNode: ObjectASTNode;
131 | try {
132 | // Parse the JSON Document with the vs-code json language service
133 | const doc = TextDocument.create("temp", JSON_LANGUAGE_ID, 1, document);
134 | const jsonDocument = service.parseJSONDocument(doc) as JSONDocument;
135 |
136 | rootNode = jsonDocument.root as ObjectASTNode;
137 | } catch (ex) {
138 | throw createJsonLdLintError(
139 | JsonLdLintErrorType.ParsingError,
140 | "An error occurred while processing the JSON document with vs-code language service",
141 | { input: document, rawError: ex }
142 | );
143 | }
144 |
145 | if (!rootNode || rootNode.type !== "object") {
146 | // TODO review this
147 | throw createJsonLdLintError(
148 | JsonLdLintErrorType.ParsingError,
149 | "Expected a JSON object at the root of the JSON-LD document",
150 | { input: document }
151 | );
152 | }
153 |
154 | if (!isCompactJsonLdDocument(parsedDocument)) {
155 | throw createJsonLdLintError(
156 | JsonLdLintErrorType.JsonLdDetectionError,
157 | "JSON Document not a valid JSON-LD document, no @context found",
158 | { input: document }
159 | );
160 | }
161 |
162 | try {
163 | const processingContext: JsonLdDocumentProcessingContext = {
164 | document: parsedDocument,
165 | contextResolver: options.contextResolver as ContextResolver,
166 | };
167 |
168 | return await processJsonObject(processingContext, rootNode);
169 | } catch (ex) {
170 | throw createJsonLdLintError(
171 | JsonLdLintErrorType.ParsingError,
172 | "An error occurred while processing the JSON-LD document",
173 | { input: document, rawError: ex }
174 | );
175 | }
176 | };
177 |
178 | /**
179 | * Processes a JSON value as a JSON object in the context of a JSON-LD document
180 | *
181 | */
182 | export const processJsonObject = async (
183 | processingContext: JsonLdDocumentProcessingContext,
184 | object: ObjectASTNode
185 | ): Promise => {
186 | const results: JsonLdDocumentProcessingResult[] = [];
187 |
188 | const jsonLdKeywordProperties = object.properties.filter(
189 | (_: PropertyASTNode) => isJsonLdKeyword(_.keyNode.value)
190 | );
191 | const nonJsonLdKeywordProperties = object.properties.filter(
192 | (_: PropertyASTNode) => !jsonLdKeywordProperties.includes(_)
193 | );
194 |
195 | const currentJsonLdObjectType = detectJsonLdObjectType(processingContext);
196 |
197 | // Process the JSON-LD syntax tokens first
198 | for (let i = 0; i < jsonLdKeywordProperties.length; i++) {
199 | results.push(
200 | ...(await processJsonProperty(
201 | processingContext,
202 | jsonLdKeywordProperties[i],
203 | object
204 | ))
205 | );
206 | }
207 |
208 | if (
209 | results.some(
210 | (item: JsonLdDocumentProcessingResult) =>
211 | item.type === JsonLdDocumentProcessingResultType.JsonLdSyntaxError
212 | )
213 | ) {
214 | return results;
215 | }
216 |
217 | let currentProcessingContext;
218 | if (!processingContext.jsonLdDocumentContext) {
219 | // TODO If we are in a context where an @type has been be sure to expand and get that complete context`
220 | try {
221 | const { unmappedTerms } = await expand(processingContext.document);
222 | const jsonLdDocumentContext = await getDocumentContext(
223 | processingContext.document,
224 | processingContext.contextResolver
225 | );
226 |
227 | currentProcessingContext = {
228 | ...processingContext,
229 | currentJsonLdObjectType,
230 | jsonLdDocumentContext,
231 | unmappedTerms,
232 | };
233 | } catch (ex) {
234 | return results;
235 | }
236 | } else {
237 | currentProcessingContext = {
238 | ...processingContext,
239 | currentJsonLdObjectType,
240 | };
241 | }
242 |
243 | // Then process the remaining properties in the object
244 | for (let i = 0; i < nonJsonLdKeywordProperties.length; i++) {
245 | results.push(
246 | ...(await processJsonProperty(
247 | currentProcessingContext,
248 | nonJsonLdKeywordProperties[i],
249 | object
250 | ))
251 | );
252 | }
253 |
254 | return results;
255 | };
256 |
257 | /**
258 | * Detects the type of the supplied JSON object in the context of JSON-LD grammar
259 | * @see https://www.w3.org/TR/json-ld11/#json-ld-grammar
260 | *
261 | * @param processingContext current processing context
262 | * @param object the object we are detecting the JsonLdObjectType of
263 | */
264 | export const detectJsonLdObjectType = (
265 | processingContext: JsonLdDocumentProcessingContext
266 | ): JsonLdObjectType => {
267 | // TODO there are other types of valid JSON-LD objects too
268 | if (processingContext.currentTerm?.name) {
269 | if (processingContext.currentTerm.name === "@context") {
270 | return JsonLdObjectType.LocalContextDefinition;
271 | }
272 | if (processingContext.currentTerm.name === "@graph") {
273 | return JsonLdObjectType.GraphObject;
274 | }
275 | if (
276 | processingContext.currentJsonLdObjectType ===
277 | JsonLdObjectType.LocalContextDefinition &&
278 | !isJsonLdKeyword(processingContext.currentTerm.name)
279 | ) {
280 | return JsonLdObjectType.ExpandedTermDefinition;
281 | }
282 | }
283 | return JsonLdObjectType.NodeObject;
284 | };
285 |
286 | /**
287 | * Processes a JSON property from a JSON object in the context of a JSON-LD document
288 | *
289 | */
290 | export const processJsonProperty = async (
291 | processingContext: JsonLdDocumentProcessingContext,
292 | property: PropertyASTNode,
293 | object: ObjectASTNode
294 | ): Promise => {
295 | const results: JsonLdDocumentProcessingResult[] = [];
296 |
297 | results.push(
298 | ...(await processJsonPropertyKey(
299 | processingContext,
300 | property.keyNode as StringASTNode,
301 | object
302 | ))
303 | );
304 |
305 | // Update the current processing context before processing the JSON value
306 | let currentProcessingContext: JsonLdDocumentProcessingContext = {
307 | ...processingContext,
308 | currentTerm: results.find(
309 | (item) => item.type === JsonLdDocumentProcessingResultType.JsonLdTerm
310 | ) as JsonLdDocumentTerm,
311 | };
312 |
313 | // Process the JSON value
314 | if (property.valueNode) {
315 | results.push(
316 | ...(await processJsonValue(currentProcessingContext, property.valueNode))
317 | );
318 | }
319 |
320 | return results;
321 | };
322 |
323 | /**
324 | * Processes a JSON value for its corresponding JSON key in the context of a JSON-LD document
325 | *
326 | */
327 | export const processJsonValue = async (
328 | processingContext: JsonLdDocumentProcessingContext,
329 | value: ASTNode
330 | ): Promise => {
331 | // If we could not understand the current term then
332 | // don't bother processing its value and return
333 | if (!processingContext.currentTerm) {
334 | return [];
335 | }
336 |
337 | if (isJsonLdKeyword(processingContext.currentTerm.name)) {
338 | const termInformation = jsonLdKeywords.get(
339 | processingContext.currentTerm.name
340 | );
341 | if (
342 | termInformation?.expectedJsonValueTypes &&
343 | !termInformation.expectedJsonValueTypes.includes(value.type)
344 | ) {
345 | return [
346 | {
347 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
348 | rule: JsonLdDocumentSyntaxErrorRule.UnexpectedJsonLdKeywordValueType,
349 | message: `Value type for the JSON-LD keyword "${
350 | processingContext.currentTerm.name
351 | }" of "${value.type}" \
352 | is invalid, ${
353 | termInformation.expectedJsonValueTypes.length > 1
354 | ? "expected one of type: " +
355 | termInformation.expectedJsonValueTypes
356 | : "expected \
357 | type: " + termInformation.expectedJsonValueTypes
358 | }`,
359 | documentPosition: documentOffSetToPosition(
360 | value.offset,
361 | value.length
362 | ),
363 | value: processingContext.currentTerm.name,
364 | },
365 | ];
366 | }
367 | }
368 |
369 | // If the value we are processing is that of a key in a JSON-LD
370 | // context definition and its not a JSON-LD syntax token, then by process of elimination
371 | // it is a JSON-LD term definition and JSON-LD term definitions can only feature certain members
372 | // @see https://www.w3.org/TR/json-ld11/#context-definitions for more information
373 | if (
374 | processingContext?.currentJsonLdObjectType ===
375 | JsonLdObjectType.LocalContextDefinition &&
376 | !isJsonLdKeyword(processingContext.currentTerm.name) &&
377 | !isValidAsJsonLdKeyword(processingContext.currentTerm.name) &&
378 | !validJsonLdTermDefinitionJsonTypes.includes(value.type)
379 | ) {
380 | return [
381 | {
382 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
383 | rule: JsonLdDocumentSyntaxErrorRule.UnexpectedJsonLdKeywordValueType,
384 | message: `Value type for the JSON-LD term definition for term "${processingContext.currentTerm.name}" of \
385 | "${value.type}" is invalid, expected one of: ${validJsonLdTermDefinitionJsonTypes}`,
386 | documentPosition: documentOffSetToPosition(value.offset, value.length),
387 | value: processingContext.currentTerm.name,
388 | },
389 | ];
390 | }
391 |
392 | switch (value.type) {
393 | case "object": {
394 | return [
395 | ...(await processJsonObject(processingContext, value as ObjectASTNode)),
396 | ];
397 | }
398 | case "array": {
399 | return [
400 | ...(await processJsonArrayValue(
401 | processingContext,
402 | value as ArrayASTNode
403 | )),
404 | ];
405 | }
406 | default: {
407 | // All other JSON value types e.g boolean & number & string
408 | if (isJsonLdKeyword(processingContext.currentTerm.name)) {
409 | const termInformation = jsonLdKeywords.get(
410 | processingContext.currentTerm.name
411 | );
412 | if (
413 | termInformation?.expectedJsonValues &&
414 | !termInformation.expectedJsonValues.includes(value.value)
415 | ) {
416 | return [
417 | {
418 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
419 | rule: JsonLdDocumentSyntaxErrorRule.UnexpectedJsonLdKeywordValue,
420 | message: `Value for the JSON-LD keyword "${processingContext.currentTerm.name}" of \
421 | "${value.value}" is invalid, expected one of: ${termInformation.expectedJsonValues}`,
422 | value: processingContext.currentTerm.name,
423 | documentPosition: documentOffSetToPosition(
424 | value.offset,
425 | value.length
426 | ),
427 | },
428 | ];
429 | }
430 |
431 | if (
432 | termInformation?.valueValidators &&
433 | termInformation.valueValidators.has(value.type)
434 | ) {
435 | const valueValidator = termInformation.valueValidators.get(
436 | value.type
437 | ) as ValueValidator;
438 | if (!valueValidator(value.value)) {
439 | return [
440 | {
441 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
442 | rule: JsonLdDocumentSyntaxErrorRule.UnexpectedJsonLdKeywordValue,
443 | message: `Value for the JSON-LD syntax token "${processingContext.currentTerm.name}" of \
444 | "${value.value}" is invalid`,
445 | value: processingContext.currentTerm.name,
446 | documentPosition: documentOffSetToPosition(
447 | value.offset,
448 | value.length
449 | ),
450 | },
451 | ];
452 | }
453 | }
454 | }
455 |
456 | // TODO do other processing on the JSON value here later
457 | return [];
458 | }
459 | }
460 | };
461 |
462 | /**
463 | * Processes a JSON properties value as a string
464 | *
465 | */
466 | export const processJsonArrayValue = async (
467 | processingContext: JsonLdDocumentProcessingContext,
468 | value: ArrayASTNode
469 | ): Promise => {
470 | const results: JsonLdDocumentProcessingResult[] = [];
471 |
472 | for (let i = 0; i < value.children.length; i++) {
473 | results.push(
474 | ...(await processJsonValue(processingContext, value.children[i]))
475 | );
476 | }
477 |
478 | return results;
479 | };
480 |
481 | /**
482 | * Processes a JSON properties key as JSON-LD term
483 | *
484 | */
485 | export const processJsonPropertyKey = async (
486 | processingContext: JsonLdDocumentProcessingContext,
487 | key: StringASTNode,
488 | object: ObjectASTNode
489 | ): Promise => {
490 | if (key.value === "") {
491 | return [
492 | {
493 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
494 | rule: JsonLdDocumentSyntaxErrorRule.EmptyJsonPropertyKey,
495 | message: `Empty JSON property encountered`,
496 | documentPosition: documentOffSetToPosition(key.offset, key.length),
497 | },
498 | ];
499 | }
500 | if (isDuplicatePropertyInObject(object, key.value)) {
501 | return [
502 | {
503 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
504 | rule: JsonLdDocumentSyntaxErrorRule.DuplicatePropertyInJsonObject,
505 | message: `Duplicate property of "${key.value}" encountered`,
506 | value: key.value,
507 | documentPosition: documentOffSetToPosition(key.offset, key.length),
508 | },
509 | ];
510 | }
511 |
512 | if (
513 | isJsonLdKeyword(key.value) &&
514 | isDuplicateAliasedPropertyInObject(object, key.value)
515 | ) {
516 | return [
517 | {
518 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
519 | rule: JsonLdDocumentSyntaxErrorRule.DuplicateAliasPropertyInJsonObject,
520 | message: `Duplicate aliased property of JSON-LD term of "${key.value}" encountered`,
521 | value: key.value,
522 | documentPosition: documentOffSetToPosition(key.offset, key.length),
523 | },
524 | ];
525 | }
526 |
527 | if (isJsonLdKeyword(key.value)) {
528 | if (
529 | processingContext.currentJsonLdObjectType &&
530 | !isJsonLdKeywordAndValidInJsonLdObjectType(
531 | key.value,
532 | processingContext.currentJsonLdObjectType
533 | )
534 | ) {
535 | return [
536 | {
537 | type: JsonLdDocumentProcessingResultType.JsonLdSyntaxError,
538 | rule: JsonLdDocumentSyntaxErrorRule.UnexpectedUseOfJsonLdKeyword,
539 | message: `Usage of JSON-LD syntax token "${key.value}" in the JSON-LD \
540 | object type of "${processingContext.currentJsonLdObjectType}" is invalid`,
541 | value: key.value,
542 | documentPosition: documentOffSetToPosition(key.offset, key.length),
543 | },
544 | ];
545 | }
546 | return [
547 | {
548 | type: JsonLdDocumentProcessingResultType.JsonLdTerm,
549 | name: key.value,
550 | iri: jsonLdKeywords.get(key.value)?.iri,
551 | isJsonLdKeyword: true,
552 | documentPosition: documentOffSetToPosition(key.offset, key.length),
553 | },
554 | ];
555 | }
556 |
557 | if (isValidAsJsonLdKeyword(key.value)) {
558 | return [
559 | {
560 | type: JsonLdDocumentProcessingResultType.JsonLdLintingResult,
561 | rule: JsonLdDocumentLintRule.UnrecognizedJsonLdKeyword,
562 | message: `The term "${key.value}" matches the convention of a JSON-LD syntax token but is un-recognized`,
563 | value: key.value,
564 | documentPosition: documentOffSetToPosition(key.offset, key.length),
565 | },
566 | {
567 | type: JsonLdDocumentProcessingResultType.JsonLdTerm,
568 | name: key.value,
569 | isJsonLdKeyword: false,
570 | documentPosition: documentOffSetToPosition(key.offset, key.length),
571 | },
572 | ];
573 | }
574 |
575 | // Check if we are in the
576 | // process of processing a JSON-LD context
577 | // if so check somethings that are unique to it
578 | if (
579 | processingContext.currentJsonLdObjectType ===
580 | JsonLdObjectType.LocalContextDefinition
581 | ) {
582 | // if (!termInformation.expectedJsonValueTypes.includes(value.type))
583 | return [];
584 | } else if (
585 | processingContext.unmappedTerms &&
586 | processingContext.unmappedTerms.includes(key.value)
587 | ) {
588 | return [
589 | {
590 | type: JsonLdDocumentProcessingResultType.JsonLdLintingResult,
591 | rule: JsonLdDocumentLintRule.UnmappedTerm,
592 | message: `The term "${key.value}" is not defined in the document context (unmapped)`,
593 | value: key.value,
594 | documentPosition: documentOffSetToPosition(key.offset, key.length),
595 | },
596 | ];
597 | } else {
598 | const termInfo = await getTermInfo(
599 | processingContext.jsonLdDocumentContext,
600 | key.value
601 | );
602 | return [
603 | {
604 | type: JsonLdDocumentProcessingResultType.JsonLdTerm,
605 | name: termInfo.name,
606 | isJsonLdKeyword: false,
607 | iri: termInfo.iri,
608 | valueTypeIri: termInfo.valueTypeIri,
609 | documentPosition: documentOffSetToPosition(key.offset, key.length),
610 | },
611 | ];
612 | }
613 | };
614 |
615 | /**
616 | * Checks whether the object contains a duplicate of the supplied property which is
617 | * illegal in all instances of JSON objects in JSON-LD syntax
618 | *
619 | * @param object object to check from
620 | * @param key string key to check if a duplicate exists
621 | */
622 | export const isDuplicatePropertyInObject = (
623 | object: ObjectASTNode,
624 | key: string
625 | ): boolean => {
626 | return (
627 | object.properties.filter(
628 | (item: PropertyASTNode) => key === item.keyNode.value
629 | ).length > 1
630 | );
631 | };
632 |
633 | /**
634 | * Checks whether an object contains duplicate alias properties
635 | *
636 | * Example - If an object contains both an `@id` and `id` property
637 | *
638 | * @param object object to check from
639 | * @param key string key to check if the duplicate aliased property exists
640 | */
641 | export const isDuplicateAliasedPropertyInObject = (
642 | object: ObjectASTNode,
643 | key: string
644 | ): boolean => {
645 | const keyword = jsonLdKeywords.get(key);
646 | if (!keyword) {
647 | return true;
648 | }
649 | return (
650 | object.properties.filter(
651 | (item: PropertyASTNode) => keyword.aliasTerm === item.keyNode.value
652 | ).length > 0
653 | );
654 | };
655 |
--------------------------------------------------------------------------------