├── .github ├── FUNDING.yml ├── contributing.md ├── issue_template.md ├── pull_request_template.md └── workflows │ └── nodejs.yml ├── .gitignore ├── .nycrc ├── CHANGELOG.md ├── LICENSE ├── greenkeeper.json ├── lerna.json ├── mocha.opts ├── package-lock.json ├── package.json ├── packages ├── schema-hooks │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── readme.md │ ├── src │ │ └── index.ts │ ├── test │ │ ├── index.test.ts │ │ └── schema.ts │ └── tsconfig.json ├── schema-sequelize │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── readme.md │ ├── src │ │ └── index.ts │ ├── test │ │ ├── index.test.ts │ │ └── schemas.ts │ └── tsconfig.json └── schema │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── readme.md │ ├── src │ ├── core.ts │ ├── decorator.ts │ ├── index.ts │ └── resolve.ts │ ├── test │ ├── decorator.test.ts │ ├── index.test.ts │ └── resolve.test.ts │ └── tsconfig.json ├── readme.md ├── tsconfig.json └── tslint.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ daffl ] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: feathers 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | custom: # Replace with a single custom sponsorship URL 10 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Feathers 2 | 3 | Thank you for contributing to Feathers! :heart: :tada: 4 | 5 | Feathers embraces modularity and is broken up across multiple modules. You can find them all in the `packages/` folder. Most reflect their name on npm. For example, the code for `@feathersjs/feathers` will be in `packages/feathers`, for `@feathersjs/authentication` in `packages/authenticaiton`. 6 | 7 | ## Report a bug 8 | 9 | Before creating an issue please make sure you have checked out the docs, specifically the [FAQ](https://docs.feathersjs.com/help/faq.html) section. You might want to also try searching Github. It's pretty likely someone has already asked a similar question. 10 | 11 | If you haven't found your answer please feel free to join our [slack channel](http://slack.feathersjs.com), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Slack and Github. 12 | 13 | Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues). Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**. 14 | 15 | ## Report a Security Concern 16 | 17 | We take security very seriously at Feathers. We welcome any peer review of our 100% open source code to ensure nobody's Feathers app is ever compromised or hacked. As a web application developer you are responsible for any security breaches. We do our very best to make sure Feathers is as secure as possible by default. 18 | 19 | In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Slack](http://slack.feathersjs.com) or email us at hello@feathersjs.com with details and we will respond ASAP. 20 | 21 | For full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html). 22 | 23 | ## Pull Requests 24 | 25 | We :heart: pull requests and we're continually working to make it as easy as possible for people to contribute. 26 | 27 | We prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A FeathersJS maintainer will pick up your PR and review it as soon as they can. They may ask for changes or reject your pull request. This is not a reflection of you as an engineer or a person. Please accept feedback graciously as we will also try to be sensitive when providing it. 28 | 29 | Although we generally accept many PRs they can be rejected for many reasons. We will be as transparent as possible but it may simply be that you do not have the same context, historical knowledge or information regarding the roadmap that the maintainers have. We value the time you take to put together any contributions so we pledge to always be respectful of that time and will try to be as open as possible so that you don't waste it. :smile: 30 | 31 | **All PRs (except documentation) should be accompanied with tests and pass the linting rules.** 32 | 33 | ### Code style 34 | 35 | Before running the tests from the `test/` folder `npm test` will run ESlint. You can check your code changes individually by running `npm run lint`. 36 | 37 | ### Tests 38 | 39 | [Mocha](http://mochajs.org/) tests are located in the `test/` folder and can be run using the `npm run mocha` or `npm test` (with ESLint and code coverage) command. 40 | 41 | ### Documentation 42 | 43 | Feathers documentation is contained in Markdown files in the [docs](https://github.com/feathersjs/docs) repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated with the next release. 44 | 45 | ## Community Contributions 46 | 47 | If you've written something awesome about Feathers, for the Feathers ecosystem, or created an app using Feathers please add it to the [awesome-feathersjs](https://github.com/feathersjs-ecosystem/awesome-feathersjs). 48 | 49 | If you are looking to create a new plugin you also might want to check out the [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) that can be used to scaffold plugins to be Feathers compliant from the start. 50 | 51 | If you think your module would be a good core `feathersjs` module or `featherjs-ecosystem` module then please contact one of the Feathers maintainers in [Slack](http://slack.feathersjs.com) and we can discuss whether it belongs and how to get it there. :beers: 52 | 53 | ## Contributor Code of Conduct 54 | 55 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 56 | 57 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 58 | 59 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 60 | 61 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 62 | 63 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 64 | 65 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 66 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Steps to reproduce 2 | 3 | (First please check that this issue is not already solved as [described 4 | here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#report-a-bug)) 5 | 6 | - [ ] Tell us what broke. The more detailed the better. 7 | - [ ] If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc. This makes it much easier for us to debug and issues that have a reproducable example will get higher priority. 8 | 9 | ### Expected behavior 10 | Tell us what should happen 11 | 12 | ### Actual behavior 13 | Tell us what happens instead 14 | 15 | ### System configuration 16 | 17 | Tell us about the applicable parts of your setup. 18 | 19 | **Module versions** (especially the part that's not working): 20 | 21 | **NodeJS version**: 22 | 23 | **Operating System**: 24 | 25 | **Browser Version**: 26 | 27 | **React Native Version**: 28 | 29 | **Module Loader**: -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | 3 | (If you have not already please refer to the contributing guideline as [described 4 | here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#pull-requests)) 5 | 6 | - [ ] Tell us about the problem your pull request is solving. 7 | - [ ] Are there any open issues that are related to this? 8 | - [ ] Is this PR dependent on PRs in other repos? 9 | 10 | If so, please mention them to keep the conversations linked together. 11 | 12 | ### Other Information 13 | 14 | If there's anything else that's important and relevant to your pull 15 | request, mention that information here. This could include 16 | benchmarks, or other information. 17 | 18 | Your PR will be reviewed by a core team member and they will work with you to get your changes merged in a timely manner. If merged your PR will automatically be added to the changelog in the next release. 19 | 20 | If your changes involve documentation updates please mention that and link the appropriate PR in [feathers-docs](https://github.com/feathersjs/feathers-docs). 21 | 22 | Thanks for contributing to Feathers! :heart: -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [10.x, 12.x, 13.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - run: npm install -g codeclimate-test-reporter 21 | - run: npm install 22 | - run: npm test 23 | env: 24 | CI: true 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Build folders 64 | lib/ 65 | *.sqlite 66 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": false, 3 | "tempDirectory": "./coverage/.tmp", 4 | "semistandard": { 5 | "env": [ 6 | "mocha" 7 | ] 8 | }, 9 | "extension": [ 10 | ".ts", 11 | ".tsx", 12 | ".js" 13 | ], 14 | "exclude": [ 15 | "**/test/*", 16 | "**/dist/*", 17 | "**/*.dist.js", 18 | "**/templates/*", 19 | "**/adapter-commons/src/sort.ts" 20 | ], 21 | "print": "detail", 22 | "reporter": [ 23 | "html", 24 | "text", 25 | "text-summary", 26 | "lcov" 27 | ], 28 | "watermarks": { 29 | "statements": [ 30 | 70, 31 | 90 32 | ], 33 | "lines": [ 34 | 70, 35 | 90 36 | ], 37 | "functions": [ 38 | 70, 39 | 90 40 | ], 41 | "branches": [ 42 | 70, 43 | 90 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.1-alpha.5](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.4...v0.0.1-alpha.5) (2020-02-08) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **schema-hooks:** Do not try to resolve if there is no schema ([#15](https://github.com/feathersjs/schema/issues/15)) ([0c51fa2](https://github.com/feathersjs/schema/commit/0c51fa29f6488bec7712b841c58db298c527e285)) 12 | 13 | 14 | 15 | 16 | 17 | ## [0.0.1-alpha.4](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.3...v0.0.1-alpha.4) (2020-02-08) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * Fix getting and resolving schemas from undefined objects ([#14](https://github.com/feathersjs/schema/issues/14)) ([511752e](https://github.com/feathersjs/schema/commit/511752e7992fc0100acd1189638a2bd8178abc70)) 23 | 24 | 25 | 26 | 27 | 28 | ## [0.0.1-alpha.3](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.2...v0.0.1-alpha.3) (2020-01-14) 29 | 30 | 31 | ### Bug Fixes 32 | 33 | * Allow to always override Sequelize type ([#11](https://github.com/feathersjs/schema/issues/11)) ([f29ed19](https://github.com/feathersjs/schema/commit/f29ed191c9ffe27d4a8539dfe4d53c6f0dfac7f6)) 34 | * **package:** update @hapi/joi to version 17.0.2 ([#10](https://github.com/feathersjs/schema/issues/10)) ([cfcfbd0](https://github.com/feathersjs/schema/commit/cfcfbd0fd2f26751e72a74b1363fcbc05458975a)) 35 | 36 | 37 | 38 | 39 | 40 | ## [0.0.1-alpha.2](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.1...v0.0.1-alpha.2) (2019-12-18) 41 | 42 | 43 | ### Features 44 | 45 | * Add @feathersjs/schema-hooks ([#5](https://github.com/feathersjs/schema/issues/5)) ([09c3e9f](https://github.com/feathersjs/schema/commit/09c3e9f5c22103a805d473d0db5d7bf7dc7cee13)) 46 | 47 | 48 | 49 | 50 | 51 | ## [0.0.1-alpha.1](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.0...v0.0.1-alpha.1) (2019-12-13) 52 | 53 | 54 | ### Features 55 | 56 | * Allow references by name and prevent circular resolvers ([#3](https://github.com/feathersjs/schema/issues/3)) ([bb34edd](https://github.com/feathersjs/schema/commit/bb34edd36f47b375871ddbde86a089ae65391dda)) 57 | * First cut of working Sequelize model converter ([#4](https://github.com/feathersjs/schema/issues/4)) ([3187896](https://github.com/feathersjs/schema/commit/3187896304cf32043f5b5b569e2976b986e5eca4)) 58 | 59 | 60 | 61 | 62 | 63 | ## 0.0.1-alpha.0 (2019-12-05) 64 | 65 | 66 | ### Features 67 | 68 | * First version of schema prototype ([#2](https://github.com/feathersjs/schema/issues/2)) ([e11f86e](https://github.com/feathersjs/schema/commit/e11f86e3a43f667e8c4bcb987fa5f917cbf156a5)) 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Feathers 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 | -------------------------------------------------------------------------------- /greenkeeper.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": { 3 | "default": { 4 | "packages": [ 5 | "package.json", 6 | "packages/schema/package.json", 7 | "packages/schema-hooks/package.json", 8 | "packages/schema-sequelize/package.json" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "ci": false, 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.0.1-alpha.5", 7 | "command": { 8 | "bootstrap": { 9 | "hoist": true 10 | }, 11 | "publish": { 12 | "allowBranch": "master", 13 | "message": "chore(release): publish %s", 14 | "conventionalCommits": true, 15 | "createRelease": "github" 16 | } 17 | }, 18 | "ignoreChanges": [ 19 | "**/changelog.md", 20 | "**/CHANGELOG.md", 21 | "**/package-lock.json", 22 | "**/yarn.lock", 23 | "**/test/**", 24 | "lerna.json", 25 | "readme.md", 26 | "package.json" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /mocha.opts: -------------------------------------------------------------------------------- 1 | --timeout 20000 2 | --require ts-node/register 3 | --require source-map-support/register 4 | --reporter Dot 5 | --exit 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@feathersjs/schema", 3 | "private": true, 4 | "scripts": { 5 | "install": "lerna bootstrap", 6 | "publish": "lerna publish && git push origin master", 7 | "lint": "tslint 'packages/**/src/*.ts' 'packages/**/test/*.ts' -c tslint.json --fix", 8 | "test": "npm run lint && nyc lerna run test" 9 | }, 10 | "devDependencies": { 11 | "lerna": "^3.17.0", 12 | "nyc": "^15.0.0", 13 | "tslint": "^6.1.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/schema-hooks/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /packages/schema-hooks/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.1-alpha.5](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.4...v0.0.1-alpha.5) (2020-02-08) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **schema-hooks:** Do not try to resolve if there is no schema ([#15](https://github.com/feathersjs/schema/issues/15)) ([0c51fa2](https://github.com/feathersjs/schema/commit/0c51fa29f6488bec7712b841c58db298c527e285)) 12 | 13 | 14 | 15 | 16 | 17 | ## [0.0.1-alpha.4](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.3...v0.0.1-alpha.4) (2020-02-08) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * Fix getting and resolving schemas from undefined objects ([#14](https://github.com/feathersjs/schema/issues/14)) ([511752e](https://github.com/feathersjs/schema/commit/511752e7992fc0100acd1189638a2bd8178abc70)) 23 | 24 | 25 | 26 | 27 | 28 | ## [0.0.1-alpha.2](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.1...v0.0.1-alpha.2) (2019-12-18) 29 | 30 | 31 | ### Features 32 | 33 | * Add @feathersjs/schema-hooks ([#5](https://github.com/feathersjs/schema/issues/5)) ([09c3e9f](https://github.com/feathersjs/schema/commit/09c3e9f5c22103a805d473d0db5d7bf7dc7cee13)) 34 | -------------------------------------------------------------------------------- /packages/schema-hooks/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Feathers 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 | -------------------------------------------------------------------------------- /packages/schema-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@feathersjs/schema-hooks", 3 | "version": "0.0.1-alpha.5", 4 | "description": "Feathers hooks to use with @feathersjs/schema", 5 | "homepage": "https://feathersjs.com", 6 | "keywords": [ 7 | "feathers" 8 | ], 9 | "license": "MIT", 10 | "funding": { 11 | "type": "opencollective", 12 | "url": "https://opencollective.com/feathers" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/feathersjs/schema.git" 17 | }, 18 | "author": { 19 | "name": "Feathers contributor", 20 | "email": "hello@feathersjs.com", 21 | "url": "https://feathersjs.com" 22 | }, 23 | "contributors": [], 24 | "bugs": { 25 | "url": "https://github.com/feathersjs/schema/issues" 26 | }, 27 | "engines": { 28 | "node": ">= 12" 29 | }, 30 | "main": "lib/", 31 | "types": "lib/", 32 | "scripts": { 33 | "prepublish": "npm run compile", 34 | "compile": "shx rm -rf lib/ && tsc", 35 | "test": "npm run compile && npm run mocha", 36 | "mocha": "mocha --opts ../../mocha.opts --recursive test/**.test.ts test/**/*.test.ts" 37 | }, 38 | "directories": { 39 | "lib": "lib" 40 | }, 41 | "publishConfig": { 42 | "access": "public" 43 | }, 44 | "devDependencies": { 45 | "@feathersjs/feathers": "^4.4.3", 46 | "@types/mocha": "^8.0.3", 47 | "@types/node": "^14.14.6", 48 | "feathers-memory": "^4.1.0", 49 | "mocha": "^7.0.1", 50 | "shx": "^0.3.2", 51 | "ts-node": "^9.0.0", 52 | "typescript": "^4.0.2" 53 | }, 54 | "dependencies": { 55 | "@feathersjs/errors": "^4.4.3", 56 | "@feathersjs/schema": "^0.0.1-alpha.4" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/schema-hooks/readme.md: -------------------------------------------------------------------------------- 1 | # @feathersjs/schema-hooks 2 | 3 | Hooks for use `@feathersjs/schema`. 4 | -------------------------------------------------------------------------------- /packages/schema-hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | import { HookContext } from '@feathersjs/feathers'; 2 | import { resolve, getSchema } from '@feathersjs/schema'; 3 | import { FeathersError } from '@feathersjs/errors'; 4 | 5 | export class ValidationError extends FeathersError { 6 | readonly details: any; 7 | 8 | constructor (message: string, details: any, data?: any) { 9 | super(message, 'validation-error', 400, 'ValidationError', { 10 | errors: details, 11 | ...data 12 | }); 13 | } 14 | } 15 | 16 | export const validateSchema = (options?: any) => { 17 | return async (context: HookContext) => { 18 | const { service, data } = context; 19 | const schema = getSchema(service?.options?.Schema || service.Schema); 20 | 21 | if (schema && data) { 22 | try { 23 | context.data = await schema.validate(data, { 24 | abortEarly: false, 25 | context, 26 | ...options 27 | }); 28 | } catch (error) { 29 | if (error.details) { 30 | throw new ValidationError(error.message, error.details, data); 31 | } 32 | 33 | throw error; 34 | } 35 | } 36 | }; 37 | }; 38 | 39 | export const resolveSchema = () => { 40 | return async (context: HookContext) => { 41 | const { result, method, service } = context; 42 | const schema = getSchema(service?.options?.Schema || service.Schema || service); 43 | 44 | if(schema === null) { 45 | return context; 46 | } 47 | 48 | if (method === 'find' && result.data) { 49 | context.result.data = await resolve(result.data, schema, context); 50 | } else { 51 | context.result = await resolve(result, schema, context); 52 | } 53 | 54 | return context; 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /packages/schema-hooks/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'assert'; 2 | 3 | import feathers, { Application } from '@feathersjs/feathers'; 4 | import memory from 'feathers-memory'; 5 | 6 | import { resolveSchema, validateSchema } from '../src'; 7 | import { User, Todo } from './schema'; 8 | 9 | describe('@feathersjs/schema-hooks', () => { 10 | let app: Application; 11 | 12 | beforeEach(() => { 13 | app = feathers().use('/users', memory({ 14 | // @ts-ignore 15 | Schema: User 16 | })).use('/todos', memory({ 17 | // @ts-ignore 18 | Schema: Todo 19 | })).use('/dummy', { 20 | async get (id: string) { 21 | return { id }; 22 | } 23 | }); 24 | 25 | app.hooks({ 26 | before: validateSchema(), 27 | after: resolveSchema() 28 | }); 29 | }); 30 | 31 | describe('validateSchema', () => { 32 | it('validation error', async () => { 33 | try { 34 | await app.service('users').create({ 35 | age: '12', 36 | email: 'dave' 37 | }); 38 | assert.fail('Should never get here'); 39 | } catch (error) { 40 | assert.equal(error.name, 'validation-error'); 41 | assert.equal(error.errors.length, 2); 42 | assert.equal(error.errors[0].message, '"email" must be a valid email'); 43 | assert.equal(error.errors[1].message, '"name" is required'); 44 | } 45 | }); 46 | 47 | it('creates a new valid user with coerced data', async () => { 48 | const user = await app.service('users').create({ 49 | email: 'dave@example.com', 50 | name: 'Dave', 51 | age: '54' 52 | }); 53 | 54 | assert.deepEqual(user, { 55 | id: 0, 56 | email: 'dave@example.com', 57 | name: 'Dave', 58 | age: 54 59 | }); 60 | }); 61 | }); 62 | 63 | describe('resolveSchema', () => { 64 | it('resolves a schema', async () => { 65 | const user = await app.service('users').create({ 66 | email: 'todo@example.com', 67 | name: 'Todo Tester', 68 | age: '54' 69 | }); 70 | const todo = await app.service('todos').create({ 71 | text: 'The users todo', 72 | userId: user.id 73 | }, { user }); 74 | 75 | assert.deepEqual(todo, { 76 | text: 'The users todo', 77 | userId: user.id, 78 | id: 0, 79 | user 80 | }); 81 | }); 82 | 83 | it('works on service without schema', async () => { 84 | const test = await app.service('dummy').get('test'); 85 | 86 | assert.deepEqual(test, { id: 'test' }); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /packages/schema-hooks/test/schema.ts: -------------------------------------------------------------------------------- 1 | import Joi from '@hapi/joi'; 2 | import { schema, property } from '@feathersjs/schema'; 3 | import { HookContext } from '@feathersjs/feathers'; 4 | 5 | @schema({ 6 | name: 'users' 7 | }) 8 | export class User { 9 | @property (validator => validator.integer()) 10 | id: number; 11 | 12 | @property (validator => validator.email().required()) 13 | email: string; 14 | 15 | @property (validator => validator.required()) 16 | name: string; 17 | 18 | @property (validator => validator.integer()) 19 | age: number; 20 | } 21 | 22 | @schema({ 23 | name: 'todos' 24 | }) 25 | export class Todo { 26 | @property (validator => validator.integer()) 27 | id: number; 28 | 29 | @property() 30 | text: string; 31 | 32 | @property (validator => validator.integer().required(), { 33 | value (_userId: number, _todo: Todo, context: HookContext) { 34 | return context.params?.user?.id; 35 | } 36 | }) 37 | userId: number; 38 | 39 | @property({ 40 | async resolve (todo: Todo, context: HookContext) { 41 | const { query, ...params } = context.params; 42 | 43 | return context.app.service('users').get(todo.userId, params); 44 | } 45 | }) 46 | user: User; 47 | } 48 | -------------------------------------------------------------------------------- /packages/schema-hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "include": [ 4 | "src/**/*.ts" 5 | ], 6 | "compilerOptions": { 7 | "outDir": "lib", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/schema-sequelize/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /packages/schema-sequelize/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.1-alpha.4](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.3...v0.0.1-alpha.4) (2020-02-08) 7 | 8 | **Note:** Version bump only for package @feathersjs/schema-sequelize 9 | 10 | 11 | 12 | 13 | 14 | ## [0.0.1-alpha.3](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.2...v0.0.1-alpha.3) (2020-01-14) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * Allow to always override Sequelize type ([#11](https://github.com/feathersjs/schema/issues/11)) ([f29ed19](https://github.com/feathersjs/schema/commit/f29ed191c9ffe27d4a8539dfe4d53c6f0dfac7f6)) 20 | 21 | 22 | 23 | 24 | 25 | ## [0.0.1-alpha.2](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.1...v0.0.1-alpha.2) (2019-12-18) 26 | 27 | **Note:** Version bump only for package @feathersjs/schema-sequelize 28 | 29 | 30 | 31 | 32 | 33 | ## [0.0.1-alpha.1](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.0...v0.0.1-alpha.1) (2019-12-13) 34 | 35 | 36 | ### Features 37 | 38 | * First cut of working Sequelize model converter ([#4](https://github.com/feathersjs/schema/issues/4)) ([3187896](https://github.com/feathersjs/schema/commit/3187896304cf32043f5b5b569e2976b986e5eca4)) 39 | 40 | 41 | 42 | 43 | 44 | ## 0.0.1-alpha.0 (2019-12-05) 45 | 46 | 47 | ### Features 48 | 49 | * First version of schema prototype ([#2](https://github.com/feathersjs/schema/issues/2)) ([e11f86e](https://github.com/feathersjs/schema/commit/e11f86e3a43f667e8c4bcb987fa5f917cbf156a5)) 50 | -------------------------------------------------------------------------------- /packages/schema-sequelize/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Feathers 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 | -------------------------------------------------------------------------------- /packages/schema-sequelize/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@feathersjs/schema-sequelize", 3 | "version": "0.0.1-alpha.4", 4 | "description": "Sequelize mappings for @feathersjs/schema", 5 | "homepage": "https://feathersjs.com", 6 | "keywords": [ 7 | "feathers" 8 | ], 9 | "license": "MIT", 10 | "funding": { 11 | "type": "opencollective", 12 | "url": "https://opencollective.com/feathers" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/feathersjs/schema.git" 17 | }, 18 | "author": { 19 | "name": "Feathers contributor", 20 | "email": "hello@feathersjs.com", 21 | "url": "https://feathersjs.com" 22 | }, 23 | "contributors": [], 24 | "bugs": { 25 | "url": "https://github.com/feathersjs/schema/issues" 26 | }, 27 | "engines": { 28 | "node": ">= 12" 29 | }, 30 | "main": "lib/", 31 | "types": "lib/", 32 | "scripts": { 33 | "prepublish": "npm run compile", 34 | "compile": "shx rm -rf lib/ && tsc", 35 | "clean": "shx rm -f test-db.sqlite", 36 | "test": "npm run compile && npm run clean && npm run mocha", 37 | "mocha": "mocha --opts ../../mocha.opts --recursive test/**.test.ts test/**/*.test.ts" 38 | }, 39 | "directories": { 40 | "lib": "lib" 41 | }, 42 | "publishConfig": { 43 | "access": "public" 44 | }, 45 | "devDependencies": { 46 | "@types/bluebird": "^3.5.29", 47 | "@types/mocha": "^8.0.3", 48 | "@types/node": "^14.14.6", 49 | "@types/validator": "^13.1.0", 50 | "mocha": "^7.0.1", 51 | "sequelize": "^6.3.5", 52 | "shx": "^0.3.2", 53 | "sqlite3": "^5.0.0", 54 | "ts-node": "^9.0.0", 55 | "typescript": "^4.0.2" 56 | }, 57 | "dependencies": { 58 | "@feathersjs/schema": "^0.0.1-alpha.4" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/schema-sequelize/readme.md: -------------------------------------------------------------------------------- 1 | # @feathersjs/schema-sequelize 2 | 3 | Sequelize converter for `@feathersjs/schema` schemas: 4 | 5 | ```js 6 | import Joi from '@hapi/joi'; 7 | import { schema, property } from '@feathersjs/schema'; 8 | 9 | @schema({ 10 | name: 'users' 11 | }) 12 | export class User { 13 | @property (validator => validator.integer(), { 14 | sequelize: { 15 | primaryKey: true, 16 | autoIncrement: true 17 | } 18 | }) 19 | id: number; 20 | 21 | @property (validator => validator.email().required()) 22 | email: string; 23 | 24 | @property (validator => validator.integer()) 25 | age: number; 26 | } 27 | 28 | @schema({ 29 | name: 'todos', 30 | sequelize (TodoModel: any, models: any) { 31 | TodoModel.belongsTo(models.users, { as: 'user' }); 32 | } 33 | }) 34 | export class Todo { 35 | @property (validator => validator.integer(), { 36 | sequelize: { 37 | primaryKey: true, 38 | autoIncrement: true 39 | } 40 | }) 41 | id: number; 42 | 43 | @property(validator => validator.required()) 44 | text: string; 45 | 46 | @property() 47 | userId: number; 48 | 49 | @property({ 50 | async resolve (todo: any, context: any) { 51 | return context.users.findOne({ 52 | raw: true, 53 | where: { 54 | id: todo.userId 55 | } 56 | }); 57 | } 58 | }) 59 | user: User; 60 | } 61 | 62 | const client = new Sequelize('sqlite://test-db.sqlite'); 63 | 64 | const UserModel = convert (User, client); 65 | const TodoModel = convert(Todo, client); 66 | 67 | associate(client); 68 | 69 | await client.sync(); 70 | 71 | assert.ok(UserModel); 72 | assert.ok(TodoModel); 73 | ``` 74 | -------------------------------------------------------------------------------- /packages/schema-sequelize/src/index.ts: -------------------------------------------------------------------------------- 1 | import Joi = require('@hapi/joi'); 2 | import { getSchema, SchemaPropertyDefinition } from '@feathersjs/schema'; 3 | import { Sequelize, DataTypes, ModelAttributeColumnOptions, ModelCtor, Model } from 'sequelize'; 4 | 5 | const typeMap: { [key: string]: any } = { 6 | string: DataTypes.STRING, 7 | number: DataTypes.NUMBER, 8 | boolean: DataTypes.BOOLEAN 9 | }; 10 | 11 | const processFlag: { [key: string]: (value: any) => any } = { 12 | presence: (value: any) => ({ allowNull: value !== 'required' }) 13 | }; 14 | 15 | export function convertProperty (description: Joi.Description, propDef: SchemaPropertyDefinition) { 16 | const type = typeMap[description.type]; 17 | const { sequelize = null } = propDef; 18 | 19 | if (!type) { 20 | return sequelize; 21 | } 22 | 23 | const { flags = {}, rules = [] } = description; 24 | 25 | const withFlags = Object.keys(flags).reduce((result, key) => { 26 | const value = (flags as any)[key]; 27 | const processor = processFlag[key] || (() => ({})); 28 | const processed = processor(value); 29 | 30 | return { 31 | ...result, 32 | ...processed 33 | }; 34 | }, { type } as ModelAttributeColumnOptions); 35 | 36 | const converted = rules.reduce((result: any, rule: any) => { 37 | if (rule.name === 'integer') { 38 | return { 39 | ...result, 40 | type: DataTypes.INTEGER 41 | }; 42 | } 43 | return result; 44 | }, withFlags); 45 | 46 | return { 47 | ...converted, 48 | ...sequelize 49 | }; 50 | } 51 | 52 | export function convert (target: any, client?: Sequelize) { 53 | const schema = getSchema(target); 54 | const describe = schema.validator.describe(); 55 | const modelProperties = Object.keys(describe.keys).reduce((props, name) => { 56 | const converted = convertProperty(describe.keys[name], schema.properties[name]); 57 | 58 | if (converted === null) { 59 | return props; 60 | } 61 | 62 | return { 63 | ...props, 64 | [name]: converted 65 | }; 66 | }, {} as { [key: string]: any }); 67 | 68 | return client.define(schema.meta.name, modelProperties) as ModelCtor>; 69 | } 70 | 71 | export function associate (client: Sequelize) { 72 | const names = Object.keys(client.models); 73 | 74 | names.forEach(name => { 75 | const schema = getSchema(name); 76 | const model = client.models[name]; 77 | 78 | if (schema && schema.meta.sequelize) { 79 | schema.meta.sequelize(model, client.models); 80 | } 81 | }); 82 | 83 | return client; 84 | } 85 | -------------------------------------------------------------------------------- /packages/schema-sequelize/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'assert'; 2 | import { Sequelize } from 'sequelize'; 3 | import { resolve } from '@feathersjs/schema'; 4 | 5 | import { convert, associate } from '../src'; 6 | import { User, Todo } from './schemas'; 7 | 8 | describe('@feathersjs/schema-sequelize', () => { 9 | it('initializes a model', async () => { 10 | const client = new Sequelize('sqlite://test-db.sqlite'); 11 | 12 | const UserModel = convert (User, client); 13 | const TodoModel = convert(Todo, client); 14 | 15 | associate(client); 16 | 17 | await client.sync(); 18 | 19 | assert.ok(UserModel); 20 | assert.ok(TodoModel); 21 | 22 | const user: any = await UserModel.create({ 23 | email: 'dave@test.com', 24 | age: 22 25 | }); 26 | const todo = await TodoModel.create({ 27 | text: 'Test todo', 28 | userId: user.id, 29 | valid: 'custom type' 30 | }); 31 | 32 | const resolvedTodo: any = await resolve(todo.toJSON(), Todo, client.models); 33 | 34 | assert.ok(resolvedTodo.id); 35 | assert.ok(resolvedTodo.user); 36 | assert.equal(resolvedTodo.user.email, 'dave@test.com'); 37 | assert.equal(resolvedTodo.valid, 'custom type'); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/schema-sequelize/test/schemas.ts: -------------------------------------------------------------------------------- 1 | import Joi from '@hapi/joi'; 2 | import { schema, property } from '@feathersjs/schema'; 3 | import Sequelize from 'sequelize'; 4 | 5 | @schema({ 6 | name: 'users' 7 | }) 8 | export class User { 9 | @property (validator => validator.integer(), { 10 | sequelize: { 11 | primaryKey: true, 12 | autoIncrement: true 13 | } 14 | }) 15 | id: number; 16 | 17 | @property (validator => validator.email().required()) 18 | email: string; 19 | } 20 | 21 | @schema({ 22 | name: 'todos', 23 | sequelize (TodoModel: any, models: any) { 24 | TodoModel.belongsTo(models.users, { as: 'user' }); 25 | } 26 | }) 27 | export class Todo { 28 | @property (validator => validator.integer(), { 29 | sequelize: { 30 | primaryKey: true, 31 | autoIncrement: true 32 | } 33 | }) 34 | id: number; 35 | 36 | @property(validator => validator.required()) 37 | text: string; 38 | 39 | @property() 40 | userId: number; 41 | 42 | @property({ 43 | sequelize: { type: Sequelize.DataTypes.STRING } 44 | }) 45 | valid: boolean; 46 | 47 | @property({ 48 | async resolve (todo: any, context: any) { 49 | return context.users.findOne({ 50 | raw: true, 51 | where: { 52 | id: todo.userId 53 | } 54 | }); 55 | } 56 | }) 57 | user: User; 58 | } 59 | -------------------------------------------------------------------------------- /packages/schema-sequelize/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "include": [ 4 | "src/**/*.ts" 5 | ], 6 | "compilerOptions": { 7 | "outDir": "lib", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/schema/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /packages/schema/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.1-alpha.4](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.3...v0.0.1-alpha.4) (2020-02-08) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * Fix getting and resolving schemas from undefined objects ([#14](https://github.com/feathersjs/schema/issues/14)) ([511752e](https://github.com/feathersjs/schema/commit/511752e7992fc0100acd1189638a2bd8178abc70)) 12 | 13 | 14 | 15 | 16 | 17 | ## [0.0.1-alpha.2](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.1...v0.0.1-alpha.2) (2019-12-18) 18 | 19 | 20 | ### Features 21 | 22 | * Add @feathersjs/schema-hooks ([#5](https://github.com/feathersjs/schema/issues/5)) ([09c3e9f](https://github.com/feathersjs/schema/commit/09c3e9f5c22103a805d473d0db5d7bf7dc7cee13)) 23 | 24 | 25 | 26 | 27 | 28 | ## [0.0.1-alpha.1](https://github.com/feathersjs/schema/compare/v0.0.1-alpha.0...v0.0.1-alpha.1) (2019-12-13) 29 | 30 | 31 | ### Features 32 | 33 | * Allow references by name and prevent circular resolvers ([#3](https://github.com/feathersjs/schema/issues/3)) ([bb34edd](https://github.com/feathersjs/schema/commit/bb34edd36f47b375871ddbde86a089ae65391dda)) 34 | * First cut of working Sequelize model converter ([#4](https://github.com/feathersjs/schema/issues/4)) ([3187896](https://github.com/feathersjs/schema/commit/3187896304cf32043f5b5b569e2976b986e5eca4)) 35 | 36 | 37 | 38 | 39 | 40 | ## 0.0.1-alpha.0 (2019-12-05) 41 | 42 | 43 | ### Features 44 | 45 | * First version of schema prototype ([#2](https://github.com/feathersjs/schema/issues/2)) ([e11f86e](https://github.com/feathersjs/schema/commit/e11f86e3a43f667e8c4bcb987fa5f917cbf156a5)) 46 | -------------------------------------------------------------------------------- /packages/schema/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Feathers 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 | -------------------------------------------------------------------------------- /packages/schema/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@feathersjs/schema", 3 | "version": "0.0.1-alpha.4", 4 | "description": "Core Feathers schema", 5 | "homepage": "https://feathersjs.com", 6 | "keywords": [ 7 | "feathers" 8 | ], 9 | "license": "MIT", 10 | "funding": { 11 | "type": "opencollective", 12 | "url": "https://opencollective.com/feathers" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/feathersjs/schema.git" 17 | }, 18 | "author": { 19 | "name": "Feathers contributor", 20 | "email": "hello@feathersjs.com", 21 | "url": "https://feathersjs.com" 22 | }, 23 | "contributors": [], 24 | "bugs": { 25 | "url": "https://github.com/feathersjs/schema/issues" 26 | }, 27 | "engines": { 28 | "node": ">= 12" 29 | }, 30 | "main": "lib/", 31 | "types": "lib/", 32 | "scripts": { 33 | "prepublish": "npm run compile", 34 | "compile": "shx rm -rf lib/ && tsc", 35 | "test": "npm run compile && npm run mocha", 36 | "mocha": "mocha --opts ../../mocha.opts --recursive test/**.test.ts test/**/*.test.ts" 37 | }, 38 | "directories": { 39 | "lib": "lib" 40 | }, 41 | "publishConfig": { 42 | "access": "public" 43 | }, 44 | "dependencies": { 45 | "@hapi/joi": "^17.0.2", 46 | "@types/hapi__joi": "^17.1.4", 47 | "reflect-metadata": "^0.1.13" 48 | }, 49 | "devDependencies": { 50 | "@types/mocha": "^8.0.3", 51 | "@types/node": "^14.14.6", 52 | "mocha": "^7.0.1", 53 | "shx": "^0.3.2", 54 | "ts-node": "^9.0.0", 55 | "typescript": "^4.0.2" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/schema/readme.md: -------------------------------------------------------------------------------- 1 | # @feathersjs/schema -------------------------------------------------------------------------------- /packages/schema/src/core.ts: -------------------------------------------------------------------------------- 1 | import Joi from '@hapi/joi'; 2 | 3 | export const Type = Joi; 4 | 5 | export const typeMap = new WeakMap(); 6 | export const nameMap: { [key: string]: Schema } = {}; 7 | 8 | export let id = 0; 9 | 10 | typeMap.set(String, Joi.string()); 11 | typeMap.set(Number, Joi.number()); 12 | typeMap.set(Boolean, Joi.boolean()); 13 | 14 | export type SchemaTypes = Schema|string|Joi.AnySchema|typeof String|typeof Number|typeof Boolean; 15 | // tslint:disable-next-line:ban-types 16 | export type SchemaPropertyType = SchemaTypes|SchemaTypes[]|Function; 17 | 18 | export interface SchemaPropertyDefinition { 19 | type: SchemaPropertyType; 20 | [key: string]: any; 21 | } 22 | 23 | export interface SchemaMeta { 24 | name: string; 25 | [key: string]: any; 26 | } 27 | 28 | export interface SchemaProperties { 29 | [key: string]: SchemaPropertyDefinition; 30 | } 31 | 32 | export const validatorFromType = (type: Schema|SchemaPropertyType|(() => Joi.AnySchema)): Joi.AnySchema => { 33 | const value = typeMap.get(type) || type; 34 | 35 | if (Array.isArray(value) && value.length === 1) { 36 | const [ arrayValue ] = value; 37 | 38 | return Joi.array().items(validatorFromType(arrayValue)); 39 | } 40 | 41 | const valueSchema = value instanceof Schema ? value : getSchema(value); 42 | 43 | if (valueSchema !== null) { 44 | return valueSchema.validator; 45 | } 46 | 47 | return value; 48 | }; 49 | 50 | export function getValidator (properties: SchemaProperties) { 51 | const validators: Joi.SchemaMap = Object.keys(properties).reduce((current, key) => { 52 | const { type } = properties[key]; 53 | 54 | return { 55 | ...current, 56 | [key]: validatorFromType(type) 57 | }; 58 | }, {}); 59 | 60 | return Joi.object(validators); 61 | } 62 | 63 | export class Schema { 64 | meta: SchemaMeta; 65 | properties: SchemaProperties; 66 | validator: Joi.ObjectSchema; 67 | 68 | constructor (schemaMeta: Partial, schemaProperties: SchemaProperties) { 69 | this.properties = {}; 70 | this.meta = { 71 | name: `schema-${++id}` 72 | }; 73 | 74 | this.addMetadata(schemaMeta); 75 | this.addProperties(schemaProperties); 76 | } 77 | 78 | async validate (value: any, options?: Joi.AsyncValidationOptions) { 79 | return this.validator.validateAsync(value, options); 80 | } 81 | 82 | addProperties (schemaProperties: SchemaProperties) { 83 | this.properties = Object.assign(this.properties, schemaProperties); 84 | this.validator = getValidator(this.properties); 85 | 86 | return this; 87 | } 88 | 89 | addMetadata (schemaMeta: Partial) { 90 | const oldName = this.meta.name; 91 | 92 | this.meta = Object.assign(this.meta, schemaMeta); 93 | 94 | delete nameMap[oldName]; 95 | nameMap[this.meta.name] = this; 96 | 97 | return this; 98 | } 99 | } 100 | 101 | export function setSchema (schema: Schema, target: any) { 102 | typeMap.set(target !== null ? target : schema, schema); 103 | 104 | return schema; 105 | } 106 | 107 | export function getSchema (target: any): Schema|null { 108 | if (target instanceof Schema) { 109 | return target; 110 | } 111 | 112 | if (typeof target === 'string') { 113 | return nameMap[target] || null; 114 | } 115 | 116 | if (!target) { 117 | return null; 118 | } 119 | 120 | let p = target; 121 | 122 | do { 123 | const schema = typeMap.get(p); 124 | 125 | if (schema !== undefined) { 126 | return schema; 127 | } 128 | 129 | p = p.prototype; 130 | } while (!!p); 131 | 132 | return null; 133 | } 134 | -------------------------------------------------------------------------------- /packages/schema/src/decorator.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import Joi, { AnySchema } from '@hapi/joi'; 3 | import { getSchema, schema, SchemaPropertyDefinition, validatorFromType } from './index'; 4 | import { SchemaMeta } from './core'; 5 | 6 | export type TypeInitializer = (type: T) => T; 7 | 8 | export function propertyDecorator ( 9 | definition: Partial|TypeInitializer = {}, 10 | propDef: Partial = {} 11 | ) { 12 | return (target: any, propertyName: string) => { 13 | const type = Reflect.getMetadata('design:type', target, propertyName); 14 | const targetSchema = getSchema(target) || schema(target, {}, {}); 15 | 16 | if (typeof definition === 'function') { 17 | targetSchema.addProperties({ 18 | [propertyName]: { 19 | type: definition(validatorFromType(type) as T), 20 | ...propDef 21 | } 22 | }); 23 | } else { 24 | targetSchema.addProperties({ 25 | [propertyName]: { 26 | type, 27 | ...definition 28 | } 29 | }); 30 | } 31 | }; 32 | } 33 | 34 | export function schemaDecorator (definition: Partial) { 35 | return (target: any) => { 36 | const targetSchema = getSchema(target) || schema(target, {}, {}); 37 | 38 | targetSchema.addMetadata(definition); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /packages/schema/src/index.ts: -------------------------------------------------------------------------------- 1 | import { SchemaMeta, SchemaProperties, Schema, setSchema } from './core'; 2 | import { schemaDecorator, propertyDecorator } from './decorator'; 3 | 4 | export * from './core'; 5 | export * from './decorator'; 6 | export * from './resolve'; 7 | 8 | export const property = propertyDecorator; 9 | 10 | export function schema (schemaMeta: Partial, schemaProperties: SchemaProperties): Schema; 11 | export function schema (target: any, schemaMeta: Partial, schemaProperties: SchemaProperties): Schema; 12 | export function schema (schemaMeta: Partial): (target: any) => void; 13 | export function schema (...args: any[]) { 14 | if (args.length === 1) { 15 | return schemaDecorator(args[0]); 16 | } 17 | 18 | const target = args.length === 3 ? args.shift() : null; 19 | const [ schemaMeta, schemaProperties ] = args; 20 | const schema = new Schema(schemaMeta, schemaProperties); 21 | 22 | setSchema(schema, target); 23 | 24 | return schema; 25 | } 26 | -------------------------------------------------------------------------------- /packages/schema/src/resolve.ts: -------------------------------------------------------------------------------- 1 | import { getSchema } from './core'; 2 | 3 | export async function resolve (source: T, schemaTarget: any, context: any, path: any[] = []): Promise { 4 | if (Array.isArray(source)) { 5 | return Promise.all(source.map((current: any) => resolve(current, schemaTarget, context, path))); 6 | } 7 | 8 | const isArray = Array.isArray(schemaTarget); 9 | const schema = getSchema(isArray ? schemaTarget[0] : schemaTarget); 10 | const { properties } = schema; 11 | const resolveKeys = Object.keys(properties).filter(key => 12 | typeof properties[key].resolve === 'function' && !path.includes(properties[key]) 13 | ); 14 | 15 | if (resolveKeys.length) { 16 | const entities: any[] = await Promise.all(resolveKeys.map(async key => { 17 | const property = properties[key]; 18 | const { resolve: resolver, type } = property; 19 | const entity = await resolver(source, context); 20 | 21 | return resolve(entity, type, context, path.concat(property)); 22 | })); 23 | 24 | return resolveKeys.reduce((result, key, index) => { 25 | return { 26 | ...result, 27 | [key]: entities[index] 28 | }; 29 | }, source); 30 | } 31 | 32 | return source; 33 | } 34 | -------------------------------------------------------------------------------- /packages/schema/test/decorator.test.ts: -------------------------------------------------------------------------------- 1 | import { property, schema, getSchema } from '../src'; 2 | import { strict as assert } from 'assert'; 3 | import Joi = require('@hapi/joi'); 4 | 5 | describe('@feathersjs/schema decorator', () => { 6 | it('initializes with property decorators', async () => { 7 | @schema({ 8 | name: 'todo' 9 | }) 10 | class Todo { 11 | @property(validator => validator.required(), {}) 12 | text: string; 13 | } 14 | 15 | @schema({ 16 | name: 'test' 17 | }) 18 | class Test { 19 | @property (validator => validator.integer()) 20 | age: number; 21 | 22 | @property() 23 | todo: Todo; 24 | 25 | constructor (_age: number) { 26 | this.age = _age; 27 | } 28 | } 29 | 30 | assert.deepEqual(getSchema(Test).meta, { 31 | name: 'test' 32 | }); 33 | 34 | const validated = await getSchema(Test).validate({ 35 | age: '2134', 36 | todo: { 37 | text: 'testing' 38 | } 39 | }); 40 | 41 | assert.deepEqual(validated, { 42 | age: 2134, 43 | todo: { text: 'testing' } 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/schema/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'assert'; 2 | import { schema, Type, getSchema } from '../src'; 3 | 4 | describe('@feathersjs/schema', () => { 5 | it('simple schema and validation', async () => { 6 | const User = schema({ 7 | name: 'users' 8 | }, { 9 | email: { 10 | type: Type.string().email().required() 11 | }, 12 | age: { 13 | type: Number 14 | }, 15 | enabled: { 16 | type: Boolean 17 | } 18 | }); 19 | 20 | const validated = await User.validate({ 21 | age: '33', 22 | enabled: 'false', 23 | email: 'someone@somewhere.com' 24 | }); 25 | 26 | assert.deepEqual(validated, { 27 | age: 33, 28 | enabled: false, 29 | email: 'someone@somewhere.com' 30 | }); 31 | 32 | await assert.rejects(() => User.validate({ 33 | email: 'Here' 34 | }), { 35 | message: '"email" must be a valid email' 36 | }); 37 | 38 | assert.equal(getSchema('users'), User, 'getSchema with name'); 39 | assert.equal(getSchema(null), null); 40 | }); 41 | 42 | it('schema on target', async () => { 43 | class Tester {} 44 | 45 | schema(Tester, {}, { 46 | age: { 47 | type: Number 48 | } 49 | }); 50 | 51 | const Related = schema({}, { 52 | test: { 53 | type: Tester 54 | } 55 | }); 56 | 57 | const validated = await Related.validate({ 58 | test: { age: '444' } 59 | }); 60 | 61 | assert.deepEqual(validated, { test: { age: 444 } }); 62 | assert.deepEqual(await getSchema(Tester).validate({ 63 | age: '123' 64 | }), { 65 | age: 123 66 | }); 67 | }); 68 | 69 | it('related schemas and validation', async () => { 70 | const Todo = schema({}, { 71 | text: { 72 | type: Type.string().required() 73 | } 74 | }); 75 | const User = schema({}, { 76 | age: { 77 | type: Type.number().required().integer() 78 | }, 79 | todos: { 80 | type: [ Todo ] 81 | } 82 | }); 83 | 84 | const validated = await User.validate({ 85 | age: '23', 86 | todos: [{ 87 | text: 'Hello' 88 | }] 89 | }); 90 | 91 | assert.deepEqual(validated, { 92 | age: 23, 93 | todos: [ { text: 'Hello' } ] 94 | }); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /packages/schema/test/resolve.test.ts: -------------------------------------------------------------------------------- 1 | import { strict as assert } from 'assert'; 2 | import { schema, Type, resolve } from '../src'; 3 | 4 | describe('@feathersjs/schema resolvers', () => { 5 | it('general schema resolvin, avoids circular dependencies', async () => { 6 | const User = schema({ 7 | name: 'resolve-users' 8 | }, { 9 | id: { 10 | type: Number 11 | }, 12 | name: { 13 | type: String 14 | }, 15 | email: { 16 | type: Type.string().email().required() 17 | }, 18 | todos: { 19 | type: [ 'resolve-todos' ], 20 | async resolve (user: any, ctx: any) { 21 | return ctx.todos.filter((todo: any) => todo.userId === user.id); 22 | } 23 | } 24 | }); 25 | 26 | const Todo = schema({ 27 | name: 'resolve-todos' 28 | }, { 29 | text: { 30 | type: Type.string().required() 31 | }, 32 | 33 | userId: { 34 | type: Number 35 | }, 36 | 37 | user: { 38 | type: User, 39 | async resolve (todo: any, context: any) { 40 | return context.users.find((user: any) => user.id === todo.userId); 41 | } 42 | } 43 | }); 44 | 45 | const ctx = { 46 | users: [{ 47 | id: 12, 48 | name: 'Dave', 49 | email: 'dave@example.com' 50 | }, { 51 | id: 15, 52 | name: 'Joe', 53 | email: 'joe@example.com' 54 | }], 55 | todos: [{ 56 | text: 'My todo', 57 | userId: 15 58 | }, { 59 | text: 'My other todo', 60 | userId: 12 61 | }] 62 | }; 63 | const todo = ctx.todos[0]; 64 | const resolvedTodo = await resolve(todo, Todo, ctx); 65 | 66 | assert.deepEqual(resolvedTodo, { 67 | text: 'My todo', 68 | userId: 15, 69 | user: { 70 | id: 15, 71 | name: 'Joe', 72 | email: 'joe@example.com', 73 | todos: [ ctx.todos[0] ] 74 | } 75 | }); 76 | 77 | const user = ctx.users[0]; 78 | const resolvedUser = await resolve(user, User, ctx, [ Todo.properties.user ]); 79 | 80 | assert.deepEqual(resolvedUser, { 81 | id: 12, 82 | name: 'Dave', 83 | email: 'dave@example.com', 84 | todos: [ ctx.todos[1] ] 85 | }); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /packages/schema/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "include": [ 4 | "src/**/*.ts" 5 | ], 6 | "compilerOptions": { 7 | "outDir": "lib", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Feathers Schema 2 | 3 | > __Note:__ Development for this module has been moved to [feathersjs/feathers](https://github.com/feathersjs/feathers). See the [documentation](https://dove.docs.feathersjs.com/api/schema/) for usage information. 4 | 5 | [![CI](https://github.com/feathersjs/schema/workflows/CI/badge.svg)](https://github.com/feathersjs/schema/actions?query=workflow%3ACI) 6 | 7 | A common schema definition format for JavaScript and TypeScript that can target different formats like 8 | 9 | - JSON schema 10 | - GraphQL 11 | - Mongoose 12 | - Sequelize 13 | 14 | ## Example 15 | 16 | ### JavaScript 17 | 18 | ```js 19 | const { schema, Type } = require('@feathersjs/schema'); 20 | 21 | const User = schema({ 22 | name: 'user' 23 | }, { 24 | id: { 25 | type: Type.number().integer() 26 | }, 27 | email: { 28 | type: Type.string().email().required(), 29 | description: 'The user email' 30 | }, 31 | firstName: { 32 | type: String 33 | }, 34 | lastName: { 35 | type: String 36 | }, 37 | todos: { 38 | type: [ 'todo' ], // Use schema name to get around circular dependencies 39 | async resolve (user, context) { 40 | const { params: { query = {} }, app } = context; 41 | 42 | return app.service('todos').find({ 43 | paginate: false, 44 | query: { 45 | ...query, 46 | userId: user.id 47 | } 48 | }); 49 | } 50 | } 51 | }); 52 | 53 | const Todo = schema({ 54 | name: 'todo' 55 | }, { 56 | text: { 57 | type: String 58 | }, 59 | completed: { 60 | type: Boolean 61 | }, 62 | userId: { 63 | type: Number 64 | }, 65 | user: { 66 | type: User, // Can use direct reference here 67 | resolve: async (todo, context) => { 68 | const { params, app } = context; 69 | 70 | return app.service('users').get(todo.userId, params); 71 | } 72 | } 73 | }); 74 | ``` 75 | 76 | ### TypeScript 77 | 78 | Schemas can be declared using decorators 79 | 80 | ```ts 81 | const { property, schema, Type } = require('@feathersjs/schema'); 82 | 83 | @schema({ 84 | name: 'users' 85 | }) 86 | class User { 87 | @property() 88 | id: number; 89 | 90 | @property(validator => validator.email().required()) 91 | email: string; 92 | 93 | @property() 94 | firstName: string; 95 | 96 | @property() 97 | lastName: string; 98 | 99 | @property({ 100 | type: [ 'todos' ], // Reference by schema name 101 | resolve: async (user, context) => { 102 | const { params: { query = {} }, app } = context; 103 | 104 | return app.service('todos').find({ 105 | paginate: false, 106 | query: { 107 | ...query, 108 | userId: user.id 109 | } 110 | }); 111 | } 112 | }) 113 | todos: Todo[]; 114 | } 115 | 116 | @schema({ 117 | name: 'todos' 118 | }) 119 | class Todo { 120 | @property() 121 | text: string; 122 | 123 | @property() 124 | completed: boolean; 125 | 126 | @property(validator => validator.required()) 127 | userId: User['id']; 128 | 129 | @property({ 130 | resolve: async (todo, context) => { 131 | const { params, app } = context; 132 | 133 | return app.service('users').get(todo.userId, params); 134 | } 135 | }) 136 | user: User; 137 | } 138 | ``` 139 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation. */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 12 | "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | // "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 15 | // "composite": true, /* Enable project compilation */ 16 | // "removeComments": true, /* Do not emit comments to output. */ 17 | // "noEmit": true, /* Do not emit outputs. */ 18 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 19 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 20 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 21 | 22 | /* Strict Type-Checking Options */ 23 | "strict": true, /* Enable all strict type-checking options. */ 24 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | "strictNullChecks": false, /* Enable strict null checks. */ 26 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 27 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 28 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 29 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 30 | 31 | /* Additional Checks */ 32 | "noUnusedLocals": true, /* Report errors on unused locals. */ 33 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 34 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 35 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 36 | 37 | /* Module Resolution Options */ 38 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 39 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 40 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 41 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 42 | // "typeRoots": [], /* List of folders to include type definitions from. */ 43 | // "types": [], /* Type declaration files to be included in compilation. */ 44 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 45 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 46 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 47 | 48 | /* Source Map Options */ 49 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 50 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 51 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 52 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 53 | 54 | /* Experimental Options */ 55 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 56 | "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */ 57 | } 58 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "**/coverage/**" 9 | ] 10 | }, 11 | "rules": { 12 | "trailing-comma": [ true, { "multiline": "never", "singleline": "never" } ], 13 | "quotemark": [ true, "single", "jsx-double" ], 14 | "member-access": [ true, "no-public" ], 15 | "space-before-function-paren": true, 16 | "variable-name": false, 17 | "max-line-length": false, 18 | "interface-name": false, 19 | "object-literal-sort-keys": false, 20 | "ordered-imports": false, 21 | "arrow-parens": false, 22 | "max-classes-per-file": false, 23 | "only-arrow-functions": false, 24 | "no-empty": false, 25 | "no-shadowed-variable": false, 26 | "no-namespace": [ true, "allow-declarations" ] 27 | }, 28 | "jsRules": true, 29 | "rulesDirectory": [] 30 | } --------------------------------------------------------------------------------