├── .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 | [](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 | }
--------------------------------------------------------------------------------