├── .cpd.yml ├── .editorconfig ├── .github └── workflows │ └── integration.yml ├── .gitignore ├── license ├── package-lock.json ├── package.json ├── readme.md ├── renovate.json ├── src ├── factory.ts ├── helpers │ ├── agentSchema.ts │ ├── getUsedIfis.ts │ ├── objectTypeFactory.ts │ ├── restrictToValue.ts │ ├── statementRules.ts │ └── statementSchema.ts ├── index.test.ts ├── index.ts ├── maps.ts ├── regexValues │ ├── duration.ts │ ├── imt.ts │ ├── interactionType.ts │ ├── iri.ts │ ├── language.ts │ ├── mailto.ts │ ├── sha1.ts │ ├── timestamp.ts │ ├── uuid.ts │ └── version.ts ├── schemaRules │ ├── account.ts │ ├── activity.ts │ ├── actor.ts │ ├── agent.ts │ ├── attachment.ts │ ├── authority.ts │ ├── context.ts │ ├── definition.ts │ ├── group.ts │ ├── groupAuthority.ts │ ├── interactionComponent.ts │ ├── object.ts │ ├── result.ts │ ├── statement.ts │ ├── statementRef.ts │ ├── subStatement.ts │ └── verb.ts ├── tests │ ├── describeIfiProp.ts │ ├── describeInteractionProp.ts │ ├── describeMemberProp.ts │ ├── describeOptionalProp.ts │ ├── describeProp.ts │ ├── describeRequiredProp.ts │ ├── factory.ts │ ├── helpers │ │ ├── .DS_Store │ │ ├── agentSchema.ts │ │ ├── collection.ts │ │ ├── object.ts │ │ ├── objectTypeFactory.ts │ │ ├── statementRules.ts │ │ ├── statementSchema.ts │ │ ├── test.ts │ │ └── validStatementData.ts │ ├── itsInvalid.ts │ ├── itsValid.ts │ ├── maps │ │ ├── extensions.ts │ │ └── languageMap.ts │ ├── regexValues │ │ ├── duration.ts │ │ ├── imt.ts │ │ ├── interactionType.ts │ │ ├── iri.ts │ │ ├── language.ts │ │ ├── mailto.ts │ │ ├── sha1.ts │ │ ├── timestamp.ts │ │ ├── uuid.ts │ │ └── version.ts │ ├── schemaRules │ │ ├── account.ts │ │ ├── activity.ts │ │ ├── actor.ts │ │ ├── agent.ts │ │ ├── attachment.ts │ │ ├── authority.ts │ │ ├── context.ts │ │ ├── contextActivities.ts │ │ ├── definition.ts │ │ ├── group.ts │ │ ├── interactionComponent.ts │ │ ├── object.ts │ │ ├── result.ts │ │ ├── score.ts │ │ ├── statement.ts │ │ ├── statementRef.ts │ │ ├── subGroup.ts │ │ ├── subStatement.ts │ │ ├── subStatementObject.ts │ │ └── verb.ts │ └── values │ │ ├── boolean.ts │ │ ├── integer.ts │ │ ├── number.ts │ │ ├── scaled.ts │ │ └── string.ts ├── values.ts └── warnings │ ├── ContextPropWarning.ts │ ├── IfiCountWarning.ts │ ├── InvalidComponentsWarning.ts │ ├── MembersLengthWarning.ts │ ├── MembersTypeWarning.ts │ ├── MinMoreThanMaxWarning.ts │ ├── MissingInteractionTypeWarning.ts │ ├── NoIfiWarning.ts │ ├── NoMembersWarning.ts │ ├── ObjectTypeWarning.ts │ ├── RawLessThanMinWarning.ts │ ├── RawMoreThanMaxWarning.ts │ ├── RestrictedValueWarning.ts │ ├── SignedContentTypeWarning.ts │ ├── SubStatementWarning.ts │ ├── TypeWarning.ts │ └── VoidWarning.ts ├── tsconfig.json └── tslint.json /.cpd.yml: -------------------------------------------------------------------------------- 1 | languages: typescript 2 | files: src/**/* 3 | min-lines: 3 4 | min-tokens: 38 5 | debug: false 6 | skip-comments: true 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: Integration Suite 2 | 3 | on: ['push'] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} 8 | 9 | jobs: 10 | integrate: 11 | name: Integration 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 15 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: "16" 21 | cache: 'npm' 22 | 23 | - name: Installing Dependencies 24 | run: npm ci 25 | 26 | - name: Compiling Code 27 | run: npm run build 28 | 29 | - name: Running Tests 30 | run: npm run cover 31 | 32 | - name: Linting Code 33 | run: npm run lint 34 | 35 | - name: Checking for Duplication 36 | run: npm run duplication 37 | 38 | - name: Semantic Release 39 | if: github.ref == 'refs/heads/master' 40 | run: npm run semantic-release 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }} 43 | NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_STORE 3 | /.nyc_output 4 | /coverage 5 | /dist 6 | /node_modules 7 | /npm-debug.log 8 | /typings 9 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Learning Pool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@learninglocker/xapi-validation", 3 | "version": "0.0.0-development", 4 | "description": "Validation library for the xAPI.", 5 | "main": "dist/index.js", 6 | "typings": "dist/index.d.ts", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/LearningLocker/xapi-validation.git" 11 | }, 12 | "files": [ 13 | "dist", 14 | ".env.example", 15 | "package-lock.json" 16 | ], 17 | "scripts": { 18 | "acp": "git add -A && npm run commit && git push", 19 | "commit": "git-cz", 20 | "build": "tsc", 21 | "test": "mocha dist/**/*.test.js --exit", 22 | "cover": "nyc --lines 100 --check-coverage npm run test", 23 | "clean": "rimraf dist", 24 | "lint": "tslint --project ./tsconfig.json -c ./tslint.json", 25 | "duplication": "jscpd --limit 1.0", 26 | "semantic-release": "ht2-release-public-circleci-lib" 27 | }, 28 | "config": { 29 | "commitizen": { 30 | "path": "cz-conventional-changelog" 31 | } 32 | }, 33 | "engines": { 34 | "node": ">16.0.0", 35 | "npm": ">8.0.0" 36 | }, 37 | "dependencies": { 38 | "lodash": "^4.17.10", 39 | "rulr": "^4.0.1" 40 | }, 41 | "devDependencies": { 42 | "@ht2-labs/semantic-release": "2.0.98", 43 | "@types/lodash": "4.14.178", 44 | "@types/mocha": "2.2.48", 45 | "@types/node": "9.6.61", 46 | "@types/source-map-support": "0.5.4", 47 | "assert": "1.5.0", 48 | "commitizen": "2.10.1", 49 | "cz-conventional-changelog": "2.1.0", 50 | "jscpd": "0.6.25", 51 | "mocha": "4.1.0", 52 | "nyc": "11.9.0", 53 | "rimraf": "2.7.1", 54 | "source-map-support": "0.5.21", 55 | "tslint": "5.20.1", 56 | "typescript": "3.9.10" 57 | }, 58 | "publishConfig": { 59 | "access": "public" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # xapi-validation 2 | 3 | ![Build Status](https://github.com/LearningLocker/xapi-validation/actions/workflows/integration.yml/badge.svg?branch=master) 4 | [![Renovate badge](https://img.shields.io/badge/Renovate-enabled-brightgreen.svg)](https://renovateapp.com/) 5 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 6 | [![Join the chat at https://gitter.im/LearningLocker/learninglocker](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/LearningLocker/learninglocker?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | 8 | 9 | This is Learning Locker's package for validating xAPI Statements. The package aims to return all of the problems with an xAPI statement in one function call. Since this package is part of Learning Locker, it has been conformance tested. You can [try this package out on RunKit](https://runkit.com/58834fa5d14b5b0013806bde/5883507a9faa130014213d6a). 10 | 11 | *Learning Locker is a trademark of [HT2 Inc.](http://ht2labs.com)* 12 | 13 | ### Installation 14 | To install all of Learning Locker, see the [installation documentation](http://docs.learninglocker.net/guides-installing/). To install just the xAPI validation package, you can follow the instructions below. 15 | 16 | ```js 17 | npm i xapi-validation 18 | ``` 19 | 20 | ### Development 21 | 1. Download the code by either: 22 | - Cloning the repository (authorised collaborators only) `git clone git@github.com:LearningLocker/xapi-validation.git`. 23 | - [Forking the repository](https://help.github.com/articles/fork-a-repo/) and cloning the fork. 24 | 1. Change to the directory of the cloned code `cd xapi-validation`. 25 | 1. Install dependencies `npm install`. 26 | 1. Make your changes to the "src" directory. 27 | 1. Build the code `npm run build`. 28 | 1. Test the code `npm test`. 29 | 1. Commit and push your changes `npm run acp`. 30 | 1. [Create a pull request](https://help.github.com/articles/about-pull-requests/). 31 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [":library"], 3 | "automerge": true, 4 | "automergeType": "branch-push", 5 | "major": { 6 | "automerge": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/factory.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from 'rulr'; 2 | import * as values from './values'; 3 | 4 | const requireFile = (file: string) => 5 | (ruleAccessor: ((mod: any) => any)): Rule => 6 | (data, path) => 7 | ruleAccessor(require(file))(data, path); 8 | 9 | const requireMap = requireFile('./maps'); 10 | const requireRule = (file: string) => requireFile(file)((mod: any) => mod.default); 11 | 12 | export const anyValue = values.anyValue; 13 | export const account = requireRule('./schemaRules/account'); 14 | export const activity = requireRule('./schemaRules/activity'); 15 | export const actor = requireRule('./schemaRules/actor'); 16 | export const agent = requireRule('./schemaRules/agent'); 17 | export const attachment = requireRule('./schemaRules/attachment'); 18 | export const authority = requireRule('./schemaRules/authority'); 19 | export const booleanValue = values.booleanValue; 20 | export const context = requireRule('./schemaRules/context'); 21 | export const definition = requireRule('./schemaRules/definition'); 22 | export const duration = requireRule('./regexValues/duration'); 23 | export const extensions = requireMap(maps => maps.extensions); 24 | export const group = requireRule('./schemaRules/group'); 25 | export const groupAuthority = requireRule('./schemaRules/groupAuthority'); 26 | export const imt = requireRule('./regexValues/imt'); 27 | export const integerValue = values.integerValue; 28 | export const interactionComponent = requireRule('./schemaRules/interactionComponent'); 29 | export const interactionType = requireRule('./regexValues/interactionType'); 30 | export const iri = requireRule('./regexValues/iri'); 31 | export const language = requireRule('./regexValues/language'); 32 | export const languageMap = requireMap(maps => maps.languageMap); 33 | export const mailto = requireRule('./regexValues/mailto'); 34 | export const numberValue = values.numberValue; 35 | export const object = requireRule('./schemaRules/object'); 36 | export const result = requireRule('./schemaRules/result'); 37 | export const scaledValue = values.scaledValue; 38 | export const sha1 = requireRule('./regexValues/sha1'); 39 | export const statement = requireRule('./schemaRules/statement'); 40 | export const statementRef = requireRule('./schemaRules/statementRef'); 41 | export const stringValue = values.stringValue; 42 | export const subStatement = requireRule('./schemaRules/subStatement'); 43 | export const timestamp = requireRule('./regexValues/timestamp'); 44 | export const uuid = requireRule('./regexValues/uuid'); 45 | export const verb = requireRule('./schemaRules/verb'); 46 | export const version = requireRule('./regexValues/version'); 47 | -------------------------------------------------------------------------------- /src/helpers/agentSchema.ts: -------------------------------------------------------------------------------- 1 | import { optional, Rule } from 'rulr'; 2 | import { stringValue, mailto, sha1, iri, account } from '../factory'; 3 | import restrictToValue from './restrictToValue'; 4 | 5 | export default { 6 | objectType: optional(restrictToValue('Agent')) as Rule, 7 | name: optional(stringValue), 8 | mbox: optional(mailto), 9 | mbox_sha1sum: optional(sha1), 10 | openid: optional(iri), 11 | account: optional(account), 12 | }; 13 | -------------------------------------------------------------------------------- /src/helpers/getUsedIfis.ts: -------------------------------------------------------------------------------- 1 | import { isPlainObject } from 'lodash'; 2 | 3 | export default (data: any): string[] => { 4 | if (!isPlainObject(data)) return []; 5 | const ifis = ['mbox', 'mbox_sha1sum', 'openid', 'account']; 6 | const keys = Object.keys(data); 7 | return ifis.filter(ifi => keys.includes(ifi)); 8 | }; 9 | -------------------------------------------------------------------------------- /src/helpers/objectTypeFactory.ts: -------------------------------------------------------------------------------- 1 | import { first, checkType, Rule } from 'rulr'; 2 | import ObjectTypeWarning from '../warnings/ObjectTypeWarning'; 3 | 4 | export type Types = {[key: string]: Rule}; 5 | 6 | export default ( 7 | types: () => Types, 8 | defaultType: string 9 | ) => first(checkType(Object), (data, path) => { 10 | const typeRules = types(); 11 | const type = typeRules[data.objectType || defaultType]; 12 | return ( 13 | type === undefined ? 14 | [new ObjectTypeWarning(data.objectType, path)] : 15 | type(data, path) 16 | ); 17 | }); 18 | -------------------------------------------------------------------------------- /src/helpers/restrictToValue.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from 'rulr'; 2 | import RestrictedValueWarning from '../warnings/RestrictedValueWarning'; 3 | 4 | export default (value: any): Rule => { 5 | return (data, path) => { 6 | if (data !== value) { 7 | return [new RestrictedValueWarning(data, path, value)]; 8 | } 9 | return []; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/helpers/statementRules.ts: -------------------------------------------------------------------------------- 1 | import { composeRules, Rule } from 'rulr'; 2 | import ContextPropWarning from '../warnings/ContextPropWarning'; 3 | import VoidWarning from '../warnings/VoidWarning'; 4 | import { isObject, isPlainObject } from 'lodash'; 5 | 6 | export default composeRules([ 7 | (data, path) => { 8 | if (!isPlainObject(data)) return []; 9 | const objectIsActivity = ( 10 | isObject(data.object) && 11 | (data.object.objectType === 'Activity' || data.object.objectType === undefined) 12 | ); 13 | const hasInvalidProps = ( 14 | isObject(data.context) && 15 | (data.context.platform !== undefined || data.context.revision !== undefined) 16 | ); 17 | const invalidContext = !objectIsActivity && hasInvalidProps; 18 | return invalidContext ? [new ContextPropWarning(data, path)] : []; 19 | }, 20 | (data, path) => { 21 | if (!isPlainObject(data)) return []; 22 | const voidVerbId = 'http://adlnet.gov/expapi/verbs/voided'; 23 | const objectIsStatementRef = ( 24 | data.object && data.object.objectType === 'StatementRef' 25 | ); 26 | const verbIsVoid = data.verb && data.verb.id === voidVerbId; 27 | const hasVoidError = verbIsVoid && !objectIsStatementRef; 28 | return hasVoidError ? [new VoidWarning(data, path, voidVerbId)] : []; 29 | }, 30 | ]) as Rule; 31 | -------------------------------------------------------------------------------- /src/helpers/statementSchema.ts: -------------------------------------------------------------------------------- 1 | import { required, optional, restrictToCollection, Rule } from 'rulr'; 2 | import { 3 | actor, 4 | verb, 5 | object, 6 | result, 7 | context, 8 | timestamp, 9 | attachment, 10 | } from '../factory'; 11 | 12 | export default { 13 | actor: required(actor) as Rule, 14 | verb: required(verb), 15 | object: required(object), 16 | result: optional(result), 17 | context: optional(context), 18 | timestamp: optional(timestamp), 19 | attachments: optional(restrictToCollection(() => attachment)), 20 | }; 21 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | import * as sourceMapSupport from 'source-map-support'; 2 | sourceMapSupport.install(); 3 | 4 | import * as assert from 'assert'; 5 | import validateStatement from './index'; 6 | import { statement } from './tests/factory'; 7 | 8 | const assertArray = (value: any, message: string) => 9 | assert.equal(Array.isArray(value), true, message); 10 | 11 | const encodeData = (data: any) => 12 | JSON.stringify(data, null, 2); 13 | 14 | statement((data, valid) => { 15 | const warnings = validateStatement(data); 16 | const encodedData = encodeData(data); 17 | assertArray(warnings, `result of validation is not an array ${encodeData}`); 18 | if (valid === true) { 19 | const encodedWarnings = encodeData(data); 20 | assert.deepEqual( 21 | warnings, 22 | [], 23 | `warnings were returned\n${encodedData}\n${encodedWarnings}` 24 | ); 25 | } else { 26 | assert.equal( 27 | warnings.length === 0, 28 | false, 29 | `no warnings were returned\n${encodedData}` 30 | ); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | import { statement } from './factory'; 3 | 4 | export default (data: any): Warning[] => statement(data, ['statement']); 5 | -------------------------------------------------------------------------------- /src/maps.ts: -------------------------------------------------------------------------------- 1 | import { Rule, Warning, first, checkType } from 'rulr'; 2 | import { anyValue, stringValue, iri, language } from './factory'; 3 | 4 | const map = (keyRule: Rule, valueRule: Rule): Rule => 5 | first(checkType(Object), (data, path) => { 6 | const keys = Object.keys(data); 7 | return keys.reduce((warnings: Warning[], key: string) => 8 | warnings.concat(keyRule(key, path)).concat( 9 | valueRule(data[key], path.concat(key)) 10 | ) 11 | , []); 12 | }); 13 | 14 | export const extensions = map(iri, anyValue); 15 | export const languageMap = map(language, stringValue); 16 | -------------------------------------------------------------------------------- /src/regexValues/duration.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:max-line-length */ 2 | import { checkRegex, Rule } from 'rulr'; 3 | import { createTypeWarning } from '../warnings/TypeWarning'; 4 | 5 | export default checkRegex( 6 | /^(-?)P(?=\d|T\d)(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)([DW]))?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ 7 | , createTypeWarning('ISO Duration')) as Rule; 8 | -------------------------------------------------------------------------------- /src/regexValues/imt.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^((application|audio|example|image|message|model|multipart|text|video)(\/[-\w\+\.]+)(;\s*[-\w]+\=[-\w]+)*;?)$/ 6 | , createTypeWarning('Internet Media Type (IMT)')) as Rule; 7 | -------------------------------------------------------------------------------- /src/regexValues/interactionType.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^((choice)|(sequencing)|(likert)|(matching)|(performance)|(true-false)|(fill-in)|(long-fill-in)|(numeric)|(other))$/ 6 | , createTypeWarning('Interaction Type')) as Rule; 7 | -------------------------------------------------------------------------------- /src/regexValues/iri.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | const regex = /^\w+:/i; 5 | const warningConstructor = createTypeWarning('Internationalized Resource Identifier (IRI)'); 6 | 7 | export default checkRegex(regex, warningConstructor) as Rule; 8 | -------------------------------------------------------------------------------- /src/regexValues/language.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:max-line-length */ 2 | import { checkRegex, Rule } from 'rulr'; 3 | import { createTypeWarning } from '../warnings/TypeWarning'; 4 | 5 | export default checkRegex( 6 | /^(([a-zA-Z]{2,8}((-[a-zA-Z]{3}){0,3})(-[a-zA-Z]{4})?((-[a-zA-Z]{2})|(-\d{3}))?(-[a-zA-Z\d]{4,8})*(-[a-zA-Z\d](-[a-zA-Z\d]{1,8})+)*)|x(-[a-zA-Z\d]{1,8})+|en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tsu|i-tay|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)$/i 7 | , createTypeWarning('Language')) as Rule; 8 | -------------------------------------------------------------------------------- /src/regexValues/mailto.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^mailto:[A-Z0-9\.\`\'_%+-]+@[A-Z0-9.-]+\.[A-Z]{1,63}$/i 6 | , createTypeWarning('Mailto')) as Rule; 7 | -------------------------------------------------------------------------------- /src/regexValues/sha1.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^\b[0-9a-f]{5,40}$/i 6 | , createTypeWarning('Sha1')) as Rule; 7 | -------------------------------------------------------------------------------- /src/regexValues/timestamp.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | const YEAR = '(\\d{4})'; 5 | const MONTH = '((0[1-9])|(1[012]))'; 6 | const DAY = '((0[1-9])|([12]\\d)|(3[01]))'; 7 | const P_HOUR = '(([01]\\d)|(2[0123]))'; 8 | const N_HOUR = '((0[1-9])|(1\\d)|(2[0123]))'; 9 | const MINUTE = '([012345]\\d)'; 10 | const SECOND = '([012345]\\d)'; 11 | const FRACTION = '(\\d+)'; 12 | const DATE_SEPARATOR = '-'; 13 | const TIME_SEPARATOR = ':'; 14 | const BASIC_SECONDS = `(${SECOND}${FRACTION}?)`; 15 | const BASIC_DATE = `(${YEAR}${MONTH}${DAY})`; 16 | const BASIC_TIME = `(${P_HOUR}(${MINUTE}${BASIC_SECONDS}?)?)`; 17 | const BASIC_P_ZONE = `(\\+${P_HOUR}${MINUTE}?)`; 18 | const BASIC_N_ZONE = `(\\-${N_HOUR}${MINUTE}?)`; 19 | const BASIC_ZONE = `(Z|${BASIC_P_ZONE}|${BASIC_N_ZONE})`; 20 | const BASIC = `(${BASIC_DATE}(T${BASIC_TIME}${BASIC_ZONE})?)`; 21 | const EXT_MONTH = `(${DATE_SEPARATOR}${MONTH})`; 22 | const EXT_DAY = `(${DATE_SEPARATOR}${DAY})`; 23 | const EXT_MINUTE = `(${TIME_SEPARATOR}${MINUTE})`; 24 | const EXT_SECOND = `(${TIME_SEPARATOR}${SECOND})`; 25 | const EXT_FRACTION = `(\\.${FRACTION})`; 26 | const EXT_SECONDS = `(${EXT_SECOND}${EXT_FRACTION}?)`; 27 | const EXT_DATE = `(${YEAR}${EXT_MONTH}${EXT_DAY})`; 28 | const EXT_TIME = `(${P_HOUR}(${EXT_MINUTE}${EXT_SECONDS}?)?)`; 29 | const EXT_P_ZONE = `(\\+${P_HOUR}${EXT_MINUTE}?)`; 30 | const EXT_N_ZONE = `(\\-${N_HOUR}${EXT_MINUTE}?)`; 31 | const EXT_ZONE = `(Z|${EXT_P_ZONE}|${EXT_N_ZONE})`; 32 | const EXT = `(${EXT_DATE}(T${EXT_TIME}${EXT_ZONE})?)`; 33 | const TIMESTAMP = new RegExp(`^(${EXT}|${BASIC})$`); 34 | 35 | export default checkRegex(TIMESTAMP, createTypeWarning('ISO Timestamp')) as Rule; 36 | -------------------------------------------------------------------------------- /src/regexValues/uuid.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^\{?[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[8,9,A,B][A-F0-9]{3}-[A-F0-9]{12}\}?$/i 6 | , createTypeWarning('Universal Unique Identifier (UUID)')) as Rule; 7 | -------------------------------------------------------------------------------- /src/regexValues/version.ts: -------------------------------------------------------------------------------- 1 | import { checkRegex, Rule } from 'rulr'; 2 | import { createTypeWarning } from '../warnings/TypeWarning'; 3 | 4 | export default checkRegex( 5 | /^1\.0(\.[0-9]+)?$/ 6 | , createTypeWarning('Version')) as Rule; 7 | -------------------------------------------------------------------------------- /src/schemaRules/account.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, required, Rule } from 'rulr'; 2 | import { iri, stringValue } from '../factory'; 3 | 4 | export default restrictToSchema({ 5 | homePage: required(iri), 6 | name: required(stringValue), 7 | }) as Rule; 8 | -------------------------------------------------------------------------------- /src/schemaRules/activity.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, optional, required, Rule } from 'rulr'; 2 | import { iri, definition } from '../factory'; 3 | import restrictToValue from '../helpers/restrictToValue'; 4 | 5 | export default restrictToSchema({ 6 | objectType: optional(restrictToValue('Activity')), 7 | id: required(iri), 8 | definition: optional(definition), 9 | }) as Rule; 10 | -------------------------------------------------------------------------------- /src/schemaRules/actor.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from 'rulr'; 2 | import objectTypeFactory from '../helpers/objectTypeFactory'; 3 | import { agent, group } from '../factory'; 4 | 5 | export default objectTypeFactory(() => ({ 6 | Agent: agent, 7 | Group: group, 8 | }), 'Agent') as Rule; 9 | -------------------------------------------------------------------------------- /src/schemaRules/agent.ts: -------------------------------------------------------------------------------- 1 | import { composeRules, restrictToSchema, Rule } from 'rulr'; 2 | import agentSchema from '../helpers/agentSchema'; 3 | import getUsedIfis from '../helpers/getUsedIfis'; 4 | import { isPlainObject } from 'lodash'; 5 | 6 | import IfiCountWarning from '../warnings/IfiCountWarning'; 7 | import NoIfiWarning from '../warnings/NoIfiWarning'; 8 | 9 | export default composeRules([ 10 | restrictToSchema(agentSchema), 11 | (data, path) => { 12 | if (!isPlainObject(data)) return []; 13 | const usedIfis = getUsedIfis(data); 14 | if (usedIfis.length > 1) return [new IfiCountWarning(data, path, usedIfis)]; 15 | if (usedIfis.length === 0) return [new NoIfiWarning(data, path)]; 16 | return []; 17 | }, 18 | ]) as Rule; 19 | -------------------------------------------------------------------------------- /src/schemaRules/attachment.ts: -------------------------------------------------------------------------------- 1 | import { composeRules, restrictToSchema, optional, required, Rule } from 'rulr'; 2 | import { isPlainObject } from 'lodash'; 3 | import { iri, languageMap, imt, integerValue, stringValue } from '../factory'; 4 | import SignedContentTypeWarning from '../warnings/SignedContentTypeWarning'; 5 | 6 | export default composeRules([ 7 | restrictToSchema({ 8 | usageType: required(iri), 9 | display: required(languageMap), 10 | description: optional(languageMap), 11 | contentType: required(imt), 12 | length: required(integerValue), 13 | sha2: required(stringValue), 14 | fileUrl: optional(iri), 15 | }), 16 | (data, path) => { 17 | if (!isPlainObject(data)) return []; 18 | if ( 19 | data.usageType === 'http://adlnet.gov/expapi/attachments/signature' && 20 | data.contentType !== 'application/octet-stream' 21 | ) { 22 | return [new SignedContentTypeWarning(data, path, data.contentType)]; 23 | } 24 | return []; 25 | } 26 | ]) as Rule; 27 | -------------------------------------------------------------------------------- /src/schemaRules/authority.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from 'rulr'; 2 | import objectTypeFactory from '../helpers/objectTypeFactory'; 3 | import { agent, groupAuthority } from '../factory'; 4 | 5 | export default objectTypeFactory(() => ({ 6 | Agent: agent, 7 | Group: groupAuthority, 8 | }), 'Agent') as Rule; 9 | -------------------------------------------------------------------------------- /src/schemaRules/context.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, restrictToCollection, optional, Rule } from 'rulr'; 2 | import { 3 | activity, 4 | uuid, 5 | actor, 6 | group, 7 | stringValue, 8 | language, 9 | statementRef, 10 | extensions, 11 | } from '../factory'; 12 | 13 | const contextActivities = restrictToSchema({ 14 | parent: optional(restrictToCollection(() => activity)), 15 | category: optional(restrictToCollection(() => activity)), 16 | grouping: optional(restrictToCollection(() => activity)), 17 | other: optional(restrictToCollection(() => activity)), 18 | }); 19 | 20 | export default restrictToSchema({ 21 | registration: optional(uuid), 22 | instructor: optional(actor), 23 | team: optional(group), 24 | contextActivities: optional(contextActivities), 25 | revision: optional(stringValue), 26 | platform: optional(stringValue), 27 | language: optional(language), 28 | statement: optional(statementRef), 29 | extensions: optional(extensions), 30 | }) as Rule; 31 | -------------------------------------------------------------------------------- /src/schemaRules/definition.ts: -------------------------------------------------------------------------------- 1 | import { 2 | restrictToSchema, restrictToCollection, composeRules, optional, Rule, Warning 3 | } from 'rulr'; 4 | import { isPlainObject } from 'lodash'; 5 | import InvalidComponentsWarning from '../warnings/InvalidComponentsWarning'; 6 | import MissingInteractionTypeWarning from '../warnings/MissingInteractionTypeWarning'; 7 | import { 8 | languageMap, 9 | iri, 10 | extensions, 11 | interactionType, 12 | stringValue, 13 | interactionComponent, 14 | } from '../factory'; 15 | 16 | const getSupportedComponents = (interactionType: string): string[] => { 17 | switch (interactionType) { 18 | case 'choice': 19 | case 'sequencing': 20 | return ['choices']; 21 | case 'likert': 22 | return ['scale']; 23 | case 'matching': 24 | return ['source', 'target']; 25 | case 'performance': 26 | return ['steps']; 27 | case 'true-false': 28 | case 'fill-in': 29 | case 'long-fill-in': 30 | case 'numeric': 31 | case 'other': 32 | default: 33 | return []; 34 | } 35 | }; 36 | const getUnsupportedComponents = (interactionType: string): string[] => { 37 | const allComponents = ['choices', 'scale', 'source', 'target', 'steps']; 38 | const supportedComponents = getSupportedComponents(interactionType); 39 | return allComponents.filter( 40 | component => !supportedComponents.includes(component) 41 | ); 42 | }; 43 | 44 | export default composeRules([ 45 | restrictToSchema({ 46 | name: optional(languageMap), 47 | description: optional(languageMap), 48 | type: optional(iri), 49 | moreInfo: optional(iri), 50 | extensions: optional(extensions), 51 | interactionType: optional(interactionType), 52 | correctResponsesPattern: optional(restrictToCollection(() => stringValue)), 53 | choices: optional(restrictToCollection(() => interactionComponent)), 54 | scale: optional(restrictToCollection(() => interactionComponent)), 55 | source: optional(restrictToCollection(() => interactionComponent)), 56 | target: optional(restrictToCollection(() => interactionComponent)), 57 | steps: optional(restrictToCollection(() => interactionComponent)), 58 | }), 59 | (data, path): Warning[] => { 60 | if (!isPlainObject(data)) return []; 61 | const interactionType = data.interactionType; 62 | const unsupportedComponents = getUnsupportedComponents(interactionType); 63 | const invalidComponents = unsupportedComponents.filter( 64 | component => data[component] !== undefined 65 | ); 66 | if (invalidComponents.length > 0) return [ 67 | new InvalidComponentsWarning(data, path, invalidComponents) 68 | ]; 69 | return []; 70 | }, 71 | (data, path): Warning[] => { 72 | if (!isPlainObject(data)) return []; 73 | const missingInteractionType = ( 74 | data.correctResponsesPattern !== undefined && 75 | data.interactionType === undefined 76 | ); 77 | if (missingInteractionType) { 78 | return [ 79 | new MissingInteractionTypeWarning(data, path) 80 | ]; 81 | } 82 | return []; 83 | } 84 | ]) as Rule; 85 | -------------------------------------------------------------------------------- /src/schemaRules/group.ts: -------------------------------------------------------------------------------- 1 | import { 2 | composeRules, 3 | restrictToSchema, 4 | restrictToCollection, 5 | optional, 6 | Rule, 7 | } from 'rulr'; 8 | import { isPlainObject } from 'lodash'; 9 | import agentSchema from '../helpers/agentSchema'; 10 | import getUsedIfis from '../helpers/getUsedIfis'; 11 | import restrictToValue from '../helpers/restrictToValue'; 12 | import { actor } from '../factory'; 13 | import IfiCountWarning from '../warnings/IfiCountWarning'; 14 | import NoMembersWarning from '../warnings/NoMembersWarning'; 15 | 16 | export default composeRules([ 17 | restrictToSchema(Object.assign({}, agentSchema, { 18 | objectType: optional(restrictToValue('Group')), 19 | member: optional(restrictToCollection(() => actor)), 20 | })), 21 | (data, path) => { 22 | if (!isPlainObject(data)) return []; 23 | const usedIfis = getUsedIfis(data); 24 | const usedMember = ( 25 | data.member != null && 26 | Array.isArray(data.member) && 27 | data.member.length > 0 28 | ); 29 | if (usedIfis.length > 1) return [new IfiCountWarning(data, path, usedIfis)]; 30 | const hasNoMembers = usedIfis.length === 0 && !usedMember; 31 | return hasNoMembers ? [new NoMembersWarning(data, path)] : []; 32 | }, 33 | ]) as Rule; 34 | -------------------------------------------------------------------------------- /src/schemaRules/groupAuthority.ts: -------------------------------------------------------------------------------- 1 | import { composeRules, Rule, optional, restrictToSchema, restrictToCollection } from 'rulr'; 2 | import { actor } from '../factory'; 3 | import MembersTypeWarning from '../warnings/MembersTypeWarning'; 4 | import MembersLengthWarning from '../warnings/MembersLengthWarning'; 5 | import restrictToValue from '../helpers/restrictToValue'; 6 | import { isPlainObject } from 'lodash'; 7 | 8 | export default composeRules([ 9 | restrictToSchema({ 10 | objectType: optional(restrictToValue('Group')), 11 | member: optional(restrictToCollection(() => actor)) 12 | }), 13 | (data, path) => { 14 | if (!isPlainObject(data)) return []; 15 | const members = Array.isArray(data.member) ? data.member.length : 0; 16 | 17 | if (members !== 2) return [new MembersTypeWarning(data, path)]; 18 | 19 | const invalidMembers = data.member.filter((member: any) => 20 | member.objectType !== 'Agent' && member.objectType !== undefined 21 | ); 22 | 23 | if (invalidMembers.length > 0) return [new MembersLengthWarning(data, path)]; 24 | return []; 25 | } 26 | ]) as Rule; 27 | -------------------------------------------------------------------------------- /src/schemaRules/interactionComponent.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, optional, required, Rule } from 'rulr'; 2 | import { stringValue, languageMap } from '../factory'; 3 | 4 | export default restrictToSchema({ 5 | id: required(stringValue), 6 | description: optional(languageMap), 7 | }) as Rule; 8 | -------------------------------------------------------------------------------- /src/schemaRules/object.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from 'rulr'; 2 | import objectTypeFactory from '../helpers/objectTypeFactory'; 3 | import { 4 | agent, 5 | group, 6 | activity, 7 | subStatement, 8 | statementRef, 9 | } from '../factory'; 10 | 11 | export default objectTypeFactory(() => ({ 12 | Agent: agent, 13 | Group: group, 14 | Activity: activity, 15 | SubStatement: subStatement, 16 | StatementRef: statementRef, 17 | }), 'Activity') as Rule; 18 | -------------------------------------------------------------------------------- /src/schemaRules/result.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, optional, Rule, composeRules, Warning } from 'rulr'; 2 | import { 3 | scaledValue, 4 | numberValue, 5 | booleanValue, 6 | stringValue, 7 | duration, 8 | extensions, 9 | } from '../factory'; 10 | import { isPlainObject } from 'lodash'; 11 | import RawLessThanMinWarning from '../warnings/RawLessThanMinWarning'; 12 | import RawMoreThanMaxWarning from '../warnings/RawMoreThanMaxWarning'; 13 | import MinMoreThanMaxWarning from '../warnings/MinMoreThanMaxWarning'; 14 | 15 | const checkRawMoreThanMin = (data: any, path: string[]): Warning[] => { 16 | if (!isPlainObject(data)) return []; 17 | if (data.raw !== undefined && data.min !== undefined && data.raw < data.min) { 18 | return [new RawLessThanMinWarning(data, path, data.raw, data.min)]; 19 | } 20 | return []; 21 | }; 22 | 23 | const checkRawLessThanMax = (data: any, path: string[]): Warning[] => { 24 | if (!isPlainObject(data)) return []; 25 | if (data.raw !== undefined && data.max !== undefined && data.raw > data.max) { 26 | return [new RawMoreThanMaxWarning(data, path, data.raw, data.max)]; 27 | } 28 | return []; 29 | }; 30 | 31 | const checkMinLessThanMax = (data: any, path: string[]): Warning[] => { 32 | if (!isPlainObject(data)) return []; 33 | if (data.min !== undefined && data.max !== undefined && data.min > data.max) { 34 | return [new MinMoreThanMaxWarning(data, path, data.min, data.max)]; 35 | } 36 | return []; 37 | }; 38 | 39 | const score = composeRules([ 40 | restrictToSchema({ 41 | scaled: optional(scaledValue), 42 | raw: optional(numberValue), 43 | min: optional(numberValue), 44 | max: optional(numberValue), 45 | }), 46 | checkRawMoreThanMin, 47 | checkRawLessThanMax, 48 | checkMinLessThanMax, 49 | ]); 50 | 51 | export default restrictToSchema({ 52 | score: optional(score), 53 | success: optional(booleanValue), 54 | completion: optional(booleanValue), 55 | response: optional(stringValue), 56 | duration: optional(duration), 57 | extensions: optional(extensions), 58 | }) as Rule; 59 | -------------------------------------------------------------------------------- /src/schemaRules/statement.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, composeRules, optional, Rule } from 'rulr'; 2 | import statementSchema from '../helpers/statementSchema'; 3 | import statementRules from '../helpers/statementRules'; 4 | import { uuid, timestamp, authority, version } from '../factory'; 5 | 6 | export default composeRules([ 7 | restrictToSchema(Object.assign({}, statementSchema, { 8 | id: optional(uuid), 9 | stored: optional(timestamp), 10 | authority: optional(authority), 11 | version: optional(version), 12 | })), 13 | statementRules, 14 | ]) as Rule; 15 | -------------------------------------------------------------------------------- /src/schemaRules/statementRef.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, required, optional, Rule } from 'rulr'; 2 | import { uuid } from '../factory'; 3 | import restrictToValue from '../helpers/restrictToValue'; 4 | 5 | export default restrictToSchema({ 6 | objectType: optional(restrictToValue('StatementRef')), 7 | id: required(uuid), 8 | }) as Rule; 9 | -------------------------------------------------------------------------------- /src/schemaRules/subStatement.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, composeRules, optional, Rule } from 'rulr'; 2 | import statementSchema from '../helpers/statementSchema'; 3 | import statementRules from '../helpers/statementRules'; 4 | import restrictToValue from '../helpers/restrictToValue'; 5 | import SubStatementWarning from '../warnings/SubStatementWarning'; 6 | import { isPlainObject } from 'lodash'; 7 | 8 | export default composeRules([ 9 | restrictToSchema(Object.assign({}, statementSchema, { 10 | objectType: optional(restrictToValue('SubStatement')), 11 | })), 12 | statementRules, 13 | (data, path) => { 14 | if (!isPlainObject(data)) return []; 15 | const objectIsSubStatement = ( 16 | data.object && data.object.objectType === 'SubStatement' 17 | ); 18 | return objectIsSubStatement ? [new SubStatementWarning(data, path)] : []; 19 | }, 20 | ]) as Rule; 21 | -------------------------------------------------------------------------------- /src/schemaRules/verb.ts: -------------------------------------------------------------------------------- 1 | import { restrictToSchema, required, optional, Rule } from 'rulr'; 2 | import { iri, languageMap } from '../factory'; 3 | 4 | export default restrictToSchema({ 5 | id: required(iri), 6 | display: optional(languageMap), 7 | }) as Rule; 8 | -------------------------------------------------------------------------------- /src/tests/describeIfiProp.ts: -------------------------------------------------------------------------------- 1 | import Test from './helpers/test'; 2 | import 'mocha'; 3 | 4 | export default (prop: string, describer: (test: Test) => void, test: Test) => 5 | describe(prop, () => { 6 | describer((value, valid) => { 7 | const data = { [prop]: value }; 8 | test(data, valid); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/tests/describeInteractionProp.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from './helpers/test'; 3 | import describeOptionalProp from './describeOptionalProp'; 4 | import itsInvalid from './itsInvalid'; 5 | import collection from './helpers/collection'; 6 | import { interactionComponent } from './factory'; 7 | 8 | const interactionComponents = collection(interactionComponent); 9 | const allComponents = ['choices', 'scale', 'source', 'target', 'steps']; 10 | 11 | export default (validProps: string[], type: string, test: Test) => { 12 | validProps.forEach(prop => 13 | describeOptionalProp(prop, interactionComponents, { 14 | interactionType: type 15 | }, test) 16 | ); 17 | allComponents.filter(prop => 18 | !validProps.includes(prop) 19 | ).forEach(prop => { 20 | const data = { 21 | interactionType: type, 22 | [prop]: [], 23 | }; 24 | const message = `containing unsupported component ${prop} for ${type}`; 25 | itsInvalid(data, message, test); 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /src/tests/describeMemberProp.ts: -------------------------------------------------------------------------------- 1 | import Test from './helpers/test'; 2 | import 'mocha'; 3 | 4 | export default (describer: (test: Test) => void, test: Test) => 5 | describe('member', () => { 6 | describer((value, valid) => 7 | test({ 8 | objectType: 'Group', 9 | name: 'Test', 10 | mbox: 'mailto:test@example.com', 11 | member: [value], 12 | }, valid) 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /src/tests/describeOptionalProp.ts: -------------------------------------------------------------------------------- 1 | import describeProp from './describeProp'; 2 | 3 | export default describeProp(true, 'should not return an error when missing'); 4 | -------------------------------------------------------------------------------- /src/tests/describeProp.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from './helpers/test'; 3 | import { omit } from 'lodash'; 4 | 5 | export default (missingValid: boolean, description: string) => 6 | (prop: string, describer: (test: Test) => void, validData: any, test: Test) => { 7 | it(`${description} ${prop}`, () => 8 | test(omit(validData, prop), missingValid) 9 | ); 10 | describe(prop, () => { 11 | describer((value, valid) => { 12 | const overrides = { [prop]: value }; 13 | const data = Object.assign({}, validData, overrides); 14 | test(data, valid); 15 | }); 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /src/tests/describeRequiredProp.ts: -------------------------------------------------------------------------------- 1 | import describeProp from './describeProp'; 2 | 3 | export default describeProp(false, 'should return an error when missing'); 4 | -------------------------------------------------------------------------------- /src/tests/factory.ts: -------------------------------------------------------------------------------- 1 | import Test from './helpers/test'; 2 | 3 | const requireTest = (rule: string) => (test: Test): void => 4 | require(rule).default(test); 5 | 6 | export const account = requireTest('./schemaRules/account'); 7 | export const activity = requireTest('./schemaRules/activity'); 8 | export const actor = requireTest('./schemaRules/actor'); 9 | export const agent = requireTest('./schemaRules/agent'); 10 | export const attachment = requireTest('./schemaRules/attachment'); 11 | export const authority = requireTest('./schemaRules/authority'); 12 | export const booleanValue = requireTest('./values/boolean'); 13 | export const context = requireTest('./schemaRules/context'); 14 | export const contextActivities = requireTest('./schemaRules/contextActivities'); 15 | export const definition = requireTest('./schemaRules/definition'); 16 | export const duration = requireTest('./regexValues/duration'); 17 | export const extensions = requireTest('./maps/extensions'); 18 | export const group = requireTest('./schemaRules/group'); 19 | export const subGroup = requireTest('./schemaRules/subGroup'); 20 | export const imt = requireTest('./regexValues/imt'); 21 | export const integerValue = requireTest('./values/integer'); 22 | export const interactionComponent = requireTest('./schemaRules/interactionComponent'); 23 | export const interactionType = requireTest('./regexValues/interactionType'); 24 | export const iri = requireTest('./regexValues/iri'); 25 | export const language = requireTest('./regexValues/language'); 26 | export const languageMap = requireTest('./maps/languageMap'); 27 | export const mailto = requireTest('./regexValues/mailto'); 28 | export const numberValue = requireTest('./values/number'); 29 | export const object = requireTest('./schemaRules/object'); 30 | export const result = requireTest('./schemaRules/result'); 31 | export const scaledValue = requireTest('./values/scaled'); 32 | export const score = requireTest('./schemaRules/score'); 33 | export const sha1 = requireTest('./regexValues/sha1'); 34 | export const statement = requireTest('./schemaRules/statement'); 35 | export const statementRef = requireTest('./schemaRules/statementRef'); 36 | export const stringValue = requireTest('./values/string'); 37 | export const subStatement = requireTest('./schemaRules/subStatement'); 38 | export const subStatementObject = requireTest('./schemaRules/subStatementObject'); 39 | export const timestamp = requireTest('./regexValues/timestamp'); 40 | export const uuid = requireTest('./regexValues/uuid'); 41 | export const verb = requireTest('./schemaRules/verb'); 42 | export const version = requireTest('./regexValues/version'); 43 | -------------------------------------------------------------------------------- /src/tests/helpers/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LearningLocker/xapi-validation/13ffff748515197cafec3d21c327ebe0f471d58b/src/tests/helpers/.DS_Store -------------------------------------------------------------------------------- /src/tests/helpers/agentSchema.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeOptionalProp from '../describeOptionalProp'; 3 | import describeIfiProp from '../describeIfiProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import { 6 | stringValue, 7 | mailto, 8 | sha1, 9 | iri, 10 | account, 11 | } from '../factory'; 12 | 13 | const validData = { 14 | mbox: 'mailto:test@example.com', 15 | }; 16 | 17 | export default (test: Test) => { 18 | describeOptionalProp('name', stringValue, validData, test); 19 | describeIfiProp('mbox', mailto, test); 20 | describeIfiProp('mbox_sha1sum', sha1, test); 21 | describeIfiProp('openid', iri, test); 22 | describeIfiProp('account', account, test); 23 | itsInvalid(10, 'not an object', test); 24 | itsInvalid({ 25 | objectType: 'Agent', 26 | name: 'Test', 27 | }, 'missing an IFI', test); 28 | itsInvalid({ 29 | objectType: 'Agent', 30 | name: 'Test', 31 | mbox: 'mailto:test@example.com', 32 | openid: 'http://www.example.com', 33 | }, 'containing too many IFIs', test); 34 | }; 35 | -------------------------------------------------------------------------------- /src/tests/helpers/collection.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | 3 | export default (describer: (test: Test) => any) => (test: Test) => 4 | describer((value, valid) => 5 | test([value], valid) 6 | ); 7 | -------------------------------------------------------------------------------- /src/tests/helpers/object.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import objectTypeFactory, { Types } from '../helpers/objectTypeFactory'; 3 | import { 4 | agent, 5 | group, 6 | activity, 7 | statementRef, 8 | } from '../factory'; 9 | 10 | export default (additionalTypes: Types) => 11 | (test: Test) => 12 | objectTypeFactory(Object.assign({}, { 13 | Agent: agent, 14 | Group: group, 15 | Activity: activity, 16 | StatementRef: statementRef, 17 | }, additionalTypes), 'Activity', test, { id: 'http://www.example.org/activity' }); 18 | -------------------------------------------------------------------------------- /src/tests/helpers/objectTypeFactory.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from '../helpers/test'; 3 | import itsInvalid from '../itsInvalid'; 4 | 5 | export type Type = (test: Test) => any; 6 | export type Types = {[key: string]: Type}; 7 | 8 | export default (types: Types, defaultType: string, test: Test, validDefaultData: object): void => { 9 | itsInvalid(10, 'not an object', test); 10 | itsInvalid({ 11 | ...validDefaultData, 12 | objectType: 'InvalidObjectType', 13 | }, 'not a valid objectType', test); 14 | Object.keys(types).forEach((type: string) => { 15 | describe(`Object Type: ${type}`, () => { 16 | types[type]((data: any, valid: boolean): any => { 17 | test(Object.assign({}, data, { 18 | objectType: type, 19 | }), valid); 20 | }); 21 | }); 22 | }); 23 | describe(`Default Object Type: ${defaultType} `, () => { 24 | types[defaultType](test); 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /src/tests/helpers/statementRules.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | const statementRef = { 3 | objectType: 'StatementRef', 4 | id: '957f56b7-1d34-4b01-9408-3ffeb2053b28', 5 | }; 6 | const activity = { 7 | objectType: 'Activity', 8 | id: 'http://www.example.com', 9 | }; 10 | const platform = 'Test'; 11 | const revision = 'Test'; 12 | const verb = { 13 | id: 'http://adlnet.gov/expapi/verbs/voided', 14 | }; 15 | 16 | export default (test: Test) => { 17 | it('should return an error when platform is set incorrectly', () => 18 | test({ 19 | object: statementRef, 20 | context: { platform }, 21 | }, false) 22 | ); 23 | it('should not return an error when platform is set and object has no objectType', () => 24 | test({ 25 | object: { id: activity.id }, 26 | context: { platform }, 27 | }, true) 28 | ); 29 | it('should return an error when revision is set incorrectly', () => 30 | test({ 31 | object: statementRef, 32 | context: { revision }, 33 | }, false) 34 | ); 35 | it('should not return an error when revision is set and object has no objectType', () => 36 | test({ 37 | object: { id: activity.id }, 38 | context: { revision }, 39 | }, true) 40 | ); 41 | it('should not return an error when context is used correctly', () => 42 | test({ 43 | object: activity, 44 | context: { platform, revision }, 45 | }, true) 46 | ); 47 | it('should return an error when void is used incorrectly', () => 48 | test({ 49 | object: activity, 50 | verb, 51 | }, false) 52 | ); 53 | it('should not return an error when void is used correctly', () => 54 | test({ 55 | object: statementRef, 56 | verb, 57 | }, true) 58 | ); 59 | }; 60 | -------------------------------------------------------------------------------- /src/tests/helpers/statementSchema.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import validStatementData from '../helpers/validStatementData'; 5 | import statementRules from '../helpers/statementRules'; 6 | import collection from '../helpers/collection'; 7 | import { 8 | actor, 9 | verb, 10 | result, 11 | context, 12 | timestamp, 13 | attachment, 14 | } from '../factory'; 15 | 16 | const attachments = collection(attachment); 17 | 18 | export default (test: Test) => { 19 | describeRequiredProp('actor', actor, validStatementData, test); 20 | describeRequiredProp('verb', verb, validStatementData, test); 21 | describeOptionalProp('result', result, validStatementData, test); 22 | describeOptionalProp('context', context, validStatementData, test); 23 | describeOptionalProp('timestamp', timestamp, validStatementData, test); 24 | describeOptionalProp('attachments', attachments, validStatementData, test); 25 | statementRules((data, valid) => 26 | test(Object.assign({}, validStatementData, data), valid) 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/tests/helpers/test.ts: -------------------------------------------------------------------------------- 1 | type Test = (data: any, valid: boolean) => void; 2 | 3 | export default Test; 4 | -------------------------------------------------------------------------------- /src/tests/helpers/validStatementData.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | actor: { 3 | objectType: 'Agent', 4 | mbox: 'mailto:test@example.com', 5 | }, 6 | verb: { 7 | id: 'http://www.example.com', 8 | }, 9 | object: { 10 | objectType: 'Activity', 11 | id: 'http://www.example.com', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/tests/itsInvalid.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from './helpers/test'; 3 | 4 | export default (invalidData: any, message: string, test: Test): any => 5 | it(`should return an error when data is ${message}`, () => 6 | test(invalidData, false) 7 | ); 8 | -------------------------------------------------------------------------------- /src/tests/itsValid.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from './helpers/test'; 3 | 4 | export default (validData: any, test: Test): any => 5 | it(`should not return an error when data is valid`, () => 6 | test(validData, true) 7 | ); 8 | -------------------------------------------------------------------------------- /src/tests/maps/extensions.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = { 6 | 'http://www.example.com': 'test', 7 | }; 8 | 9 | export default (test: Test) => { 10 | itsInvalid(10, 'not an object', test); 11 | itsInvalid({ 12 | http: 'test' 13 | }, 'containing invalid keys', test); 14 | itsValid(validData, test); 15 | }; 16 | -------------------------------------------------------------------------------- /src/tests/maps/languageMap.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = { 6 | 'en-GB': 'test', 7 | }; 8 | 9 | export default (test: Test) => { 10 | itsInvalid(10, 'not an object', test); 11 | itsInvalid({ 12 | '-': 'test' 13 | }, 'containing invalid keys', test); 14 | itsInvalid({ 15 | 'en-GB': 10 16 | }, 'containing invalid values', test); 17 | itsValid(validData, test); 18 | }; 19 | -------------------------------------------------------------------------------- /src/tests/regexValues/duration.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'P3Y6M4DT12H30M5S'; 6 | const validData2 = 'P4W'; 7 | 8 | export default (test: Test) => { 9 | itsInvalid('3Y6M4DT12H30M5S', 'not a Duration', test); 10 | itsInvalid('P4W1D', 'not a Duration', test); 11 | itsInvalid(10, 'not a String', test); 12 | itsValid(validData, test); 13 | itsValid(validData2, test); 14 | }; 15 | -------------------------------------------------------------------------------- /src/tests/regexValues/imt.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'application/json'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('applications/json', 'not a IMT', test); 9 | itsInvalid(10, 'not a String', test); 10 | itsValid(validData, test); 11 | itsValid( 12 | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 13 | test 14 | ); // v1#819 15 | }; 16 | -------------------------------------------------------------------------------- /src/tests/regexValues/interactionType.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'choice'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('choices', 'not an Interaction Type', test); 9 | itsInvalid(10, 'not a String', test); 10 | itsValid(validData, test); 11 | }; 12 | -------------------------------------------------------------------------------- /src/tests/regexValues/iri.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid('http', 'not an IRI', test); 7 | itsInvalid(10, 'not a String', test); 8 | itsValid('http://www.example.com', test); 9 | 10 | // https://mathiasbynens.be/demo/url-regex 11 | itsValid('http://fo-o.com/blah_blah_(wikipedia)#cite-1', test); 12 | itsValid('https://www.example.com/foo/?bar=b%20az&inga=42&quux', test); 13 | itsValid('http://userid:password@example.com:8080/', test); 14 | itsValid('http://userid:password@example.com/', test); 15 | itsValid('http://142.42.1.1:8080/', test); 16 | itsValid('http://foo.com/unicode_(✪)_in_parens', test); 17 | itsValid('http://foo.com/(something)?after=parens', test); 18 | itsValid('http://code.google.com/events/#&product=browser', test); 19 | itsValid('ftp://foo.bar/baz', test); 20 | itsValid('http://⌘➡例子.测试✪उदाहरण.परीकإختبار/䨹', test); 21 | itsValid('http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com', test); 22 | itsValid('http://www.example.com/fgdfgd?sdfsdfsdf#fgdgdfg', test); 23 | 24 | // tslint:disable-next-line:max-line-length 25 | itsValid('http://some.large.test.string.for.regex/some-large-string/string.html?largeString=largeString&someStrangeText=%D0%9F%D1%81%D0%B5%D0%B2%D0%B4%D0%BE%D1%82%D1%83%D0%B1%D0%B5%D1%80%D0%BA%D1%83%D0%BB%D0%B5%D0%B7', test); 26 | itsValid('https://some.strange.test/tests/very-strange-test-that-hangs-regex/test#test/test"', test); 27 | 28 | // Tests from the conformance suite. 29 | itsInvalid('ab=c://should.fail.com', 'not an IRI', test); 30 | itsInvalid('not.a.valid.iri.com/verb', 'not an IRI', test); 31 | 32 | // LL-472 33 | itsValid('urn:071b8229-c909-5d6f-b250-8cbb6f36fda7:Test:Test_0', test); 34 | itsValid('urn:uuid:a4942cbb-aabf-526f-8f69-379f265416b5', test); 35 | }; 36 | -------------------------------------------------------------------------------- /src/tests/regexValues/language.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'en-US'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('-', 'not a Language', test); 9 | itsInvalid(10, 'not a String', test); 10 | itsValid(validData, test); 11 | }; 12 | -------------------------------------------------------------------------------- /src/tests/regexValues/mailto.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'mailto:test@example.com'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('test@example.com', 'not a Mailto', test); 9 | itsInvalid(10, 'not a String', test); 10 | itsValid(validData, test); 11 | itsValid('mailto:test@example.horse', test); // factory#8 12 | itsValid('mailto:te\`st@example.com', test); // factory#10 13 | }; 14 | -------------------------------------------------------------------------------- /src/tests/regexValues/sha1.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = '4445904ac65039ef7a91506207f19162ac4dea73'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('test', 'not a Sha1', test); 9 | itsInvalid(10, 'not a String', test); 10 | itsValid(validData, test); 11 | }; 12 | -------------------------------------------------------------------------------- /src/tests/regexValues/timestamp.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid(10, 'not a String', test); 7 | 8 | itsValid('20090131T230000-0100', test); // Basic format 9 | itsValid('2009-01-31T23:00:00-01:00', test); // Extended format 10 | itsValid('20170101', test); // Date basic format 11 | itsValid('2017-01-01', test); // Date extended format 12 | 13 | itsInvalid('2009-01-31T230000-01:00', 'not a Timestamp', test); 14 | itsInvalid('2017', 'not a Timestamp', test); 15 | itsInvalid('2017-01', 'not a Timestamp', test); 16 | 17 | // http://stackoverflow.com/questions/12756159 18 | itsInvalid('2013-99-99T04:13:00+00:00', 'not a Timestamp', test); 19 | itsValid('0785-10-10T04:13:00+00:00', test); 20 | }; 21 | -------------------------------------------------------------------------------- /src/tests/regexValues/uuid.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = '957f56b7-1d34-4b01-9408-3ffeb2053b28'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid('957f56b7-1d34-4b01-9408-3ffeb2053b2', 'not a UUID', test); 9 | itsInvalid('957e56b7-1d34-4b01-9408-3ffeb2053b2', 'not a UUID with non hex digits', test); 10 | itsInvalid(10, 'not a String', test); 11 | itsValid(validData, test); 12 | }; 13 | -------------------------------------------------------------------------------- /src/tests/regexValues/version.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = '1.0.0'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid(10, 'not a String', test); 9 | itsValid('1.0', test); 10 | itsValid(validData, test); 11 | }; 12 | -------------------------------------------------------------------------------- /src/tests/schemaRules/account.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import { iri, stringValue } from '../factory'; 5 | 6 | const validData = { 7 | homePage: 'http://www.example.com', 8 | name: '123', 9 | }; 10 | 11 | export default (test: Test) => { 12 | itsInvalid(10, 'not an object', test); 13 | describeRequiredProp('homePage', iri, validData, test); 14 | describeRequiredProp('name', stringValue, validData, test); 15 | }; 16 | -------------------------------------------------------------------------------- /src/tests/schemaRules/activity.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import { iri, definition } from '../factory'; 6 | 7 | const validData = { 8 | objectType: 'Activity', 9 | id: 'http://www.example.com', 10 | }; 11 | 12 | export default (test: Test) => { 13 | itsInvalid(10, 'not an object', test); 14 | describeRequiredProp('id', iri, validData, test); 15 | describeOptionalProp('definition', definition, validData, test); 16 | }; 17 | -------------------------------------------------------------------------------- /src/tests/schemaRules/actor.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import objectTypeFactory from '../helpers/objectTypeFactory'; 3 | import { agent, group } from '../factory'; 4 | 5 | export default (test: Test) => 6 | objectTypeFactory({ 7 | Agent: agent, 8 | Group: group, 9 | }, 'Agent', test, { mbox: 'mailto:test@example.org' }); 10 | -------------------------------------------------------------------------------- /src/tests/schemaRules/agent.ts: -------------------------------------------------------------------------------- 1 | import agentSchema from '../helpers/agentSchema'; 2 | 3 | export default agentSchema; 4 | -------------------------------------------------------------------------------- /src/tests/schemaRules/attachment.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import itsValid from '../itsValid'; 6 | import { iri, languageMap, imt, integerValue, stringValue } from '../factory'; 7 | 8 | const validData = { 9 | usageType: 'http://www.example.com', 10 | display: {}, 11 | description: {}, 12 | contentType: 'application/json', 13 | length: 10, 14 | sha2: 'test', 15 | fileUrl: 'http://www.example.com', 16 | }; 17 | 18 | export default (test: Test) => { 19 | itsInvalid(10, 'not an object', test); 20 | itsInvalid({ 21 | ...validData, 22 | usageType: 'http://adlnet.gov/expapi/attachments/signature', 23 | contentType: 'application/json', 24 | }, 'not a valid signed content type', test); 25 | itsValid({ 26 | ...validData, 27 | usageType: 'http://adlnet.gov/expapi/attachments/signature', 28 | contentType: 'application/octet-stream', 29 | }, test); 30 | describeRequiredProp('usageType', iri, validData, test); 31 | describeRequiredProp('display', languageMap, validData, test); 32 | describeOptionalProp('description', languageMap, validData, test); 33 | describeRequiredProp('contentType', imt, validData, test); 34 | describeRequiredProp('length', integerValue, validData, test); 35 | describeRequiredProp('sha2', stringValue, validData, test); 36 | describeOptionalProp('fileUrl', iri, validData, test); 37 | }; 38 | -------------------------------------------------------------------------------- /src/tests/schemaRules/authority.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | import agentSchema from '../helpers/agentSchema'; 5 | 6 | const agentMember = { 7 | objectType: 'Agent', 8 | mbox: 'mailto:test@example.com', 9 | }; 10 | 11 | export default (test: Test) => { 12 | itsInvalid(10, 'not an object', test); 13 | itsInvalid({ 14 | objectType: 'InvalidObjectType', 15 | mbox: 'mailto:test@example.org', 16 | }, 'uses invalid objectType', test); 17 | itsInvalid({ 18 | objectType: 'Group', 19 | member: [], 20 | }, 'contains no members', test); 21 | itsInvalid({ 22 | objectType: 'Group', 23 | member: [agentMember], 24 | }, 'contains too few members', test); 25 | itsInvalid({ 26 | objectType: 'Group', 27 | member: [agentMember, agentMember], 28 | mbox: agentMember.mbox 29 | }, 'contains an mbox on a group', test); 30 | itsInvalid({ 31 | objectType: 'Group', 32 | member: [agentMember, agentMember], 33 | account: {name: 'test', homePage: 'http://example.org'} 34 | }, 'contains an account on a group', test); 35 | itsInvalid({ 36 | objectType: 'Group', 37 | member: [agentMember, agentMember], 38 | mbox_sha1sum: 'a9993e364706816aba3e25717850c26c9cd0d89d' 39 | }, 'contains an mbox_sha1sum on a group', test); 40 | itsInvalid({ 41 | objectType: 'Group', 42 | member: [agentMember, agentMember], 43 | openid: 'http://example.org/test' 44 | }, 'contains an openid on a group', test); 45 | itsInvalid({ 46 | objectType: 'Group', 47 | member: [agentMember, agentMember, agentMember], 48 | }, 'contains too many members', test); 49 | itsInvalid({ 50 | objectType: 'Group', 51 | member: [agentMember, { 52 | objectType: 'Group', 53 | mbox: 'mailto:test@example.com', 54 | }], 55 | }, 'contains group members', test); 56 | itsValid({ 57 | objectType: 'Group', 58 | member: [agentMember, agentMember], 59 | }, test); 60 | agentSchema(test); 61 | }; 62 | -------------------------------------------------------------------------------- /src/tests/schemaRules/context.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeOptionalProp from '../describeOptionalProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import objectTypeFactory from '../helpers/objectTypeFactory'; 5 | import { 6 | uuid, 7 | actor, 8 | group, 9 | contextActivities, 10 | stringValue, 11 | language, 12 | statementRef, 13 | extensions, 14 | } from '../factory'; 15 | 16 | const validData = { 17 | registration: 'd0310d1c-65fe-4b59-9d4f-c56de054243a', 18 | instructor: { 19 | objectType: 'Agent', 20 | mbox: 'mailto:test@example.com', 21 | }, 22 | team: { 23 | objectType: 'Group', 24 | mbox: 'mailto:test@example.com', 25 | }, 26 | contextActivities: {}, 27 | revision: 'Test', 28 | platform: 'Test', 29 | language: 'en-US', 30 | statement: { 31 | objectType: 'StatementRef', 32 | id: 'd0310d1c-65fe-4b59-9d4f-c56de054243a', 33 | }, 34 | extensions: {}, 35 | }; 36 | 37 | export default (test: Test) => { 38 | itsInvalid(10, 'not an object', test); 39 | itsInvalid({ team: null }, 'team must be an object', test); 40 | describeOptionalProp('registration', uuid, validData, test); 41 | describeOptionalProp('instructor', actor, validData, test); 42 | describeOptionalProp('team', (test: Test) => { 43 | return objectTypeFactory({ 44 | Group: group 45 | }, 'Group', test, {}); 46 | }, validData, test); 47 | describeOptionalProp('contextActivities', contextActivities, validData, test); 48 | describeOptionalProp('revision', stringValue, validData, test); 49 | describeOptionalProp('platform', stringValue, validData, test); 50 | describeOptionalProp('language', language, validData, test); 51 | describeOptionalProp('statement', (test: Test) => { 52 | return objectTypeFactory({ 53 | StatementRef: statementRef 54 | }, 'StatementRef', test, {}); 55 | }, validData, test); 56 | describeOptionalProp('extensions', extensions, validData, test); 57 | }; 58 | -------------------------------------------------------------------------------- /src/tests/schemaRules/contextActivities.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeOptionalProp from '../describeOptionalProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import collection from '../helpers/collection'; 5 | import objectTypeFactory from '../helpers/objectTypeFactory'; 6 | import { activity } from '../factory'; 7 | 8 | const validData = { 9 | parent: [], 10 | category: [], 11 | grouping: [], 12 | other: [], 13 | }; 14 | 15 | const activities = collection((test: Test) => { 16 | return objectTypeFactory({ 17 | Activity: activity 18 | }, 'Activity', test, {}); 19 | }); 20 | 21 | export default (test: Test) => { 22 | itsInvalid(10, 'not an object', test); 23 | describeOptionalProp('parent', activities, validData, test); 24 | describeOptionalProp('category', activities, validData, test); 25 | describeOptionalProp('grouping', activities, validData, test); 26 | describeOptionalProp('other', activities, validData, test); 27 | }; 28 | -------------------------------------------------------------------------------- /src/tests/schemaRules/definition.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeInteractionProp from '../describeInteractionProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import { 5 | languageMap, 6 | iri, 7 | extensions, 8 | interactionType, 9 | stringValue, 10 | } from '../factory'; 11 | import itsInvalid from '../itsInvalid'; 12 | import collection from '../helpers/collection'; 13 | 14 | const validData = {}; 15 | const correctResponsesPattern = collection(stringValue); 16 | 17 | export default (test: Test) => { 18 | itsInvalid(10, 'not an object', test); 19 | itsInvalid({ 20 | type: 'http://adlnet.gov/expapi/activities/cmi.interaction', 21 | correctResponsesPattern: [ 22 | 'Bob\'s your uncle' 23 | ] 24 | }, 'Missing interactionType', test); 25 | 26 | describeOptionalProp('name', languageMap, validData, test); 27 | describeOptionalProp('description', languageMap, validData, test); 28 | describeOptionalProp('type', iri, validData, test); 29 | describeOptionalProp('moreInfo', iri, validData, test); 30 | describeOptionalProp('extensions', extensions, validData, test); 31 | describeOptionalProp('interactionType', interactionType, validData, test); 32 | describeOptionalProp('correctResponsesPattern', correctResponsesPattern, { 33 | ...validData, 34 | type: 'http://adlnet.gov/expapi/activities/cmi.interaction', 35 | interactionType: 'fill-in' 36 | }, test); 37 | 38 | describeInteractionProp(['choices'], 'choice', test); 39 | describeInteractionProp(['choices'], 'sequencing', test); 40 | describeInteractionProp(['scale'], 'likert', test); 41 | describeInteractionProp(['source', 'target'], 'matching', test); 42 | describeInteractionProp(['steps'], 'performance', test); 43 | }; 44 | -------------------------------------------------------------------------------- /src/tests/schemaRules/group.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from '../helpers/test'; 3 | import itsInvalid from '../itsInvalid'; 4 | import agentSchema from '../helpers/agentSchema'; 5 | import describeMemberProp from '../describeMemberProp'; 6 | import { subGroup, agent } from '../factory'; 7 | import objectTypeFactory from '../helpers/objectTypeFactory'; 8 | 9 | export default (test: Test) => { 10 | itsInvalid(10, 'not an object', test); 11 | subGroup(test); 12 | describeMemberProp((test: Test) => { 13 | return objectTypeFactory({ 14 | Agent: agent, 15 | Group: subGroup, 16 | }, 'Agent', test, { mbox: 'mailto:test@example.org' }); 17 | }, test); 18 | agentSchema(test); 19 | }; 20 | -------------------------------------------------------------------------------- /src/tests/schemaRules/interactionComponent.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import { stringValue, languageMap } from '../factory'; 6 | 7 | const validData = { 8 | id: 'test', 9 | description: {}, 10 | }; 11 | 12 | export default (test: Test) => { 13 | itsInvalid(10, 'not an object', test); 14 | describeRequiredProp('id', stringValue, validData, test); 15 | describeOptionalProp('description', languageMap, validData, test); 16 | }; 17 | -------------------------------------------------------------------------------- /src/tests/schemaRules/object.ts: -------------------------------------------------------------------------------- 1 | import object from '../helpers/object'; 2 | import { subStatement } from '../factory'; 3 | 4 | export default object({ 5 | SubStatement: subStatement, 6 | }); 7 | -------------------------------------------------------------------------------- /src/tests/schemaRules/result.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeOptionalProp from '../describeOptionalProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import { 5 | score, 6 | booleanValue, 7 | stringValue, 8 | duration, 9 | extensions, 10 | } from '../factory'; 11 | 12 | const validData = { 13 | score: {}, 14 | success: false, 15 | completion: false, 16 | response: 'test', 17 | duration: 'P3Y6M4DT12H30M5S', 18 | extensions: {}, 19 | }; 20 | 21 | export default (test: Test) => { 22 | itsInvalid(10, 'not an object', test); 23 | describeOptionalProp('score', score, validData, test); 24 | describeOptionalProp('success', booleanValue, validData, test); 25 | describeOptionalProp('completion', booleanValue, validData, test); 26 | describeOptionalProp('response', stringValue, validData, test); 27 | describeOptionalProp('duration', duration, validData, test); 28 | describeOptionalProp('extensions', extensions, validData, test); 29 | }; 30 | -------------------------------------------------------------------------------- /src/tests/schemaRules/score.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeOptionalProp from '../describeOptionalProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import { scaledValue, numberValue } from '../factory'; 5 | 6 | const validData = {}; 7 | 8 | export default (test: Test) => { 9 | itsInvalid(10, 'not an object', test); 10 | itsInvalid({ 11 | min: 1, 12 | raw: 0, 13 | }, 'raw less than min', test); 14 | itsInvalid({ 15 | max: 0, 16 | raw: 1, 17 | }, 'raw more than max', test); 18 | itsInvalid({ 19 | max: 0, 20 | min: 1, 21 | }, 'min more than max', test); 22 | describeOptionalProp('scaled', scaledValue, validData, test); 23 | describeOptionalProp('raw', numberValue, validData, test); 24 | describeOptionalProp('min', numberValue, validData, test); 25 | describeOptionalProp('max', numberValue, validData, test); 26 | }; 27 | -------------------------------------------------------------------------------- /src/tests/schemaRules/statement.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import statementSchema from '../helpers/statementSchema'; 6 | import validStatementData from '../helpers/validStatementData'; 7 | import { uuid, timestamp, authority, version, object } from '../factory'; 8 | 9 | export default (test: Test) => { 10 | itsInvalid(10, 'not an object', test); 11 | describeOptionalProp('id', uuid, validStatementData, test); 12 | describeOptionalProp('stored', timestamp, validStatementData, test); 13 | describeOptionalProp('authority', authority, validStatementData, test); 14 | describeOptionalProp('version', version, validStatementData, test); 15 | describeRequiredProp('object', object, validStatementData, test); 16 | statementSchema(test); 17 | }; 18 | -------------------------------------------------------------------------------- /src/tests/schemaRules/statementRef.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import { uuid } from '../factory'; 5 | 6 | const validData = { 7 | objectType: 'StatementRef', 8 | id: '957f56b7-1d34-4b01-9408-3ffeb2053b28', 9 | }; 10 | 11 | export default (test: Test) => { 12 | itsInvalid(10, 'not an object', test); 13 | describeRequiredProp('id', uuid, validData, test); 14 | }; 15 | -------------------------------------------------------------------------------- /src/tests/schemaRules/subGroup.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import Test from '../helpers/test'; 3 | import itsInvalid from '../itsInvalid'; 4 | import describeMemberProp from '../describeMemberProp'; 5 | import agentSchema from '../helpers/agentSchema'; 6 | import { agent } from '../factory'; 7 | 8 | export default (test: Test) => { 9 | itsInvalid(10, 'not an object', test); 10 | itsInvalid({ 11 | objectType: 'Group', 12 | name: 'Test', 13 | member: [], 14 | }, 'contains no members', test); 15 | describeMemberProp(agent, test); 16 | agentSchema(test); 17 | }; 18 | -------------------------------------------------------------------------------- /src/tests/schemaRules/subStatement.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import itsInvalid from '../itsInvalid'; 4 | import statementSchema from '../helpers/statementSchema'; 5 | import validStatementData from '../helpers/validStatementData'; 6 | import { subStatementObject } from '../factory'; 7 | 8 | export default (test: Test) => { 9 | itsInvalid(10, 'not an object', test); 10 | itsInvalid(Object.assign({}, validStatementData, { 11 | object: Object.assign({}, validStatementData, { 12 | objectType: 'SubStatement', 13 | }), 14 | }), 'object is a SubStatement', test); 15 | describeRequiredProp('object', subStatementObject, validStatementData, test); 16 | statementSchema((data, valid) => 17 | test(Object.assign({}, data), valid) 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/tests/schemaRules/subStatementObject.ts: -------------------------------------------------------------------------------- 1 | import object from '../helpers/object'; 2 | 3 | export default object({}); 4 | -------------------------------------------------------------------------------- /src/tests/schemaRules/verb.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import describeRequiredProp from '../describeRequiredProp'; 3 | import describeOptionalProp from '../describeOptionalProp'; 4 | import itsInvalid from '../itsInvalid'; 5 | import { iri, languageMap } from '../factory'; 6 | 7 | const validData = { 8 | id: 'http://www.example.com', 9 | display: {}, 10 | }; 11 | 12 | export default (test: Test) => { 13 | itsInvalid(10, 'not an object', test); 14 | describeRequiredProp('id', iri, validData, test); 15 | describeOptionalProp('display', languageMap, validData, test); 16 | }; 17 | -------------------------------------------------------------------------------- /src/tests/values/boolean.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid(10, 'not a Boolean', test); 7 | itsValid(true, test); 8 | itsValid(false, test); 9 | }; 10 | -------------------------------------------------------------------------------- /src/tests/values/integer.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid(1.1, 'not a Integer', test); 7 | itsInvalid('', 'not a Number', test); 8 | itsValid(10, test); 9 | itsValid(0, test); 10 | }; 11 | -------------------------------------------------------------------------------- /src/tests/values/number.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid('', 'not a Number', test); 7 | itsValid(-1.12345678, test); 8 | itsValid(0, test); 9 | itsValid(1.12345678, test); 10 | }; 11 | -------------------------------------------------------------------------------- /src/tests/values/scaled.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | export default (test: Test) => { 6 | itsInvalid(1.01, 'too high', test); 7 | itsInvalid(-1.01, 'too low', test); 8 | itsInvalid('', 'not a Number', test); 9 | itsValid(1, test); 10 | itsValid(0.1, test); 11 | itsValid(0, test); 12 | itsValid(-0.1, test); 13 | itsValid(-1, test); 14 | }; 15 | -------------------------------------------------------------------------------- /src/tests/values/string.ts: -------------------------------------------------------------------------------- 1 | import Test from '../helpers/test'; 2 | import itsInvalid from '../itsInvalid'; 3 | import itsValid from '../itsValid'; 4 | 5 | const validData = 'hello'; 6 | 7 | export default (test: Test) => { 8 | itsInvalid(10, 'not a String', test); 9 | itsValid(validData, test); 10 | }; 11 | -------------------------------------------------------------------------------- /src/values.ts: -------------------------------------------------------------------------------- 1 | import { first, checkType, Rule } from 'rulr'; 2 | import { createTypeWarning } from './warnings/TypeWarning'; 3 | 4 | const checkNumber = (typeName: string, checker: (data: any) => boolean): Rule => 5 | first(checkType(Number), (data, path) => 6 | checker(data) ? [] : [createTypeWarning(typeName)(data, path)] 7 | ); 8 | 9 | export const anyValue: Rule = () => []; 10 | export const stringValue: Rule = checkType(String); 11 | export const booleanValue: Rule = checkType(Boolean); 12 | export const numberValue: Rule = checkType(Number); 13 | export const integerValue: Rule = checkNumber('Integer', data => 14 | (data - Math.floor(data)) === 0 15 | ); 16 | export const scaledValue: Rule = checkNumber('Scaled', data => 17 | (-1) <= data && data <= 1 18 | ); 19 | -------------------------------------------------------------------------------- /src/warnings/ContextPropWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class ContextPropWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/IfiCountWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class IfiCountWarning extends Warning { 4 | constructor(data: any, path: Path, public usedIfis: string[]) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/InvalidComponentsWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class InvalidComponentsWarning extends Warning { 4 | constructor(data: any, path: Path, public invalidComponents: string[]) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/MembersLengthWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class MembersLengthWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/MembersTypeWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class MembersTypeWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/MinMoreThanMaxWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class MinMoreThanMaxWarning extends Warning { 4 | constructor(data: any, path: Path, public min: number, public max: number) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/MissingInteractionTypeWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class MissingInteractionTypeWarning extends Warning { 4 | constructor(data: any, path: Path) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/NoIfiWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class NoIfiWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/NoMembersWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class NoMembersWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/ObjectTypeWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class ObjectTypeWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/RawLessThanMinWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class RawLessThanMinWarning extends Warning { 4 | constructor(data: any, path: Path, public raw: number, public min: number) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/RawMoreThanMaxWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class RawMoreThanMaxWarning extends Warning { 4 | constructor(data: any, path: Path, public raw: number, public max: number) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/RestrictedValueWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class RestrictedValueWarning extends Warning { 4 | constructor(data: any, path: Path, public requiredValue: any) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/SignedContentTypeWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class SignedContentTypeWarning extends Warning { 4 | constructor(data: any, path: Path, public contentType: string) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/warnings/SubStatementWarning.ts: -------------------------------------------------------------------------------- 1 | import { Warning } from 'rulr'; 2 | 3 | export default class SubStatementWarning extends Warning {} 4 | -------------------------------------------------------------------------------- /src/warnings/TypeWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class TypeWarning extends Warning { 4 | constructor(data: any, path: Path, public typeName: string) { 5 | super(data, path); 6 | } 7 | } 8 | 9 | export const createTypeWarning = (typeName: string) => { 10 | return (data: any, path: Path): Warning => { 11 | return new TypeWarning(data, path, typeName); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/warnings/VoidWarning.ts: -------------------------------------------------------------------------------- 1 | import { Path, Warning } from 'rulr'; 2 | 3 | export default class VoidWarning extends Warning { 4 | constructor(data: any, path: Path, public voidVerbId: string) { 5 | super(data, path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "target": "es5", 6 | "rootDir": "src", 7 | "outDir": "dist", 8 | "lib": [ 9 | "es2016" 10 | ], 11 | "sourceMap": true, 12 | "removeComments": true, 13 | "preserveConstEnums": true, 14 | "declaration": true, 15 | "strictNullChecks": true, 16 | "noImplicitAny": true, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "alwaysStrict": true, 20 | "noUnusedParameters": true, 21 | "noUnusedLocals": true 22 | }, 23 | "includes": [ 24 | "src/**/*" 25 | ], 26 | "exclude": [ 27 | "node_modules", 28 | "dist/**/*" 29 | ], 30 | "compileOnSave": true 31 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules":{ 3 | "class-name":true, 4 | "comment-format":[ 5 | true, 6 | "check-space" 7 | ], 8 | "indent":[ 9 | true, 10 | "spaces" 11 | ], 12 | "linebreak-style": [true, "LF"], 13 | "eofline": true, 14 | "max-classes-per-file": [true, 0], 15 | "max-line-length": [true, 120], 16 | "max-file-line-count": [true, 300], 17 | "no-unused-expression": true, 18 | "no-duplicate-variable":true, 19 | "no-eval":true, 20 | "no-internal-module":true, 21 | "no-trailing-whitespace":true, 22 | "no-var-keyword":true, 23 | "align": true, 24 | "import-spacing": true, 25 | "interface-over-type-literal": false, 26 | "object-literal-key-quotes": [true, "as-needed"], 27 | "object-literal-shorthand": true, 28 | "one-variable-per-declaration": true, 29 | "no-consecutive-blank-lines": true, 30 | "one-line":[ 31 | true, 32 | "check-open-brace", 33 | "check-whitespace" 34 | ], 35 | "quotemark":[ 36 | true, 37 | "single" 38 | ], 39 | "semicolon":[ 40 | true, 41 | "always" 42 | ], 43 | "triple-equals":[ 44 | true, 45 | "allow-null-check" 46 | ], 47 | "typedef-whitespace":[ 48 | true, 49 | { 50 | "call-signature":"nospace", 51 | "index-signature":"nospace", 52 | "parameter":"nospace", 53 | "property-declaration":"nospace", 54 | "variable-declaration":"nospace" 55 | } 56 | ], 57 | "variable-name":{ 58 | "items": [ 59 | "check-format", 60 | "ban-keywords" 61 | ], 62 | "minLength": 3, 63 | "maxLength": 15 64 | }, 65 | "whitespace":[ 66 | true, 67 | "check-branch", 68 | "check-decl", 69 | "check-operator", 70 | "check-separator", 71 | "check-type" 72 | ] 73 | } 74 | } 75 | --------------------------------------------------------------------------------